結果
問題 | No.3071 玉虫色着色 |
ユーザー | 37zigen |
提出日時 | 2020-07-14 19:30:00 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 58 ms / 2,000 ms |
コード長 | 9,539 bytes |
コンパイル時間 | 2,186 ms |
コンパイル使用メモリ | 144,804 KB |
実行使用メモリ | 8,028 KB |
最終ジャッジ日時 | 2024-07-03 20:13:33 |
合計ジャッジ時間 | 15,313 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 24 ms
6,400 KB |
testcase_01 | AC | 11 ms
6,528 KB |
testcase_02 | AC | 10 ms
5,888 KB |
testcase_03 | AC | 12 ms
6,448 KB |
testcase_04 | AC | 10 ms
5,888 KB |
testcase_05 | AC | 10 ms
6,016 KB |
testcase_06 | AC | 10 ms
5,888 KB |
testcase_07 | AC | 58 ms
7,756 KB |
testcase_08 | AC | 56 ms
7,948 KB |
testcase_09 | AC | 56 ms
7,872 KB |
testcase_10 | AC | 54 ms
7,988 KB |
testcase_11 | AC | 56 ms
8,028 KB |
testcase_12 | AC | 1 ms
5,376 KB |
testcase_13 | AC | 1 ms
5,376 KB |
testcase_14 | AC | 2 ms
5,376 KB |
evil_large1.txt | AC | 786 ms
40,600 KB |
evil_large2.txt | AC | 1,106 ms
48,784 KB |
ソースコード
#include <iostream> #include <vector> #include <queue> #include <set> #include <deque> #include <assert.h> #include <random> #include <utility> #include <time.h> struct djset { std::vector<int> upper; std::vector<int> id; int n; djset(int n_) { n=n_; upper.resize(n); id.resize(n); for (int i=0;i<n;++i) upper[i]=-1; } int root(int x) { return upper[x]<0?x:(upper[x]=root(upper[x])); } bool equiv(int x,int y) { return root(x)==root(y); } void unite(int x,int y) { x=root(x);y=root(y); if (x==y) return; if (upper[x]<upper[y]) std::swap(x,y); upper[y]+=upper[x]; upper[x]=y; } void build_id() { for (int i=0,p=0;i<n;++i) if (i==root(i)) id[i]=p++; } int components() { int e=0; for (int i=0;i<n;++i) if (i==root(i)) ++e; return e; } }; struct edge { int dst=-1; int rev=-1; int cnt=1; int col=-1; int id=-1;// -1 ならば bad edge }; struct vertex { int next_edge=0; int id; std::vector<edge> edges; }; void add_edge(vertex &a,vertex &b,int col,int cnt,int id) { if (cnt==0) return; edge ab; edge ba; ab.dst=b.id; ba.dst=a.id; ab.rev=b.edges.size(); ba.rev=a.edges.size(); ab.col=col; ba.col=col; ab.cnt=cnt; ba.cnt=cnt; ab.id=id; ba.id=id; a.edges.push_back(ab); b.edges.push_back(ba); } int max_deg(std::vector<vertex> &vs){ int deg=0; for (vertex &v:vs) { int sum=0; for (edge &e:v.edges) sum+=e.cnt; deg=std::max(deg,sum); } return deg; } int bad_edge(std::vector<vertex> &vs) { int ret=0; for (vertex &v:vs) for (edge &e:v.edges) if (e.id==-1) ++ret; return ret; } void divide_edge(std::vector<vertex> &v0,std::vector<vertex> &v1,int a,int b,edge &e) { add_edge(v0[a],v0[b],e.col,(e.cnt+1)/2,e.id); add_edge(v1[a],v1[b],e.col,e.cnt/2,e.id); } void divide(std::vector<vertex> &vs,std::vector<vertex> &v0,std::vector<vertex> &v1) { assert(max_deg(vs)%2==0); std::vector<std::vector<bool>> vis; for (int i=0;i<(int)vs.size();++i) { vis.push_back(std::vector<bool>(vs[i].edges.size(),false)); } for (int i=0;i<(int)vs.size();++i) { int cur=i; int parity=0; while (vs[i].next_edge!=(int)vs[i].edges.size()) { edge e=vs[cur].edges[vs[cur].next_edge]; if (vis[cur][vs[cur].next_edge]) { ++vs[cur].next_edge; continue; } if (e.cnt%2==0) { divide_edge(v0,v1,cur,e.dst,e); vis[e.dst][e.rev]=true; ++vs[cur].next_edge; } else { if (parity==0) divide_edge(v0,v1,cur,e.dst,e); else divide_edge(v1,v0,cur,e.dst,e); vis[e.dst][e.rev]=true; ++vs[cur].next_edge; cur=e.dst; parity^=1; } } } } std::vector<int> find_matching(std::vector<vertex> vs) { int n=(int)vs.size(),m=0,M=1; for (vertex v:vs) m+=v.edges.size(); while (M<m) M*=2; for (int i=0;i<n/2;++i) { int k=vs[i].edges.size(); for (edge &e:vs[i].edges) { e.cnt=M/k; vs[e.dst].edges[e.rev].cnt=e.cnt; } add_edge(vs[i],vs[i+n/2],-1,M%k,-1); } while (max_deg(vs)>1) { std::vector<vertex> v0(n); std::vector<vertex> v1(n); for (int i=0;i<n;++i) { v0[i].id=i; v1[i].id=i; } divide(vs,v0,v1); if (bad_edge(v0) <= bad_edge(v1)) { vs=v0; } else { vs=v1; } } std::vector<int> matching; for (vertex &v:vs) for (edge &e:v.edges) { if (v.id<e.dst) matching.push_back(e.id); } return matching; } void delete_edges(std::vector<vertex> &vs,std::vector<int> delete_edges) { std::vector<vertex> ret(vs.size()); for (int i=0;i<(int)ret.size();++i) ret[i].id=i; std::set<int> s; for (int &id:delete_edges) s.insert(id); for (vertex &v:vs) for (edge &e:v.edges) { if (v.id>e.dst) continue; if (s.count(e.id)!=0) { --e.cnt; s.erase(e.id); } add_edge(ret[v.id],ret[e.dst],e.col,e.cnt,e.id); } vs=ret; } std::vector<std::pair<int,int>> colorize2(std::vector<vertex> &vs,int offset=0) { int D=max_deg(vs); if (D==1) { std::vector<std::pair<int,int>> ret; for (vertex &v:vs) for (edge &e:v.edges) { if (v.id>e.dst) continue; ret.push_back(std::make_pair(e.id,offset)); } return ret; } std::vector<vertex> v0(vs.size()); std::vector<vertex> v1(vs.size()); for (int i=0;i<(int)vs.size();++i) { v0[i].id=i; v1[i].id=i; } divide(vs,v0,v1); std::vector<std::pair<int,int>> ans0=colorize2(v0,offset); std::vector<std::pair<int,int>> ans1=colorize2(v1,offset+D/2); for (std::pair<int,int> &p:ans0) { ans1.push_back(p); } return ans1; } std::vector<std::pair<int,int>> colorize(std::vector<vertex> vs,int offset=0) { int D=max_deg(vs); if (D==0) return std::vector<std::pair<int,int>>(); else if (D==1) { std::vector<std::pair<int,int>> ans; for (vertex &v:vs) { for (edge &e:v.edges) { ans.push_back(std::make_pair(e.id,offset)); } } return ans; } else if (D%2==0) { int D2=1; while (D2<D/2) D2*=2; std::vector<vertex> v0(vs.size()); std::vector<vertex> v1(vs.size()); for (int i=0;i<(int)vs.size();++i) { v0[i].id=i; v1[i].id=i; } divide(vs,v0,v1); std::vector<std::pair<int,int>> ans0=colorize(v0,offset); std::set<int> invalid; for (auto &p:ans0) { assert(p.second<offset+D/2); if (p.second-offset>=(int)(D/2-(D2-D/2))) { invalid.insert(p.first); } } for (vertex &v:v0) { for (edge &e:v.edges) { if (v.id>e.dst) continue; if (invalid.count(e.id)) { add_edge(v1[v.id],v1[e.dst],-1,1,e.id); } } } std::vector<std::pair<int,int>> ans1=colorize2(v1,offset+(D/2-(D2-D/2))); for (std::pair<int,int> &p:ans0) { if (invalid.count(p.first)==0) ans1.push_back(p); } return ans1; } else { std::vector<int> matching=find_matching(vs); std::vector<std::pair<int,int>> ans0; std::vector<std::pair<int,int>> ans1; for (int &id:matching) { ans0.push_back(std::make_pair(id,offset)); } delete_edges(vs,matching); ans1=colorize(vs,offset+1); for (std::pair<int,int> &p:ans1) { ans0.push_back(p); } return ans0; } } void contract(std::vector<int> °,djset &ds,int D) { std::priority_queue<std::pair<int,int>> pq; for (int i=0;i<(int)deg.size();++i) { pq.push(std::make_pair(-deg[i],i)); } while (pq.size()>1) { std::pair<int,int> a=pq.top();pq.pop(); std::pair<int,int> b=pq.top();pq.pop(); if (-(a.first+b.first)>D) break; a.first+=b.first; ds.unite(a.second,b.second); pq.push(a); } ds.build_id(); } std::vector<int> solve(int L,int R,int M,std::vector<int> &a,std::vector<int> &b) { int D=0; std::vector<int> deg[2]; deg[0]=std::vector<int>(L); deg[1]=std::vector<int>(R); for (int i=0;i<M;++i) { ++deg[0][a[i]]; ++deg[1][b[i]]; D=std::max(D,std::max(deg[0][a[i]],deg[1][b[i]])); } djset ds[2]={L,R}; contract(deg[0],ds[0],D); contract(deg[1],ds[1],D); int sz=std::max(ds[0].components(),ds[1].components()); std::vector<vertex> vs(2*sz); for (int i=0;i<(int)vs.size();++i) vs[i].id=i; for (int i=0;i<M;++i) { int u=ds[0].id[ds[0].root(a[i])]; int v=ds[1].id[ds[1].root(b[i])]; add_edge(vs[u],vs[v+sz],-1,1,i); } int p=0,q=sz,extra=0; while (p<(int)vs.size()&&q<(int)vs.size()) { if ((int)vs[p].edges.size()==D) ++p; else if ((int)vs[q].edges.size()==D) ++q; else add_edge(vs[p],vs[q],-1,1,M+(extra++)); } std::vector<std::pair<int,int>> ps=colorize(vs); std::vector<int> ans(M); for (auto &pair:ps) { if (pair.first<M) ans[pair.first]=pair.second; } return ans; } void transform(int &L,int &R,int &M,std::vector<int> &a,std::vector<int> &b) { std::vector<int> deg[2]; deg[0]=std::vector<int>(L,0); deg[1]=std::vector<int>(R,0); int nL=L,nR=R; for (int i=0;i<M;++i) { ++deg[0][a[i]]; ++deg[1][b[i]]; } int d=1<<30; for (int deg:deg[0]) d=std::min(d,deg); for (int deg:deg[1]) d=std::min(d,deg); if (d==0) { std::cout<<0<<std::endl; exit(0); } for (int i=0;i<M;++i) { if (deg[0][a[i]]>d) { --deg[0][a[i]]; if (L==nL || deg[0][nL-1]==d) { deg[0].push_back(0); ++nL; } a[i]=nL-1; ++deg[0][nL-1]; } if (deg[1][b[i]]>d) { --deg[1][b[i]]; if (R==nR || deg[1][nR-1]==d) { deg[1].push_back(0); ++nR; } b[i]=nR-1; ++deg[1][nR-1]; } } L=nL; R=nR; return; } std::mt19937 mt; void gen() { int L=100000; int R=100000; int M=100000; std::vector<int> a(M); std::vector<int> b(M); for (int i=0;i<M;++i) { a[i]=mt()%L; b[i]=mt()%R; } transform(L,R,M,a,b); std::vector<int> ans=solve(L,R,M,a,b); std::vector<vertex> g(L+R); for (int i=0;i<(int)g.size();++i) g[i].id=i; for (int i=0;i<M;++i) { add_edge(g[a[i]],g[b[i]+L],ans[i],1,i); } for (vertex &v:g) { std::set<int> cols; for (edge &e:v.edges) { cols.insert(e.col); } } std::cout<<"ok"<<std::endl; } void solve() { int L,R,M; scanf("%d%d%d",&L,&R,&M); std::vector<int> a(M); std::vector<int> b(M); for (int i=0;i<M;++i) { std::cin>>a[i]>>b[i]; } transform(L,R,M,a,b); std::vector<int> ans=solve(L,R,M,a,b); int D=0; for (int &c:ans) D=std::max(D,c+1); printf("%d\n",D); for (int &c:ans) { printf("%d\n",c); } } int main() { solve(); }