bzoj3569 DZY Loves Chinese II

题目链接

problem

给出一个\(n\)个点\(m\)条边的无向图,然后有\(Q\)次询问,每次询问会给出\(k\)条边,你需要回答删掉这\(k\)条边之后这个无向图还是不是连通。

\(n\le 10^5,m\le 5\times 10^5,k\le 15\)

solution

先找出一个\(dfs\)树,考虑在什么情况下无向图会变得不连通。

当且仅当存在一条树边,满足所有覆盖这条树边的返祖边和这条树边都被删除时,无向图不连通。

那么如何判断是不是存在这样一条树边呢,我们可以给每条返祖边随机一个权值,每条树边的权值就是所有覆盖它的返祖边的权值异或和。对于一次查询,如果查询的边权线性相关说明一定能找到一个子集异或和为0,也就是满足无向图不连通的条件了。

code

/*
* @Author: wxyww
* @Date:   2020-05-25 16:14:15
* @Last Modified time: 2020-05-25 16:47:10
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 500100;
ll read() {
	ll x = 0,f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1; c = getchar();
	}
	while(c >= '0' && c <= '9') {
		x = x * 10 + c - '0'; c = getchar();
	}
	return x * f;
}
int n,m;
struct node {
	int v,nxt,w,id;
}e[N << 1];

int head[N],ejs = 1;
void add(int u,int v,int id) {
	e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].id = id;
}
int vis[N],w[N];

void dfs1(int u,int fa) {
	vis[u] = 1;
	for(int i = head[u];i;i = e[i].nxt) {
		int v = e[i].v;
		if(e[i].w || v == fa) continue;
		if(vis[v]) {
			e[i].w = e[i ^ 1].w = rand() + 1;
			w[u] ^= e[i].w;w[v] ^= e[i].w;
			continue;
		}
		dfs1(v,u);
	}
}

void dfs2(int u,int fa) {
	for(int i = head[u];i;i = e[i].nxt) {
		int v = e[i].v;if(v == fa || e[i].w) continue;
		dfs2(v,u);
		w[u] ^= w[v];
		e[i].w = e[i ^ 1].w = w[v];
	}
}

int cnt,p[32];
int ins(int x) {

	// printf("!!!%d\n",x);
	
	for(int i = 30;i >= 0;--i) {
		if(x >> i & 1) {
			if(!p[i]) {p[i] = x;return 1;}
			x ^= p[i];
		}
	}
	return 0;
}
void solve() {
	int k = read(),flag = 0;
	for(int i = 1;i <= k;++i) {
		int x = read() ^ cnt;
		// printf("%d ",x);
		if(flag) continue;
		if(!ins(e[x << 1].w)) {
			puts("Disconnected");
			flag = 1;
			continue;
		}
	}
	// puts("");
	if(!flag) {
		++cnt;
		puts("Connected");
	}
}

int main() {
	// freopen("1.in","r",stdin);
	n = read(),m = read();

	for(int i = 1;i <= m;++i) {
		int u = read(),v = read();
		add(u,v,i);add(v,u,i);
	}

	dfs1(1,0);
	dfs2(1,0);
	int Q = read();
	while(Q--) {
		memset(p,0,sizeof(p));
		solve();
	}
	return 0;
}
posted @ 2020-05-25 16:57  wxyww  阅读(513)  评论(0编辑  收藏  举报