讲解博客:https://www.cnblogs.com/zhoushuyu/p/8137553.html
struct Link_Cut_Tree
{
int fa[N],ch[N][2],sum[N],rev[N],Stack[N],top;
bool son(int x)//判断点x是父节点的左儿子还是右儿子
{
return x==ch[fa[x]][1];
}
bool isroot(int x)//判断一个点是不是根节点(当前splay的根节点)
{
return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
void pushup(int x)//上传(维护信息)
{
sum[x]=sum[ch[x][0]]^sum[ch[x][1]]^val[x];
}
void reverse(int x)//交换左右子树
{
if(!x)return;
swap(ch[x][0],ch[x][1]);rev[x]^=1;
}
void pushdown(int x)//下传(更新反转标记用)
{
if(!rev[x])return;
reverse(ch[x][0]);reverse(ch[x][1]);
rev[x]=0;
}
void rotate(int x)//splay的旋转
{
int y=fa[x],z=fa[y],c=son(x);
ch[y][c]=ch[x][c^1];if(ch[y][c]) fa[ch[y][c]]=y;
fa[x]=z;if(!isroot(y))ch[z][son(y)]=x;
ch[x][c^1]=y;fa[y]=x;pushup(y);
}
void splay(int x)//将x转到根节点
{
Stack[top=1]=x;
for (int i=x;!isroot(i);i=fa[i])
Stack[++top]=fa[i];
while (top) pushdown(Stack[top--]);
for (int y=fa[x];!isroot(x);rotate(x),y=fa[x])
if (!isroot(y)) son(x)^son(y)?rotate(x):rotate(y);
pushup(x);
}
void access(int x)//把x节点到x所在树(连通块)的根节点之间的路径全部变成重路径
{
for (int y=0;x;y=x,x=fa[x])
splay(x),ch[x][1]=y,pushup(x);
}
void makeroot(int x)//把x节点设为x所在树(连通块)的根节点
{
access(x);splay(x);reverse(x);
}
int findroot(int x)//找到x节点所在树(连通块)的根节点
{
access(x);splay(x);
while (ch[x][0]) x=ch[x][0];
splay(x);return x;
}
void split(int x,int y)//抠出x到y的路径,抠完以后y是splay的根
{
makeroot(x);access(y);splay(y);
}
void cut(int x,int y)//砍断x到y的边
{
makeroot(x);
if(findroot(y)==x&&fa[y]==x&&!ch[y][0])
fa[y]=ch[x][1]=0,pushup(x);
}
void link(int x,int y)//连接x到y的边
{
makeroot(x);
if(findroot(y)!=x)fa[x]=y;
}
}t;