本模板是从网上复制来的。
操作如下:
access(x,y),将x到y的路径连上实边,其他儿子都变成虚边。
link(x,y),将x和y连起来。
cut(x,y),将x和y断开。
对于修改操作,若将点x的权值修改成y,只需splay(x)然后v[x] = y即可。
findroot(x)==findroot(y)表示连通。
makeroot(x)表示将x选为跟。
split(x,y),将x到y的路径变成一个splay,且y为splay的跟。
模板在下面:
#include <bits/stdc++.h>
#define sc(n) scanf("%d",&n)
#define pt(n) printf("%d\n",n)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define vi vector<int>
#define vl vector<long long>
#define pb push_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 3e5+7;
int fa[maxn],ch[maxn][2],v[maxn],siz[maxn],st[maxn];
bool rev[maxn];
bool nroot(int x) //判断节点是否为一个splay的跟
{
return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
}
void pushup(int x) //询问的是x到y路径的异或和
{
siz[x] = siz[ch[x][0]] ^ siz[ch[x][1]] ^ v[x];
}
void pushr(int x) //翻转标记
{
swap(ch[x][0],ch[x][1]);
rev[x] ^= 1;
}
void pushdown(int x)
{
if(rev[x])
{
if(ch[x][0]) pushr(ch[x][0]);
if(ch[x][1]) pushr(ch[x][1]);
rev[x] = 0;
}
}
void rotate(int x)
{
int y = fa[x],z = fa[y],k = ch[y][1]==x,w = ch[x][!k];
if(nroot(y)) ch[z][ch[z][1]==y]=x;
ch[x][!k] = y,ch[y][k] = w;
if(w) fa[w] = y;
fa[y] = x,fa[x] = z;
pushup(y);
}
void splay(int x)
{
int y = x,top = 0;
st[++top] = y;
while(nroot(y)) st[++top] = y = fa[y];
while(top) pushdown(st[top--]);
while(nroot(x))
{
y = fa[x];
int z = fa[y];
if(nroot(y)) rotate((ch[y][0]==x)^(ch[z][0]==y)?x:y);
rotate(x);
}
pushup(x);
}
void access(int x)
{
for(int y=0;x;x=fa[y=x])
{
splay(x);
ch[x][1] = y;
pushup(x);
}
}
void makeroot(int x)
{
access(x);
splay(x);
pushr(x);
}
int findroot(int x)
{
access(x);
splay(x);
while(ch[x][0])
{
pushdown(x);
x = ch[x][0];
}
splay(x);
return x;
}
void split(int x,int y)
{
makeroot(x);
access(y);
splay(y);
}
void link(int x,int y)
{
makeroot(x);
if(findroot(y)!=x) fa[x] = y;
}
void cut(int x,int y)
{
makeroot(x);
if(findroot(y)==x && fa[y]==x && !ch[y][0])
{
fa[y] = ch[x][1] = 0;
pushup(x);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",v+i);
while(m--)
{
int t,x,y;
scanf("%d%d%d",&t,&x,&y);
if(t==0)
{
split(x,y);
printf("%d\n",siz[y]);
}
if(t==1) link(x,y);
if(t==2) cut(x,y);
if(t==3)
{
splay(x);
v[x] = y;
}
}
return 0;
}