简单来说就是用
s
p
l
a
y
splay
splay维护一棵树的某条链上的信息
主要操作有:
a
c
c
e
s
s
access
access:连通一个点到根的链
m
a
k
e
r
o
o
t
makeroot
makeroot:将
x
x
x变成根
f
i
n
d
r
o
o
t
findroot
findroot:找到树根
l
i
n
k
link
link:将两个点连上边
c
u
t
cut
cut:删掉两个点之间的边
s
p
l
i
t
split
split:将一条链上的信息提取出来
有一些细节需要注意:
l
i
n
k
link
link和
c
u
t
cut
cut首先需要一些条件,其次
c
u
t
cut
cut的条件要注意
c
h
[
x
]
[
1
]
=
=
0
ch[x][1]==0
ch[x][1]==0
r
o
t
a
t
e
rotate
rotate操作的写法,一开始顺序不对就无限递归了
q
w
q
qwq
qwq
s
p
l
a
y
splay
splay的时候判断
!
i
s
r
o
o
t
(
f
a
)
!isroot(fa)
!isroot(fa)
代码在这:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ls ch[x][0]
#define rs ch[x][1]
#define fa f[x]
#define LL long long
#define N 300005
using namespace std;
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
namespace lct{
int f[N],ch[N][2],rev[N],sum[N],w[N];
inline int get(int x){return ch[fa][1]==x;}
inline int isrt(int x){return ch[fa][0]!=x && ch[fa][1]!=x;}
inline void update(int x){sum[x]=sum[ls]^sum[rs]^w[x];}
inline void rever(int x){rev[x]^=1;swap(ls,rs);}
inline void pushdown(int x){
if(rev[x]){
if(ls) rever(ls);
if(rs) rever(rs);
rev[x]=0;
}
}
void pushup(int x){if(!isrt(x)) pushup(fa);pushdown(x);}
inline void rotate(int x){
int old=f[x],oldf=f[old],wh=get(x);
if(!isrt(old)) ch[oldf][get(old)]=x;//要写在前面
f[ch[x][wh^1]]=old; ch[old][wh]=ch[x][wh^1];
f[old]=x; ch[x][wh^1]=old; f[x]=oldf;
update(old); update(x);
}
inline void splay(int x){
pushup(x);
for(;!isrt(x);rotate(x))
if(!isrt(fa)) rotate(get(x)==get(fa)?fa:x);//
}
inline void access(int x){
for(int y=0;x;y=x,x=fa) splay(x),rs=y,update(x);
}
inline void makeroot(int x){
access(x); splay(x); rever(x);
}
inline int findroot(int x){
access(x); splay(x);
while(ls) pushdown(x),x=ls; return x;
}
inline void link(int x,int y){
makeroot(x); f[x]=y;
}
inline void cut(int x,int y){
makeroot(x); access(y); splay(y);
if(ch[y][0]==x && ch[x][1]==0)//注意ch[x][1]==0
f[x]=ch[y][0]=0,update(y);
}
inline void split(int x,int y){
makeroot(x); access(y); splay(y);
}
};
int n,m,opt,x,y;
int main(){
n=rd(); m=rd();
for(int i=1;i<=n;i++) lct::w[i]=rd();
while(m--){
opt=rd(); x=rd(); y=rd();
if(opt==0) lct::split(x,y),printf("%d\n",lct::sum[y]);
if(opt==1)
if(lct::findroot(x)!=lct::findroot(y))
lct::link(x,y);
if(opt==2)
if(lct::findroot(x)==lct::findroot(y))
lct::cut(x,y);
if(opt==3) lct::w[x]=y,lct::splay(x);
}
return 0;
}