[HDU5354]Bipartite Graph(CDQ分治+并查集)

经典动态二分图问题。

考虑solve(l,r)分治成l,mid和mid+1,r。先将区间[mid+1,r]中的点全部加入图中,若此时存在奇环则ans[l..mid]全部为0,否则递归到左边。

递归完左边后将右边的点全部删去,左边点全部加入,按同样的方法处理右边。

判断奇环使用可撤销带权并查集,注意多组数据不要用memset。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 using namespace std;
 6 
 7 const int N=200010;
 8 int T,n,m,top,cnt,u,v;
 9 int fa[N],sz[N],d[N],ans[N],h[N],nxt[N],to[N];
10 struct P{ int a,b,c; }s[3*N];
11 struct S{ int x,y; };
12 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
13 
14 void init(){ cnt=0; rep(i,1,n) fa[i]=i,sz[i]=1,d[i]=0,h[i]=0; }
15 
16 S get(int x){
17     if (fa[x]==x) return (S){x,0};
18     S t=get(fa[x]); return (S){t.x,t.y^d[x]};
19 }
20 
21 void uni(int x,int y){
22     int t1=get(x).y; x=get(x).x;
23     int t2=get(y).y; y=get(y).x;
24     if (sz[x]<sz[y]) swap(x,y);
25     s[++top]=(P){0,y,y}; s[++top]=(P){1,x,sz[x]}; s[++top]=(P){2,y,0};
26     fa[y]=x; d[y]=t1^t2^1; sz[x]+=sz[y];
27 }
28 
29 void cancel(int x){
30     if (s[x].a==0) fa[s[x].b]=s[x].c;
31     if (s[x].a==1) sz[s[x].b]=s[x].c;
32     if (s[x].a==2) d[s[x].b]=s[x].c;
33 }
34 
35 void solve(int l,int r){
36     if (l==r) { ans[l]=1; return; }
37     int mid=(l+r)>>1,tmp=top; bool flag=0;
38     rep(u,mid+1,r)
39         for (int i=h[u]; i; i=nxt[i]){
40             int v=to[i];
41             if (v>=l && v<=mid) continue;
42             if (get(u).x!=get(v).x) uni(u,v);
43             else if (get(u).y==get(v).y) { flag=1; break; }
44         }
45     if (flag) rep(i,l,mid) ans[i]=0; else solve(l,mid);
46     while (top>tmp) cancel(top--); flag=0;
47     rep(u,l,mid)
48         for (int i=h[u]; i; i=nxt[i]){
49             int v=to[i];
50             if (v>mid && v<=r) continue;
51             if (get(u).x!=get(v).x) uni(u,v);
52             else if (get(u).y==get(v).y) { flag=1; break; }
53         }
54     if (flag) rep(i,mid+1,r) ans[i]=0; else solve(mid+1,r);
55     while (top>tmp) cancel(top--);
56 }
57 
58 int main(){
59     freopen("hdu5354.in","r",stdin);
60     freopen("hdu5354.out","w",stdout);
61     for (scanf("%d",&T); T--; ){
62         scanf("%d%d",&n,&m); init();
63         rep(i,1,m) scanf("%d%d",&u,&v),add(u,v),add(v,u);
64         solve(1,n);
65         rep(i,1,n) printf("%d",ans[i]); puts("");
66     }
67     return 0;
68 }
原文地址:https://www.cnblogs.com/HocRiser/p/9858063.html