Link-Cut Tree可以十分灵活地处理树,它可以轻松地将树节点Cut或者Link。
它的核心操作是Access(x)和Makeroot(x),功能分别是将x与原树的根建立起联系(具体来说是一头一尾);将x变成原树的根。
注意其中有一个叫“原树”,一个是“辅助树”。Splay和Rotate操作都是对辅助树而言的。
模板:P3690 【模板】动态树(Link Cut Tree)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
class Class_LCT
{
private:
//const int LCT_SIZE = N;
int Stack[N + 5];
struct Tree
{
int Val, Sum, Father, Rev, Son[2];
}node[N + 5];
void Rever(int x)
{
swap(node[x].Son[0], node[x].Son[1]);
node[x].Rev ^= 1;
}
void PushUp(int x)
{
node[x].Sum = node[x].Val ^ node[node[x].Son[0]].Sum ^ node[node[x].Son[1]].Sum;
}
void PushDown(int x)
{
if(node[x].Rev)
{
Rever(node[x].Son[0]);
Rever(node[x].Son[1]);
node[x].Rev = 0;
}
}
bool Which(int x)
{
return node[node[x].Father].Son[1] == x;
}
void Connect(int x,int y,int d)
{
node[node[x].Father = y].Son[d] =x;
}
bool IsRoot(int x) // 是否是Splay中的根
{
return node[node[x].Father].Son[0] ^ x && node[node[x].Father].Son[1] ^ x;
}
void MakeRoot(int x)
{
Access(x),Splay(x),Rever(x);
}
int FindRoot(int x) // 找到x的原树中的根节点
{
Access(x), Splay(x); // 先将x与原树的根相连,然后转到原树根的位置,由于中序遍历最左的儿子即使根节点(左儿子层数是第一层的)
while(node[x].Son[0]) PushDown(x), x = node[x].Son[0];
Splay(x);
return x;
}
void Split(int x,int y)
{
MakeRoot(x),Access(y),Splay(y);
}
void Rotate(int x)
{
int fa = node[x].Father, pa = node[fa].Father, d = Which(x);
if(!IsRoot(fa)) node[pa].Son[Which(fa)] = x;
node[x].Father = pa;
Connect(node[x].Son[d^1], fa, d);
Connect(fa, x, d^1);
PushUp(fa);
PushUp(x);
}
void Splay(int x)
{
int fa = x, Top = 0;
while(Stack[++Top] = fa, !IsRoot(fa)) fa = node[fa].Father;
while(Top) PushDown(Stack[Top]), --Top; // 由于需要从上往下下放标记,所以要用一个堆先处理下
while(!IsRoot(x))
{
fa = node[x].Father;
if(!IsRoot(fa))// ?
{
Rotate(Which(x) ^ Which(fa) ? x : fa);
}
Rotate(x);
}
}
void Access(int x) // 断掉x的右儿子(即x为Splay中最深点),然后将x通往原树根的路径打通
{
for(int son = 0; x; x = node[son = x].Father)
{
Splay(x), node[x].Son[1] = son, PushUp(x);
}
}
public:
void Init(int len, int *data)
{
for(int i = 1; i <= len; i++) node[i].Val = data[i];
}
void Link(int x,int y)
{
MakeRoot(x);
if(FindRoot(y) != x) node[x].Father = y;
}
void Cut(int x,int y)
{
MakeRoot(x);
if(FindRoot(y) == x && node[y].Father == x && !node[y].Son[0])
{
node[y].Father = node[x].Son[1] = 0;
PushUp(x);
}
}
void Updata(int x,int v)
{
Splay(x);
node[x].Val = v;
}
int Query(int x,int y)
{
Split(x, y);
return node[y].Sum;
}
}LCT;
int a[N];
int main()
{
int T, n;
scanf("%d%d", &n, &T);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
LCT.Init(n, a);
while(T--)
{
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
switch(op)
{
case 0:printf("%d\n", LCT.Query(x,y));break;
case 1:LCT.Link(x, y);break;
case 2:LCT.Cut(x, y);break;
case 3:LCT.Updata(x, y);break;
}
}
return 0;
}