题目大意:给定一个【魞歄连通图】,多次询问当图中某k条边消失时这个图是否联通 强制在线
我们找到这个图的任意一棵生成树 然后对于每条非树边将其的权值赋为一个随机数
对于每条树边 我们将这条树边的权值设为所有覆盖这条树边的边权的异或和
那么图不连通当且仅当删除一条树边和覆盖这条树边的所有边集 而由于刚才的处理一条树边和覆盖这条边的所有边集的异或和为零
于是问题转化成了对于给定的k条边是否存在一个边权的异或和为零的子集 果断高斯消元 由于使用了随机化所以碰撞率极低
好方法学习了。。。构思真是巧妙
记得设随机数种子否则会被卡掉
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 using namespace std; struct abcd{ int to,next; }table[1001001]; int head[M],tot=1; int n,m,q,last_ans; int a[500500],b[M]; int stack[20],top; void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } void DFS1(int x,int from) { static bool v[M]; int i; v[x]=1; for(i=head[x];i;i=table[i].next) { if(table[i].to==from) continue; if(!v[table[i].to]) DFS1(table[i].to,x); else if(!~a[i>>1]) { a[i>>1]=rand(); b[table[i].to]^=a[i>>1]; b[x]^=a[i>>1]; } } } void DFS2(int x,int from) { static bool v[M]; int i; v[x]=1; for(i=head[x];i;i=table[i].next) if(!v[table[i].to]) { DFS2(table[i].to,x); a[i>>1]=b[table[i].to]; b[x]^=b[table[i].to]; } } void Gauss_Elimination() { int i,j,k=0; for(j=1<<30;j;j>>=1) { for(i=k+1;i<=top;i++) if(stack[i]&j) break; if(i==top+1) continue; swap(stack[i],stack[++k]); for(i=1;i<=top;i++) if(stack[i]&j&&i!=k) stack[i]^=stack[k]; } } int main() { srand(19980402); int i,x,y,k; cin>>n>>m; for(i=1;i<=m;i++) scanf("%d%d",&x,&y),Add(x,y),Add(y,x); memset(a,-1,sizeof a); DFS1(1,0); DFS2(1,0); cin>>q; for(i=1;i<=q;i++) { scanf("%d",&k);top=0; for(;k;k--) scanf("%d",&x),stack[++top]=a[x^last_ans]; Gauss_Elimination(); last_ans+=(bool)stack[top]; printf("%s\n",stack[top]?"Connected":"Disconnected"); } }
时间: 2024-10-10 18:34:47