bzoj 3569: DZY Loves Chinese II
Description
神校XJ之学霸兮,Dzy皇考曰JC。
摄提贞于孟陬兮,惟庚寅Dzy以降。
纷Dzy既有此内美兮,又重之以修能。
遂降临于OI界,欲以神力而凌♂辱众生。
今Dzy有一魞歄图,其上有N座祭坛,又有M条膴蠁边。
时而Dzy狂WA而怒发冲冠,神力外溢,遂有K条膴蠁边灰飞烟灭。
而后俟其日A50题则又令其复原。(可视为立即复原)
然若有祭坛无法相互到达,Dzy之神力便会大减,于是欲知其是否连通。
题目大意:给定一张图,每次询问去掉几条边之后图是否连通
Solution
先做一棵生成树,然后给每一条非树边随机一个权值
再把每一条树边的权值设为所有跨过这条边的非树边的权值的异或和
如果存在不连通的情况一定是:跨过这条树边的所有非树边和这条边都被去掉了
也就是存在一个子集的权值异或和为 \(0\)
每一次用线性基判断一下就好了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+10;
int n,m,fa[N],head[N],nxt[N*2],to[N*2],num=0,dep[N];bool v[N];
ll x0=914241,mod=1e15,w[N],b[65];int p[20];
inline ll seed(){return x0=(x0*41+19260817)%mod;}
struct data{int x,y;ll w;}e[N];
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
inline void dfs(int x,int last){
for(int u,i=head[x];i;i=nxt[i]){
if((u=to[i])==last)continue;
fa[u]=x;dep[u]=dep[x]+1;dfs(u,x);
}
}
inline void dfs1(int x){
for(int u,i=head[x];i;i=nxt[i]){
if((u=to[i])==fa[x])continue;
w[x]^=w[u];dfs1(u);
}
}
inline bool ins(ll x){
for(int i=60;i>=0;i--){
if(!(x>>i&1))continue;
if(!b[i]){b[i]=x;return true;}
else x^=b[i];
if(!x)return false;
}
return false;
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
srand(19260859);
int x,y,Q,k,cnt=0;
cin>>n>>m;
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);e[i]=(data){x,y};
if(find(x)==find(y)){e[i].w=seed();continue;}
fa[find(y)]=find(x);link(x,y);link(y,x);v[i]=1;
}
dfs(1,1);
for(int i=1;i<=m;i++){
if(dep[e[i].x]<dep[e[i].y])swap(e[i].x,e[i].y);
if(v[i])continue;
w[e[i].x]^=e[i].w;w[e[i].y]^=e[i].w;
}
dfs1(1);
for(int i=1;i<=m;i++)if(v[i])e[i].w=w[e[i].x];
cin>>Q;
while(Q--){
bool flag=1;
scanf("%d",&k);
for(int i=1;i<=k;i++)scanf("%d",&p[i]),p[i]^=cnt;
for(int i=1;i<=k;i++)
if(!ins(e[p[i]].w)){flag=0;break;}
if(flag)puts("Connected"),cnt++;else puts("Disconnected");
memset(b,0,sizeof(b));
}
return 0;
}