- 题目大意:给出一张\(n\)个点\(m\)条边的无向图,进行\(q\)次询问,问删掉某\(k\)条边后图是否联通,强制在线。
- \(N≤100000 \ M≤500000\ Q≤50000\ 1≤K≤15\)
- 先考虑一下离线怎么做:
- \(cdq\)分治。
- 首先把所有没有影响的边都建出来
- 分治过程:
- 1、把左边没有右边有的边建出来
- 2、分治左边
- 3、把并查集恢复至初始的样子
- 4、把右边没有左边有的边建出来
- 5、分治右边
- 虽然每次\(cdq\)的过程中,都暴力判断了每个询问中的边集合的划分情况,但是复杂度是类似于线段树递归的
- 所以总复杂度还是\(O(qklogq)\)
- 有个细节就是,如何将并查集恢复至初始的样子?
- 每当一个点的父亲被修改时,将它和它的父亲入栈,每次只需要记录一下当前过程对应在栈的哪个位置即可
这样就顺带把[Ahoi2013]连通图切掉了
- 强制在线怎么做?
- 我们首先可以求出一棵生成树,然后边就有树边和非树边。
- 对于一条非树边,我们给它赋一个随机的权值。
- 然后对于每条树边,它的权值就是所有覆盖这条树边的非树边的权值的异或和。
- 具体如何搞出树边的权值呢:
- 树上差分一下,在每条非树边的两端打上标记,树边的权值就是y的子树的异或和。
当然你想写一个树剖也可以
- 这样我们可以发现,如果这条树边和所有覆盖它的非树边都删除了,就一定不会联通,而都删除代表选出的这些边的异或和为0。
- 那么问题变成了每次给出一个边集问是否有某个子集的异或和为0。
- 线性基维护一下即可。
- 复杂度\(O(n+qklog(1e9))\)
#include<bits/stdc++.h>
#define R register int
#define ll long long
#define uLL unsigned long long
using namespace std;
const int N=2000001;
const int M=1000001;
int n,m,cnt,vis[N],nt[M],to[M],hd[N],p,flag;
uLL num[M],vl[N],Bas[35];
struct ed{int u,v,us;}G[M];
void link(R f,R t){nt[++cnt]=hd[f],to[cnt]=t,hd[f]=cnt;}
uLL rnd() { return (((uLL)rand())<<32)^((uLL)rand()<<16)^rand(); }
int gi(){
R x=0,k=1;char c=getchar();
while((c<'0'||c>'9')&&c!='-')c=getchar();
if(c=='-')k=-1,c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*k;
}
void Dfs1(R i,R e){
vis[i]=1;
for(R k=hd[i];k;k=nt[k])
if(!vis[to[k]])
G[k>>1].us=1,Dfs1(to[k],i);
}
void Dfs2(R i){
vis[i]=1;
for(R k=hd[i];k;k=nt[k])
if(!vis[to[k]]){
Dfs2(to[k]),vl[k>>1]=num[to[k]];
num[i]^=num[to[k]];
}
}
void ins(R x){
for(R j=0;j<=30;++j){
(!x)?flag=1:0;
if((1<<j)&x){
if(!Bas[j]){Bas[j]=x;return;}
else x^=Bas[j];
}
}
}
int main(){
freopen("chi.in","r",stdin);
freopen("chi.out","w",stdout);
srand(time(NULL));
n=gi(),m=gi(),cnt=1;
for(R i=1;i<=m;++i){
G[i].u=gi(),G[i].v=gi();
link(G[i].u,G[i].v),link(G[i].v,G[i].u);
}
Dfs1(1,0);
for(R i=1;i<=m;++i)
if(!G[i].us){
vl[i]=rnd();
num[G[i].u]^=vl[i],num[G[i].v]^=vl[i];
}
memset(vis,0,sizeof(vis));
Dfs2(1);R u=0,q=gi(),v;
while(q--){
p=gi(),flag=0,memset(Bas,0,sizeof(Bas));
for(R j=1;j<=p;++j)v=gi()^u,ins(vl[v]);
if(!flag)u++,puts("Connected");
else puts("Disconnected");
}
return 0;
}