hdu_5354_Bipartite Graph(cdq分治+并查集判二分图)

题目链接:hdu_5354_Bipartite Graph

题意:

给你一个由无向边连接的图,问对于每一个点来说,如果删除这个点,剩下的点能不能构成一个二分图。

题解:

如果每次排除一个点然后去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 }
View Code

 

posted @ 2016-11-21 12:26  bin_gege  阅读(226)  评论(0编辑  收藏  举报