[bzoj3569]DZY Loves Chinese II
作者:互联网
若原图不连通,显然答案都是"Disconnected",不妨假设原图连通
任求一棵生成树,对每条非树边随机一个权值,并将树边的权值为所有"包含"其的非树边("包含"指树边在非树边两端点生成树的路径上),那么每一条边即都有一个边权
下面,只需要判定删除的边权是否存在非空子集异或和为0即可(存在即不连通)
具体实现上,随机值范围在long long中即可,求树边的权值可以差分,判定使用线性基即可
时间复杂度为$o(m+qk\log V)$(其中$V$为随机值范围),可以通过
关于其的正确性,证明来自于这篇blog,摘抄如下——
必要性:
若删掉边后的图不连通,任选其中一个极大连通块$S$,考虑$S$和$\complement_{V}S$(其中$V$为原图点集)之间的边,显然存在(指非空)且都被删除,下面只需要说明这些边异或和为0
关于这个,考虑所有非树边(包括不在$S$和$\complement_{V}S$之间的边),对其分类讨论:
1.在$S$或$\complement_{V}S$内部,将其两端点生成树的路径上$S$和$\complement_{V}S$之间的边取出,由于每一条这样的边都会改变其所属的集合,而最终其所属集合没有变化,那么必然是偶数条,即其贡献为0
2.在$S$和$\complement_{V}S$之间的边,同理取出这些边,必然是奇数条,即其贡献也为0
综上,即得证
充分性:
考虑一个异或和为0的非空边集,将其中的树边先删除,即将生成树划分为若干个连通块(不考虑非树边)
对这些连通块黑白染色,要求使得任意一条被删除的树边两端点所属连通块不同色
此时,考虑一条未被删除的非树边,在忽略随机的值很特殊的情况下,可以认为其两端点生成树的路径上在此边集中的边为偶数条,也即其所连结的两个连通块同色
由此,不难发现不同色的点对之间一定没有(未被删除的)边,也即这两个集合不连通,同时由于边集非空,即总存在树边,那么两个集合都非空
综上,即得证
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define M 500005 5 #define L 63 6 #define ll long long 7 struct Edge{ 8 int nex,to; 9 }edge[M<<1]; 10 int E,n,m,q,x,y,ans,head[N],dfn[N]; 11 ll z,a[L],val[M],sum[N]; 12 void add(int x,int y){ 13 edge[E].nex=head[x]; 14 edge[E].to=y; 15 head[x]=E++; 16 } 17 void dfs1(int k,int fa){ 18 dfn[k]=++dfn[0]; 19 for(int i=head[k];i!=-1;i=edge[i].nex) 20 if (edge[i].to!=fa){ 21 if (!dfn[edge[i].to])dfs1(edge[i].to,k); 22 else{ 23 if (dfn[k]<dfn[edge[i].to])continue; 24 for(int j=0;j<L;j++)val[(i>>1)]=(val[(i>>1)]<<1)+rand()%2; 25 sum[k]^=val[(i>>1)],sum[edge[i].to]^=val[(i>>1)]; 26 } 27 } 28 } 29 void dfs2(int k,int fa){ 30 dfn[k]=++dfn[0]; 31 for(int i=head[k];i!=-1;i=edge[i].nex) 32 if (!dfn[edge[i].to]){ 33 dfs2(edge[i].to,k); 34 val[(i>>1)]=sum[edge[i].to]; 35 sum[k]^=sum[edge[i].to]; 36 } 37 } 38 int main(){ 39 scanf("%d%d",&n,&m); 40 memset(head,-1,sizeof(head)); 41 for(int i=1;i<=m;i++){ 42 scanf("%d%d",&x,&y); 43 add(x,y); 44 add(y,x); 45 } 46 dfs1(1,0); 47 scanf("%d",&q); 48 for(int i=1;i<=n;i++) 49 if (!dfn[i]){ 50 while (q--)printf("Disconnected\n"); 51 return 0; 52 } 53 memset(dfn,0,sizeof(dfn)); 54 dfs2(1,0); 55 while (q--){ 56 scanf("%d",&x); 57 memset(a,0,sizeof(a)); 58 int tot=0; 59 for(int i=1;i<=x;i++){ 60 scanf("%d",&y); 61 z=val[(y^ans)-1]; 62 for(int j=L-1;j>=0;j--) 63 if (z&(1LL<<j)){ 64 if (!a[j]){ 65 a[j]=z; 66 tot++; 67 } 68 z^=a[j]; 69 } 70 } 71 if (tot<x)printf("Disconnected\n"); 72 else{ 73 printf("Connected\n"); 74 ans++; 75 } 76 } 77 }View Code
标签:连通,int,complement,II,edge,DZY,非树边,bzoj3569,sum 来源: https://www.cnblogs.com/PYWBKTDA/p/15024702.html