Description
神校XJ之学霸兮,Dzy皇考曰JC。
摄提贞于孟陬兮,惟庚寅Dzy以降。
纷Dzy既有此内美兮,又重之以修能。
遂降临于OI界,欲以神力而凌♂辱众生。
今Dzy有一魞歄图,其上有N座祭坛,又有M条膴蠁边。
时而Dzy狂WA而怒发冲冠,神力外溢,遂有K条膴蠁边灰飞烟灭。
而后俟其日A50题则又令其复原。(可视为立即复原)
然若有祭坛无法相互到达,Dzy之神力便会大减,于是欲知其是否连通。
N≤100000 M≤500000 Q≤50000 1≤K≤15
Solution
记得之前做过这题的sb版,好像是连k都要异或于是离线瞎jb做就行了
据说dfs树对付无向图有奇效,反正dfs一次又不亏是不是
考虑先求出图的dfs树,那么对于一条树边,我们需要删掉树边和所有包含树边的非树边才能使图不连通
我们给每条非树边赋随机权,树边的权则是所有包含它的非树边的权的异或和,那么问题转变为删掉的边的集合中是否存在子集异或和为0
这是一个可以用线性基搞定的东西,直接上就行了
对于非树边的处理可以考虑用树上差分打标记的方式前后dfs两次即可
Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
using namespace std;
const int N=500005;
const int E=1000005;
struct edge {int y,next;} e[E];
int bin[34],val[N],rec[N],tag[N];
int ls[N],edCnt=1;
bool vis[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}
void dfs1(int now,int fa) {
vis[now]=1;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa) continue;
if (!vis[e[i].y]) dfs1(e[i].y,now);
else if (!val[i/2]) {
val[i/2]=rand();
tag[now]^=val[i/2];
tag[e[i].y]^=val[i/2];
}
}
}
void dfs2(int now,int fa,int u) {
vis[now]=1;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa) continue;
if (vis[e[i].y]) continue;
val[i/2]=u;
dfs2(e[i].y,now,u^tag[e[i].y]);
}
}
int main(void) {
freopen("data.in","r",stdin);
srand(20020303);
bin[0]=1; rep(i,1,31) bin[i]=bin[i-1]*2;
int n=read(),m=read();
rep(i,1,m) add_edge(read(),read());
dfs1(1,0);
fill(vis,0);
dfs2(1,0,tag[1]);
for (int T=read(),lastans=0;T--;) {
rep(i,0,31) rec[i]=0; bool flag=false;
for (int s=read();s--;) {
int x=val[read()^lastans];
drp(i,31,0) if (x&bin[i]) {
if (!rec[i]) {
rec[i]=x;
break;
} else x^=rec[i];
}
flag|=(!x);
}
lastans+=!flag;
if (flag) puts("Disconnected");
else puts("Connected");
}
return 0;
}