hdu_5354_Bipartite Graph(cdq分治+并查集判二分图)
题意:
给你一个由无向边连接的图,问对于每一个点来说,如果删除这个点,剩下的点能不能构成一个二分图。
题解:
如果每次排除一个点然后去DFS判是否为二分图,那肯定会超时。
我们可以知道,删除其中一个点,对其他好多的边都不会有影响,所以我们可以将其他点的边先加进去,然后来判断一个区间的点是否可行。
这就和cdq分治的思想差不多。我们令cdq(l,r)表示解决l到r区间的答案。然后通过并查集来判断已经加入的点是否为二分图。
并查集在判二分图的时候不能路径压缩,因为我们在cdq过程中会还原并查集的结构。
这里要注意,如果在更新[l,mid]时候,[mid+1,r]只要不能构成二分图,那么[l,mid]的答案就全部都是0,然后就是在并查集合并的时候要以节点多的树为跟,这样才不会T。
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 5 const int N=1e5+7; 6 int t,n,m,ed,g[N],v[N*2],nxt[N*2],rk[N],col[N],top,fa[N]; 7 char ans[N]; 8 struct node 9 { 10 int u,v,colu,colv,fau,fav,rku,rkv; 11 node(){} 12 node(int _u,int _v,int _colu,int _colv,int _fau,int _fav,int _rku,int _rkv): 13 u(_u),v(_v),colu(_colu),colv(_colv),fau(_fau),fav(_fav),rku(_rku),rkv(_rkv){} 14 }S[N],tmp; 15 16 void init(){ed=top=0,ans[n+1]=0;F(i,1,n)g[i]=0,rk[i]=col[i]=1,fa[i]=i;} 17 void adg(int x,int y){v[++ed]=y,nxt[ed]=g[x],g[x]=ed;} 18 19 inline int find_fa(int x){return fa[x]==x?x:find_fa(fa[x]);} 20 inline int find_col(int x) 21 { 22 if(fa[x]==x)return col[x]; 23 return col[x]?find_col(fa[x]):!find_col(fa[x]); 24 } 25 26 int merge(int u,int v) 27 { 28 int fa_u=find_fa(u),fa_v=find_fa(v); 29 int col_u=find_col(u),col_v=find_col(v); 30 if(fa_u==fa_v) 31 {//如果同根并且同色,又有这条边,该图肯定不是二分图 32 if(col_u==col_v)return 0; 33 return 1; 34 } 35 int rt,son; 36 if(rk[fa_u]<rk[fa_v])rt=fa_v,son=fa_u;else rt=fa_u,son=fa_v;//以大树为根 37 S[++top]=node(rt,son,col[rt],col[son],fa[rt],fa[son],rk[rt],rk[son]); 38 if(col_u==col_v)col[son]^=1;//如果要合并的两个点的颜色相同,那么将要作为儿子的点改变颜色 39 fa[son]=rt,rk[rt]+=rk[son]; 40 return 1; 41 } 42 43 void back(int pre)//还原并查集 44 { 45 while(top>pre) 46 { 47 tmp=S[top--]; 48 int u=tmp.u,v=tmp.v; 49 col[u]=tmp.colu,col[v]=tmp.colv; 50 fa[u]=tmp.fau,fa[v]=tmp.fav; 51 rk[u]=tmp.rku,rk[v]=tmp.rkv; 52 } 53 } 54 55 int unite(int l,int r,int a,int b) 56 { 57 F(j,l,r)for(int i=g[j];i;i=nxt[i]) 58 { 59 if(a<=v[i]&&v[i]<=b)continue;//只合并[l,r]区间的点 60 if(!merge(j,v[i]))return 0; 61 } 62 return 1; 63 } 64 65 void cdq(int l=1,int r=n,int flag=1) 66 { 67 if(l==r){ans[l]=flag+'0';return;} 68 int mid=l+r>>1,pre=top,now=flag&&unite(mid+1,r,l,mid); 69 cdq(l,mid,now),back(pre); 70 now=flag&&unite(l,mid,mid+1,r); 71 cdq(mid+1,r,now),back(pre); 72 } 73 74 int main() 75 { 76 scanf("%d",&t); 77 while(t--) 78 { 79 scanf("%d%d",&n,&m); 80 init(); 81 F(i,1,m) 82 { 83 int x,y; 84 scanf("%d%d",&x,&y); 85 adg(x,y),adg(y,x); 86 } 87 cdq(),printf("%s\n",ans+1); 88 } 89 return 0; 90 }