拿出原图的一个生成树
那么一个图不连通当且仅当切断了某一段的树边和所有覆盖这一段的非树边
给所有的非树边一个随机的哈希值,树边的哈希值为所有覆盖它的非树边的哈希值的异或和
若一条树边以及所有覆盖它的非树边被移除了,那么这些边的异或和为0
我们用线性基实现查询询问是否存在一个子集异或和为0
#include <bits/stdc++.h>
#define N 100050
#define M 1000050
#define each(v) for (int i=h[u],v; v=e[i].b,i; i=e[i].n)
using namespace std;
typedef unsigned long long uLL;
struct Edge{ int a,b,n; }e[2*M];
uLL hash[M],tmp[M];
int h[N],vis[N],cnt=1,n,m;
int flag;
uLL F[65];
inline int rd() { int r; scanf("%d",&r); return r; }
void link(int x,int y) {
e[++cnt] = (Edge){x,y,h[x]}, h[x] = cnt;
e[++cnt] = (Edge){y,x,h[y]}, h[y] = cnt;
}
uLL rnd() { return (((uLL)rand())<<32)^((uLL)rand()<<16) ^ rand(); }
void dfs1(int u,int f) {
vis[u] = 1;
each(v) if (v != f) {
if (!vis[v]) dfs1(v,u); else hash[i>>1] = rnd();
}
}
void dfs2(int u,int f) {
vis[u] = 1;
each(v) if (v != f && !vis[v]) {
dfs2(v,u);
tmp[u] ^= tmp[v];
hash[i>>1] = tmp[v];
}
}
void add(uLL x) {
for (int i=60;i>=0;i--) {
x == 0 ? flag = 1 : 0;
if ((x>>i)&1) {
if (!F[i]) { F[i] = x; break; } else x ^= F[i];
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
srand(19930726);
n = rd(), m = rd();
for (int _=1;_<=m;_++) link(rd(),rd());
memset(vis,0,sizeof(vis));
dfs1(1,1);
for (int _=1;_<=m;_++)
tmp[e[_<<1].a] ^= hash[_], tmp[e[_<<1].b] ^= hash[_];
memset(vis,0,sizeof(vis));
dfs2(1,1);
int q=rd(), ans = 0;
while (q--) {
int k = rd(); flag = 0;
for (int _=0;_<=60;_++) F[_] = 0LL;
for (int _=1;_<=k;_++) add( hash[rd()^ans] );
!flag ? ans++, puts("Connected") : puts("Disconnected");
}
return 0;
}