UOJ#207. 共价大爷游长沙 LCT

时间:2023-03-08 17:01:45
UOJ#207. 共价大爷游长沙 LCT

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ207.html

题解

  第一次听说 LCT 还可以维护子树信息。

  首先对于每一条路径 rand 一个值,分别放在两个端点上,于是询问一条边是否被所有路径的经过就变成了询问某一边所代表的子树是否包含所有路径的端点各一次。于是我求出子树 xor ,并与当前所有路径值的 xor 比较是否相同就可以判断了。

  于是接下来就变成了 LCT 维护子树 xor 。

  考虑在 LCT 的时候,再对于每一个节点维护其虚儿子的信息。由于 LCT 涉及虚儿子的操作十分少,所以只需要在修改边的虚实关系的时候顺便维护一下就好了。

  时间复杂度 $O((n+m)\log n)$ 。

代码

#include <bits/stdc++.h>
#define link __zzd001
using namespace std;
typedef long long LL;
int read(){
int x=0;
char ch=getchar();
while (!isdigit(ch))
ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+ch-48,ch=getchar();
return x;
}
const int N=100005;
int n,m,id;
int fa[N],son[N][2],rev[N],val[N],sum[N];
void pushup(int x){
sum[x]=sum[son[x][0]]^val[x]^sum[son[x][1]];
}
int isroot(int x){
return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
}
int wson(int x){
return son[fa[x]][1]==x;
}
void rotate(int x){
if (isroot(x))
return;
int y=fa[x],z=fa[y],L=wson(x),R=L^1;
if (!isroot(y))
son[z][wson(y)]=x;
fa[x]=z,fa[y]=x,fa[son[x][R]]=y;
son[y][L]=son[x][R],son[x][R]=y;
pushup(y),pushup(x);
}
void pushdown(int x){
if (rev[x]){
swap(son[x][0],son[x][1]);
rev[son[x][0]]^=1;
rev[son[x][1]]^=1;
rev[x]=0;
}
}
void pushadd(int x){
if (!isroot(x))
pushadd(fa[x]);
pushdown(x);
}
void splay(int x){
pushadd(x);
for (int y=fa[x];!isroot(x);rotate(x),y=fa[x])
if (!isroot(y))
rotate(wson(x)==wson(y)?y:x);
}
void access(int x){
for (int t=0;x;t=x,x=fa[x]){
splay(x);
val[x]^=sum[son[x][1]]^sum[t];
fa[t]=x,son[x][1]=t;
pushup(x);
}
}
void rever(int x){
access(x),splay(x),rev[x]^=1;
}
void link(int x,int y){
rever(x),rever(y);
fa[x]=y,val[y]^=sum[x];
pushup(y);
}
void cut(int x,int y){
rever(x),access(y),splay(y);
son[y][0]=fa[x]=0;
pushup(y);
}
int randv[N*3],rands=0,cnt=0;
pair <int,int> path[N*3];
int randint(){
int a=rand()&65535,b=rand()&65535;
return (a<<15)^b;
}
int main(){
srand('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I');
id=read(),n=read(),m=read();
for (int i=1;i<n;i++){
int x=read(),y=read();
link(x,y);
}
while (m--){
int opt=read(),x,y,u,v;
if (opt==1){
x=read(),y=read(),u=read(),v=read();
cut(x,y),link(u,v);
}
else if (opt==2){
x=read(),y=read();
int now=randv[++cnt]=randint();
path[cnt]=make_pair(x,y);
rever(x),val[x]^=now,pushup(x);
rever(y),val[y]^=now,pushup(y);
rands^=now;
}
else if (opt==3){
u=read();
int now=randv[u];
x=path[u].first,y=path[u].second;
rever(x),val[x]^=now,pushup(x);
rever(y),val[y]^=now,pushup(y);
rands^=now;
}
else if (opt==4){
x=read(),y=read();
rever(x);
access(y);
splay(y);
puts(rands==sum[x]?"YES":"NO");
}
}
return 0;
}