bzoj3237 [Ahoi2013]连通图
题意:
给一张n个点m条边的无向图。Q次询问每次给一个大小为c的边集,问删去这些边后图是否还联通?
$n,m,Q\leq 2\times 10^5,c\leq 4.$
题解:
随机权值。
跑出任意一棵生成树,给每条非树边随机一个权值,每条树边的权值记为覆盖它的非树边的权值异或和。可以发现对于一个给定的边集合,如果有一个子集边权异或和为0,那么图必定不连通。判断是否存在子集异或和为0可以使用线性基。
复杂度$\mathcal{O}(n+30Qc)$。
code:
1 #include<bits/stdc++.h> 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++) 3 #define per(i,x,y) for (int i=(x);i>=(y);i--) 4 #define ll long long 5 #define inf 1000000001 6 #define y1 y1___ 7 using namespace std; 8 char gc(){ 9 static char buf[100000],*p1=buf,*p2=buf; 10 return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; 11 } 12 #define gc getchar 13 ll read(){ 14 char ch=gc();ll x=0;int op=1; 15 for (;!isdigit(ch);ch=gc()) if (ch=='-') op=-1; 16 for (;isdigit(ch);ch=gc()) x=(x<<1)+(x<<3)+ch-'0'; 17 return x*op; 18 } 19 #define N 200005 20 int n,m,cnt,Q,clk,head[N],vis[N],w[N],a[35],w_[N]; 21 struct edge{int to,nxt;}e[N<<1]; 22 void adde(int x,int y){ 23 e[++cnt].to=y;e[cnt].nxt=head[x];head[x]=cnt; 24 } 25 int Rnd(){ 26 return rand()<<15|rand(); 27 } 28 void dfs(int u,int pr){ 29 vis[u]=++clk; 30 for (int i=head[u];i;i=e[i].nxt) if (e[i].to!=pr){ 31 int v=e[i].to; 32 if (!vis[v]){ 33 dfs(v,u); 34 w_[(i+1)/2]=w[v]; 35 w[u]^=w[v]; 36 } else if (vis[u]>vis[v]){ 37 int tmp=Rnd(); 38 w_[(i+1)/2]=tmp; 39 w[v]^=tmp;w[u]^=tmp; 40 } 41 } 42 } 43 bool ins(int x){ 44 per (i,30,0) if (x>>i&1) 45 if (!a[i]) return a[i]=x,1;else x^=a[i]; 46 return 0; 47 } 48 int main(){ 49 srand(20030731); 50 n=read(),m=read(); 51 rep (i,1,m){ 52 int x=read(),y=read(); 53 adde(x,y);adde(y,x); 54 } 55 dfs(1,0); 56 Q=read(); 57 while (Q--){ 58 bool flag=1; 59 for (int k=read();k;k--){ 60 int x=read(); 61 if (!ins(w_[x])) flag=0; 62 } 63 puts(flag?"Connected":"Disconnected"); 64 rep (i,0,30) a[i]=0; 65 } 66 return 0; 67 }