bzoj 3569 DZY Loves Chinese II

bzoj

对于这题先套路的找出一棵生成树,然后还会剩下一些非树边,要删边使得图不连通(假设先删非树边)当且仅当删掉了一条没有返祖边覆盖的树边,或者是删了两条被相同的非树边集合覆盖的树边

现在要处理这个问题.我们给所有非树边一个随机权值,然后树边的权值就是覆盖它的非树边权值异或和,这个可以树上差分实现,那么两条树边如果异或和相等就认为覆盖它们的非树边集合相同,如果一条树边异或和为0就认为没有被覆盖.如果我们的随机的值域为\(2^w\),那么出错的概率就是\(\frac{1}{2^w}\),因为某个数只有正好等于那个对应的数才会出错

先给结论.对于给出的一个边集,删掉以后不连通,当且仅当这个边集中有一个子集权值异或和为0.接下来是感性证明:如果这个子集全是非树边那应该就在别的地方直接WA了;如果有一个树边,也就是选出来的其他非树边都是覆盖它的,所以删掉后会不连通;如果有\(\ge 2\)个树边,那么一定可以把其他一些其他非树边分别异或到树边上去,使得有两个树边异或和相同.顺便再推荐一波理性证明.所以实现可以用线性基,做到出现线性相关的子集就可以不连通

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=1e5+10;
int rd()
{
	int x=0,w=1;char ch=0;
	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
int to[N*10],nt[N*10],hd[N],tot=1;
void add(int x,int y)
{
	++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
	++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
}
int n,m,q,fa[N],de[N],sz[N],hs[N],top[N];
uLL a[N],w[N*5],bs[70];
bool vv[N*5];
void dfs1(int x)
{
	sz[x]=1;
	for(int i=hd[x];i;i=nt[i])
	{
		int y=to[i];
		if(de[y]) continue;
		vv[i>>1]=1;
		fa[y]=x,de[y]=de[x]+1,dfs1(y);
		sz[x]+=sz[y],hs[x]=sz[hs[x]]>sz[y]?hs[x]:y;
	}
}
void dfs2(int x)
{
	if(hs[x]) top[hs[x]]=top[x],dfs2(hs[x]);
	for(int i=hd[x];i;i=nt[i])
	{
		int y=to[i];
		if(!vv[i>>1]||y==fa[x]||y==hs[x]) continue;
		top[y]=y,dfs2(y);
	}
}
int glca(int x,int y)
{
	while(top[x]!=top[y])
	{
		if(de[top[x]]<de[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	return de[x]<de[y]?x:y;
}
void dfs3(int x)
{
	for(int i=hd[x];i;i=nt[i])
	{
		int y=to[i];
		if(!vv[i>>1]||y==fa[x]) continue;
		dfs3(y),a[x]^=a[y],w[i>>1]=a[y];
	}
}

int main()
{
	n=rd(),m=rd();
	for(int i=1;i<=m;++i) add(rd(),rd());
	de[1]=1,dfs1(1);
	top[1]=1,dfs2(1);
	for(int i=1;i<=m;++i)
		if(!vv[i])
		{
			w[i]=(1ull*rand()<<32)|1ull*rand();
			int x=to[i<<1],y=to[i<<1|1],lca=glca(x,y);
			if(y==lca) swap(x,y);
			a[x]^=w[i],a[y]^=w[i];
			if(x!=lca) a[lca]^=w[i];
		}
	dfs3(1);
	q=rd();
	int las=0;
	while(q--)
	{
		memset(bs,0,sizeof(bs));
		bool ok=0;
		int kk=rd();
		while(kk--)
		{
			uLL x=w[rd()^las];
			for(int i=64;~i;--i)
				if(x>>i&1)
				{
					if(!bs[i]){bs[i]=x;break;}
					x^=bs[i];
					if(!x) break;
				}
			ok|=!x;
		}
		las+=!ok;
		puts(ok?"Disconnected":"Connected");
	}
    return 0;
}
posted @ 2019-10-01 08:21  ✡smy✡  阅读(146)  评论(0编辑  收藏  举报