BZOJ 3569: DZY Loves Chinese II(线性基)

传送门

解题思路

  首先构造出一个生成树,考虑不连接的情况。假设连通两点的非树边和树边都断掉后不连通,那么可以给所有的非树边随机一个互不相同的值,然后树边的权值为过他两端点的非树边权值的异或和,这个可以用一个类似树上差分的东西来实现。询问的时候把所有询问的边权加到线性基里,看是否某个数字能被线性表出。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<set>

using namespace std;
const int N=100005;
const int M=500005;
const int INF=(1<<30);

inline int rd(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return f?x:-x;
}

int n,m,head[N],cnt,to[N<<1],nxt[N<<1],Q,b[35],F[N];
int tag[N],tot,id[N<<1],ans;
bool flag;
set<int> S;

struct Edge{
	int u,v,w;
}edge[M];

inline void add(int bg,int ed,int Id){
	to[++cnt]=ed,nxt[cnt]=head[bg],id[cnt]=Id,head[bg]=cnt;
}

int get(int x){
	if(x==F[x]) return x;
	return F[x]=get(F[x]);
}

void dfs(int x,int fa){
	for(int i=head[x];i;i=nxt[i]){
		int u=to[i]; if(u==fa) continue;
		dfs(u,x);
		edge[id[i]].w^=tag[u];
		tag[x]^=tag[u];	
	}
}

inline void init(){
	memset(b,0,sizeof(b));
	flag=false;
}

inline void Insert(int x){
	for(int i=30;~i;i--)
		if(x&(1<<i)){
			if(!b[i]) {b[i]=x; return ;}
			x^=b[i];
		}
	if(!x) flag=1;
}

int main(){
	srand(time(0)); srand(rand()); srand(20020426);
	n=rd(),m=rd();int x,y;
	for(int i=1;i<=n;i++) F[i]=i;
	for(int i=1;i<=m;i++)
		edge[i].u=rd(),edge[i].v=rd();
	for(int i=1;i<=m;i++){
		x=get(edge[i].u); y=get(edge[i].v);
		if(x==y) {
			edge[i].w=rand()%INF;
			while(S.find(edge[i].w)!=S.end()) edge[i].w=rand()%INF;
			S.insert(edge[i].w);
			tag[edge[i].u]^=edge[i].w; 
			tag[edge[i].v]^=edge[i].w;
			continue;
		}
		add(edge[i].u,edge[i].v,i); add(edge[i].v,edge[i].u,i);
		F[x]=y; tot++;
	}	
	dfs(1,0); Q=rd();
	while(Q--){
		init();
		for(x=rd();x;x--) y=(rd()^ans),Insert(edge[y].w);
		if(flag) puts("Disconnected");
		else puts("Connected"),ans++;
	}
	return 0;
}	
posted @ 2019-01-17 09:13  Monster_Qi  阅读(176)  评论(0编辑  收藏  举报