#include #define _GLIBCXX_DEBUG using namespace std; using ll = long long; using V = vector; using VV = vector; using VVV = vector; #define rep2(i, m, n) for (int i = (m); i < (n); ++i) #define rep(i, n) rep2(i, 0, n) #define all(a) (a).begin(), (a).end() struct fast_ios { fast_ios(){ cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(20); }; } fast_ios_; template inline bool chmin(T &a, T b) { if (a > b) { a = b; return true; } return false; } template inline bool chmax(T &a, T b) { if (a < b) { a = b; return true; } return false; } template istream &operator>>(istream &is, pair &p) { is >> p.first >> p.second; return is; } template istream &operator>>(istream &is, vector &v) { for (auto &e : v) is >> e; return is; } template ostream &operator<<(ostream &os, const vector &v) { for (auto &e : v) os << e << '\n'; return os; } // Credit: Benq typedef array P; typedef array T; templatestruct Eulerian_Trail{ vector

g[N]; vector

::iterator it[N]; bool exist[N]; vector vs; vector used; Eulerian_Trail(){rep2(i,0,N)exist[i]=0;} vector res; void clear(){ for(auto& v:vs)g[v].clear(),exist[v]=0; vs.clear(); used.clear(); res.clear(); } void dfs(int v){ vector ret; stack s; s.push({v,-1,-1}); while(!s.empty()){ int x=(s.top())[0]; auto& cur=it[x],ed=g[x].end(); while(cur!=ed and used[(*cur)[1]])cur++; if(cur==ed){ret.push_back(s.top()); s.pop();} else{s.push({(*cur)[0],x,(*cur)[1]}); used[(*cur)[1]]=1;} } rep2(i,0,ret.size()-1)res.push_back(ret[i][2]); } vector run(vector

es){ rep2(i,0,es.size()){ auto [u,v]=es[i]; used.push_back(0); if(!exist[u]){ exist[u]=1; vs.push_back(u); } if(!exist[v]){ exist[v]=1; vs.push_back(v); } g[u].push_back({v,i}); g[v].push_back({u,i}); } for(auto& v:vs)it[v]=g[v].begin(); for(auto& v:vs)for(auto& e:g[v])if(!used[e[1]])dfs(e[0]); return res; } }; struct Edge_Coloring{ int n; vector

_es,es; Eulerian_Trail<201010,0> euler; Edge_Coloring(){} void add_edge(int u,int v){_es.push_back({u,v});} array,2> divide(vector

tmp){ //divide eulerian trail euler.clear(); auto p=euler.run(tmp); array,2> res; rep2(i,0,p.size())res[i&1].push_back(p[i]); return res; } vector find(vector ids){ //find perfect matching int k=(int)ids.size()/n; assert(n*k==(int)ids.size()); int t=0; while((1< ori(ids.size(),x),dum(n,y); while(t--){ vector

tmp; vector add; int cnt=0; rep2(i,0,ids.size()){ if(ori[i]&1){ tmp.push_back({es[ids[i]][0],es[ids[i]][1]}); add.push_back(i); cnt++; } ori[i]>>=1; } rep2(i,0,n){ if(dum[i]&1){ tmp.push_back({i,n+i}); add.push_back(i); } dum[i]>>=1; } array,2> w=divide(tmp); int dum_cnt[2]={}; rep2(i,0,2)for(int x:w[i])if(x>=cnt)dum_cnt[i]++; for(int i:w[dum_cnt[0]>dum_cnt[1]]){ if(i res; rep2(i,0,ids.size())if(ori[i])res.push_back(ids[i]); assert((int)res.size()==n); return res; } vector used; vector> colorize(vector ids){ //must be regular bipartite graph int k=(int)ids.size()/n; assert(n*k==(int)ids.size()); if(k==0)return {}; if(k==1)return {ids}; vector> res; if(k&1){ auto add=find(ids); for(int x:add)used[x]=1; vector rem; for(int x:ids)if(!used[x])rem.push_back(x); for(int x:add)used[x]=0; res=colorize(rem); res.push_back(add); } else{ vector

tmp; for(int i:ids)tmp.push_back({es[i][0],es[i][1]}); array,2> p=divide(tmp); rep2(i,0,2)for(auto& x:p[i])x=ids[x]; res=colorize(p[0]); int cur=k>>1; while(__builtin_popcount(cur)!=1){ auto add=res.back(); res.pop_back(); p[1].insert(p[1].end(),all(add)); cur++; } auto add=colorize(p[1]); res.insert(res.end(),all(add)); } return res; } int run(vector& res){ //normalize int LR[2]={}; for(auto e:_es)rep2(j,0,2)chmax(LR[j],e[j]+1); vector deg[2],kind[2],sz[2]; rep2(i,0,2)deg[i].resize(LR[i]),kind[i].resize(LR[i]); for(auto e:_es)rep2(j,0,2)deg[j][e[j]]++; int k=0; rep2(i,0,2)rep2(j,0,LR[i])chmax(k,deg[i][j]); rep2(j,0,2){ for(int i=0;i tmp(n*k); iota(all(tmp),0); auto ret=colorize(tmp); rep2(i,0,ret.size())for(int idx:ret[i]){ if(idx<(int)_es.size())res[idx]=i; } return k; } }; int main() { // input int l, r, m; cin >> l >> r >> m; vector> E(m); cin >> E; // count degrees and find the minimum VV deg = {V(l), V(r)}; for (auto [a, b] : E) { ++deg[0][a], ++deg[1][b]; } int D = min(*min_element(all(deg[0])), *min_element(all(deg[1]))); // reset degree deg = {V(l), V(r)}; // copied vertex set VVV vtx = {VV(l), VV(r)}; rep(i, l) vtx[0][i].push_back(i); rep(i, r) vtx[1][i].push_back(i); // solution Edge_Coloring sol; // construct a graph with copied vertexes for (auto [a, b] : E) { int x = vtx[0][a].back(); int y = vtx[1][b].back(); if (deg[0][x] == D) { vtx[0][a].push_back(deg[0].size()); x = vtx[0][a].back(); deg[0].push_back(0); } if (deg[1][y] == D) { vtx[1][b].push_back(deg[1].size()); y = vtx[1][b].back(); deg[1].push_back(0); } sol.add_edge(x, y); ++deg[0][x]; ++deg[1][y]; } // find edge coloring V res; sol.run(res); // verify // vector> S0(l), S1(r); rep(i, m) { auto [a, b] = E[i]; S0[a].insert(res[i]); S1[b].insert(res[i]); } rep(i, l) assert(S0[i].size() == D); rep(i, r) assert(S1[i].size() == D); //////////// // output cout << D << '\n'; cout << res; return 0; } // 5 3 10 // 0 0 // 0 1 // 1 0 // 1 2 // 2 1 // 2 2 // 3 1 // 3 2 // 4 1 // 4 2