神校XJ之學霸兮,Dzy皇考曰JC。node
攝提貞於孟陬兮,唯庚寅Dzy以降。ios
紛Dzy既有此內美兮,又重之以修能。git
遂降臨於OI界,欲以神力而凌♂辱衆生。搜索引擎
今Dzy有一魞歄圖,其上有N座祭壇,又有M條膴蠁邊。spa
時而Dzy狂WA而怒髮衝冠,神力外溢,遂有K條膴蠁邊灰飛煙滅。code
然後俟其日A50題則又令其復原。(可視爲當即復原)索引
然如有祭壇沒法相互到達,Dzy之神力便會大減,因而欲知其是否連通。ip
第一行N,Mget
接下來M行x,y:表示M條膴蠁邊,依次編號input
接下來一行Q
接下來Q行:
每行第一個數K然後K個編號c1~cK:表示K條邊,編號爲c1~cK
爲了體如今線,c1~cK均需異或以前回答爲連通的個數
對於每組詢問,輸出到輸出文件zap.out一個正整數,表示知足條件的整數對數。
對於每一個詢問輸出:連通則爲‘Connected’,不連通則爲‘Disconnected’
(不加引號)
5 10
2 1
3 2
4 2
5 1
5 3
4 1
4 3
5 2
3 1
5 4
5
1 1
3 7 0 3
4 0 7 4 6
2 2 7
4 5 0 2 13
Connected
Connected
Connected
Connected
Disconnected
N≤100000 M≤500000 Q≤50000 1≤K≤15
數據保證沒有重邊與自環
Tip:請學會使用搜索引擎
n個點,m條無向邊,求斷掉k條邊後,殘圖是否仍然聯通,強制在線。
考慮先構造出原圖的一棵生成樹,對於每條非樹邊rand一個權值。
每條樹邊的權值設爲能夠與當前邊構成迴路的邊的權值異或和。
那麼,若是當前圖不連通,當且僅當一條樹邊被刪除且覆蓋了這條樹邊的全部邊都被刪除了。
此時,這些邊的權值異或起來爲0。
問題轉化爲:
給定邊中是否存在若干個權值異或起來爲0。
此時即可使用線性基求解。
簡單的建樹操做,任意一棵生成樹都可。
注意用\(fa[ ]\)記錄父親,並用\(use[ ]\)記錄好哪些是樹上的邊,方便以後處理。
void Dfs1(int x){ vis[x]=1; for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(vis[to])continue; use[i>>1]=1,fa[to]=x; Dfs1(to); } }
由於此時是一棵樹,因此增長一條邊會且僅會產生一條迴路。
那麼,咱們給一條非樹邊的兩點附上權值,
在上傳的過程當中把該權值附給與父親節點相連的邊,這樣就能夠覆蓋至整條迴路了。
void Dfs2(int x){ for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(fa[to]^x)continue; Dfs2(to); e[i>>1].val^=val[to]; val[x]^=val[to]; } } for(int i=1;i<=m;i++){ if(use[i])continue; int x=(LL)rand*rand()%1000000000+1; e[i].val=x; val[e[i].x]^=x,val[e[i].y]^=x; }
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> #include<iomanip> #include<cstdlib> #include<ctime> #define MAXN 0x7fffffff typedef long long LL; const int N=100005,M=500005; using namespace std; inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;} int h[N],cnt=1; struct node{int to,next;}g[M<<1]; void AddEdge(int x,int y){g[++cnt].to=y,g[cnt].next=h[x],h[x]=cnt;} struct Edge{int x,y,val;}e[M]; int fa[N],val[M]; bool vis[N],use[M]; void Dfs1(int x){ vis[x]=1; for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(vis[to])continue; use[i>>1]=1,fa[to]=x; Dfs1(to); } } void Dfs2(int x){ for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(fa[to]^x)continue; Dfs2(to); e[i>>1].val^=val[to]; val[x]^=val[to]; } } int p[35]; bool Insert(int x){ for(int i=31;i>=0;i--){ if(!((x>>i)&1))continue; if(!p[i]){p[i]=x;break;} x^=p[i]; } return x>0; } int main(){ srand(time(0)); int n=Getint(),m=Getint(); for(int i=1;i<=m;i++){ int x=e[i].x=Getint(),y=e[i].y=Getint(); AddEdge(x,y),AddEdge(y,x); } Dfs1(1); for(int i=1;i<=m;i++){ if(use[i])continue; int x=(LL)rand()*rand()%1000000000+1; e[i].val=x; val[e[i].x]^=x,val[e[i].y]^=x; } Dfs2(1); int Q=Getint(),ans=0; while(Q--){ int k=Getint(); memset(p,0,sizeof(p)); bool ok=0; for(int i=1;i<=k;i++){ int x=Getint()^ans; if(!Insert(e[x].val))ok=1; } if(!ok)puts("Connected"),ans++; else puts("Disconnected"); } return 0; }