【BZOJ3563/BZOJ3569】DZY Loves Chinese I/II(随机化,线性基)

【BZOJ3563/BZOJ3569】DZY Loves Chinese I/II(随机化,线性基)

题面

搞笑版本
正经版本

题面请自行观赏
注意细节。

题解

搞笑版本真的是用来搞笑的
所以我们来讲正经代码
首先随便找一棵生成树出来
于是,我们就得到了一棵树+若干边的东西
如果删掉了若干边使得图不再联通,
证明这条边,以及覆盖了这条边的那些边都被断开了。
于是,我们给所有不再生成树上的边全部随机一个权值
然后树上的边的权值为覆盖了它的所有边的权值异或和
考虑如何查询,如果这一系列边都被断开,导致图不连通
那么,证明可以从断开的边中选出一个非空子集,
使得他们的异或和为\(0\)
线性基实现即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 111111
#define MAXL 555555
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct Line{int v,next,i;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v,int i){e[cnt]=(Line){v,h[u],i};h[u]=cnt++;}
int f[MAX],V[MAXL],val[MAX];;
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
void dfs(int u,int ff)
{
	for(int i=h[u];i;i=e[i].next)
		if(e[i].v!=ff)
			dfs(e[i].v,u),V[e[i].i]^=val[e[i].v],val[u]^=val[e[i].v];
}
struct xxj
{
	int p[31];
	void insert(int x)
	{
		for(int i=30;~i;--i)
			if(x&(1<<i))
			{
				if(!p[i]){p[i]=x;break;}
				x^=p[i];
			}
	}
	bool Query(int x)
	{
		for(int i=30;~i;--i)
			if(x&(1<<i))x^=p[i];
		return x;
	}
	void init(){memset(p,0,sizeof(p));}
}G;
int n,m;
int main()
{
	srand(5550555);
	n=read();m=read();
	for(int i=1;i<=n;++i)f[i]=i;
	for(int i=1;i<=m;++i)
	{
		int u=read(),v=read();
		if(getf(u)!=getf(v))
			Add(u,v,i),Add(v,u,i),f[getf(u)]=getf(v);
		else V[i]=rand()%(1<<30)+1,val[u]^=V[i],val[v]^=V[i];
	}
	dfs(1,0);
	int ans=0,Q=read();
	while(Q--)
	{
		int K=read();G.init();
		bool fl=true;
		while(K--)
		{
			int x=read()^ans;
			if(G.Query(V[x]))G.insert(V[x]);
			else fl=false;
		}
		fl?puts("Connected"):puts("Disconnected");
		ans+=fl;
	}
	return 0;
}

posted @ 2018-04-05 20:37  小蒟蒻yyb  阅读(308)  评论(0编辑  收藏  举报