【CF1555F】Good Graph

题目

题目链接:https://codeforces.com/contest/1555/problem/F
\(n\) 个点,有 \(Q\) 次操作。每次操作给出 \(x,y,z\),如果满足在 \(x,y\) 之间加了一条权值为 \(z\) 的边后,不存在任意一个简单环的所有边权值异或和为 \(0\),那么就连上这条边,否则忽略这条边。
对于每一条边输出它是否被连上了。
\(n\leq 3\times 10^5,Q\leq 5\times 10^5,z\in\{0,1\}\)

思路

考场被卡常了。。我把

stack<int> st;
st.push(x);
for (int y=x;notrt(y);y=fa[y]) st.push(fa[y]);
for (;st.size();st.pop()) pushdown(st.top());

改成了

void down(int x)
{
	if (notrt(x)) down(fa[x]);
	pushdown(x);
}

就从 3s 跑到了 0.7s??


有一个显而易见的结论:如果加边后存在一条边同时在两个简单环内,那么必然不会加这条边。因为如果两个简单环的异或和都为 \(1\),那么这两个环拼在一起去掉重复边形成的大环的异或和一定为 \(0\)
所以说我们需要支持加边,路径覆盖,询问路径异或和。采用 LCT 即可。
为了卡常,我赛后参考了 WZYYN 大爷的代码,没有在 LCT 上维护异或和,而是用带权并查集维护异或和。事实上慢的地方并不是那里 /fad。
而且由于每次路径覆盖一定是覆盖之前没有被覆盖的部分,所以不用懒标记,直接暴力覆盖即可。
时间复杂度 \(O(Q\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N=800010;
int n,m,cnt,father[N],xors[N];

int find(int x)
{
	if (x==father[x]) return x;
	int y=father[x]; father[x]=find(y);
	xors[x]^=xors[y];
	return father[x];
}

int read()
{
	int d=0; char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d;
}

struct LCT
{
	int ch[N][2],fa[N];
	bool rev[N],vis[N],flag[N];
	
	bool pos(int x) { return ch[fa[x]][1]==x; }
	bool notrt(int x) {	return (ch[fa[x]][0]==x) || (ch[fa[x]][1]==x); }
	
	void pushup(int x)
	{
		flag[x]=flag[ch[x][0]]|flag[ch[x][1]]|vis[x];
	}
	
	void pushdown(int x)
	{
		if (rev[x])
		{
			int lc=ch[x][0],rc=ch[x][1];
			if (lc) swap(ch[lc][0],ch[lc][1]),rev[lc]^=1;
			if (rc) swap(ch[rc][0],ch[rc][1]),rev[rc]^=1;
			rev[x]=0;
		}
	}
	
	void rotate(int x)
	{
		int y=fa[x],z=fa[y],k=pos(x),c=ch[x][k^1];
		if (notrt(y)) ch[z][pos(y)]=x; ch[x][k^1]=y; ch[y][k]=c;
		if (c) fa[c]=y; fa[y]=x; fa[x]=z;
		pushup(y); pushup(x);
	}
	
	void down(int x)
	{
		if (notrt(x)) down(fa[x]);
		pushdown(x);
	}
	
	void splay(int x)
	{
		down(x);
		for (;notrt(x);rotate(x))
			if (notrt(fa[x])) rotate(pos(x)==pos(fa[x])?fa[x]:x);
	}
	
	void access(int x)
	{
		for (int y=0;x;y=x,x=fa[x])
		{
			splay(x); ch[x][1]=y;
			pushup(x);
		}
	}
	
	void makert(int x)
	{
		access(x); splay(x);
		rev[x]^=1; swap(ch[x][0],ch[x][1]);
	}
	
	void link(int x,int y)
	{
		makert(x); fa[x]=y;
	}
	
	void update(int x)
	{
		if (x>n) vis[x]=1;
		if (ch[x][0]) update(ch[x][0]);
		if (ch[x][1]) update(ch[x][1]);
		pushup(x);
	}
}lct;

int main()
{
	n=cnt=read(); m=read();
	for (int i=1;i<=n;i++) father[i]=i;
	for (int i=1;i<=m;i++)
	{
		int x=read(),y=read(),z=read();
		if (find(x)!=find(y))
		{
			int xx=find(x),yy=find(y);
			father[xx]=yy; xors[xx]=xors[x]^xors[y]^z; 
			cnt++; lct.link(x,cnt); lct.link(y,cnt);
			cout<<"YES\n";
		}
		else
		{
			if (xors[x]^xors[y]==z) { cout<<"NO\n"; continue; }
			lct.makert(x); lct.access(y); lct.splay(x);
			if (lct.flag[x]) { cout<<"NO\n"; continue; }
			lct.update(x);
			cout<<"YES\n";
		}
	}
	return 0;
}
posted @ 2021-07-31 09:03  stoorz  阅读(180)  评论(0编辑  收藏  举报