DZY Loves Chinese/DZY Loves Chinese II 题解

题目传送门1   \, 题目传送门2

题目大意: 给一张无向图,每次询问删掉一些边,然后问图是否连通,强制在线。

题解1

DZY Loves Chinese 和 DZY Loves Chinese II 的区别就是强制在线时 k k k 是否需要异或。

DZY Loves Chinese 是需要的,而这就成了一个大性质:你可以通过读入数据得到真正的 k k k,异或上他给的 k k k 就能求出前面有多少个Connected,所以你可以借此得到前 q − 1 q-1 q1 个询问的答案……最后一问暴力做即可。

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 500010

int n,m,q;
struct edge{
    
    int x,y;}e[maxn];
int d[maxn],tot,ans[maxn];
bool isendl(char x){
    
    return x=='\r'||x=='\n';}
int fa[maxn];
int findfa(int x){
    
    return x==fa[x]?x:fa[x]=findfa(fa[x]);}
void link(int x,int y){
    
    
	x=findfa(x);y=findfa(y);
	if(x!=y)fa[y]=x;
}
bool v[maxn];

int main()
{
    
    
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++)scanf("%d %d",&e[i].x,&e[i].y);
	scanf("%d",&q);
	for(int i=1,k;i<=q;i++){
    
    
		scanf("%d",&k);tot=0;
		while(!isendl(getchar()))scanf("%d",&d[++tot]);
		ans[i]=tot^k;
	}
	for(int i=1;i<q;i++)puts(ans[i+1]-ans[i]?"Connected":"Disconnected");
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=tot;i++)v[d[i]^ans[q]]=true;
	for(int i=1;i<=m;i++)if(!v[i])link(e[i].x,e[i].y);
	for(int i=1;i<=n;i++)if(findfa(i)!=findfa(1))return printf("Disconnected"),0;
	printf("Connected");
}

题解2

这题就没有那么蛋疼的性质了。

考虑求出一棵dfs树,那么剩下的非树边一定是返祖边。考虑随机给每条非树边一个权值,然后令一条树边的权值为所有覆盖它的非树边的权值异或和。

那么,删掉一些边能使图不连通,有两种情况:

  1. 删掉了一个树边和所有覆盖它的非树边
  2. 对于两条树边 E 1 , E 2 E_1,E_2 E1,E2,删掉了一些覆盖他们的非树边,然后对于剩下的非树边,覆盖 E 1 E_1 E1 的非树边集合与覆盖 E 2 E_2 E2 的非树边集合相同,然后删除掉 E 1 , E 2 E_1,E_2 E1,E2

注意到在这两种情况中,被删掉的边的异或和都是 0 0 0

所以你只需要判断每次询问删掉的边中,是否存在若干条边的异或和为 0 0 0 即可,这个可以用线性基简单判断。

代码如下:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 500010
#define ll long long

int n,m,q;
struct edge{
    
    int y,z,next;}e[maxn<<1];
int first[maxn],len=0;
void buildroad(int x,int y,int z){
    
    e[++len]=(edge){
    
    y,z,first[x]};first[x]=len;}
vector<int> E[maxn];
bool vis[maxn];
int rd(){
    
    
	static int x0=9904;
	x0=(1000000007ll*x0+9904527)%998244353;
	return x0;
}
ll val[maxn];
vector<ll> s[maxn];
int dep[maxn],edgeFa[maxn];
void dfs(int x,int fa){
    
    
	vis[x]=true;
	for(int i=first[x];i;i=e[i].next){
    
    
		int y=e[i].y;if(y==fa)continue;
		if(vis[y]){
    
    
			if(dep[y]>dep[x])continue;
			val[e[i].z]=1ll*rd()*rd();
			s[x].push_back(val[e[i].z]);
			s[y].push_back(val[e[i].z]);
		}else{
    
    
			E[x].push_back(y);
			edgeFa[y]=e[i].z;
			dep[y]=dep[x]+1;
			dfs(y,x);
		}
	}
}
void dfs2(int x){
    
    
	for(int y:E[x])dfs2(y),val[edgeFa[x]]^=val[edgeFa[y]];
	for(ll i:s[x])val[edgeFa[x]]^=i;
}
struct XXJ{
    
    
	int d[70];
	void clear(){
    
    
		memset(d,0,sizeof(d));
	}
	bool insert(int x){
    
    
		for(int i=62;i>=0;i--){
    
    
			if(x>>i&1){
    
    
				if(d[i])x^=d[i];
				else return d[i]=x,true;
			}
		}
		return false;
	}
}S;

int main()
{
    
    
	scanf("%d %d",&n,&m);
	for(int i=1,x,y;i<=m;i++){
    
    
		scanf("%d %d",&x,&y);
		buildroad(x,y,i);buildroad(y,x,i);
	}
	dfs(1,0);dfs2(1);
	scanf("%d",&q);int ans=0;
	for(int i=1,k,x;i<=q;i++){
    
    
		scanf("%d",&k);bool p=false;S.clear();
		while(k--)scanf("%d",&x),x^=ans,p|=(!S.insert(val[x]));
		puts(p?"Disconnected":"Connected");
		ans+=!p;
	}
}

猜你喜欢

转载自blog.csdn.net/a_forever_dream/article/details/109729193