標籤:bzoj bzoj3569 高斯消元
題目大意:給定一個【魞歄連通圖】,多次詢問當圖中某k條邊消失時這個圖是否聯通 強制線上
我們找到這個圖的任意一棵產生樹 然後對於每條非樹邊將其的權值賦為一個隨機數
對於每條樹邊 我們將這條樹邊的權值設為所有覆蓋這條樹邊的邊權的異或和
那麼圖不連通若且唯若刪除一條樹邊和覆蓋這條樹邊的所有邊集 而由於剛才的處理一條樹邊和覆蓋這條邊的所有邊集的異或和為零
於是問題轉化成了對於給定的k條邊是否存在一個邊權的異或和為零的子集 果斷高斯消元 由於使用了隨機化所以碰撞率極低
好方法學習了。。。構思真是巧妙
記得設隨機數種子否則會被卡掉
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 100100using 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"); }}
BZOJ 3569 DZY Loves Chinese II 高斯消元