您的位置:首页 > 其它

bzoj 3569: DZY Loves Chinese II dfs树+线性基【神题】

2017-09-04 21:35 316 查看

题意

给出一个无向图,每次询问删掉给定的k条边后图是否仍然连通。强制在线。

n<=100000,m<=500000,q<=50000,k<=15

分析

记得之前有位大爷告诉我说无向图的题有时候用dfs树会有奇效。

这题的题解十分的巧妙,我们可以先把原图的一棵dfs树求出来,然后对于每条非树边,给其赋一个随机权值;对于每条树边,其权值为所有包含它的非树边的权值异或和。那么图不连通,当且仅当一条树边和所有包含它的边都被删掉了,那么问题就转化成了删掉的边中能否选出一个子集使得其权值异或和为0。

直接上线性基即可!

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=100005;

int n,m,cnt,last
,val[N*5],c
,bas[35],bin[35];
bool vis
;
struct edge{int to,next;}e[N*10];

int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}

void addedge(int u,int v)
{
e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}

void dfs1(int x,int fa)
{
vis[x]=1;
for (int i=last[x];i;i=e[i].next)
{
if (e[i].to==fa) continue;
if (!vis[e[i].to]) dfs1(e[i].to,x);
else if (!val[(i+1)/2]) val[(i+1)/2]=rand(),c[e[i].to]^=val[(i+1)/2],c[x]^=val[(i+1)/2];
}
}

void dfs2(int x,int fa,int from)
{
vis[x]=1;
for (int i=last[x];i;i=e[i].next)
{
if (e[i].to==fa) continue;
if (!vis[e[i].to]) dfs2(e[i].to,x,i),c[x]^=c[e[i].to];
}
if (from) val[(from+1)/2]=c[x];
}

int main()
{
srand(19980402);
bin[0]=1;
for (int i=1;i<=30;i++) bin[i]=bin[i-1]*2;
n=read();m=read();
for (int i=1;i<=m;i++)
{
int x=read(),y=read();
addedge(x,y);
}
dfs1(1,0);
memset(vis,0,sizeof(vis));
dfs2(1,0,0);
int ans=0,q=read();
while (q--)
{
int k=read(),s=0;
memset(bas,0,sizeof(bas));
for (int i=1;i<=k;i++)
{
int x=val[read()^ans];
for (int j=30;j>=0;j--)
if (x&bin[j])
{
if (!bas[j])
{
s++;bas[j]=x;
break;
}
else x^=bas[j];
}
}
if (s<k) puts("Disconnected");
else ans++,puts("Connected");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: