table of Contents
Tree data structure --LCT
Outline
LCT is a potent tree data structure, supports the following operations:
- Chain summation
- Most value chain
- Wind modification
- Modify Subtree
- Subtree summing
- In other root
- Disconnect the trees an edge
- Connecting two points, to ensure that the connection is still a tree.
basic concept
LCT tree is real chain split , i.e., all the sides are divided into real and imaginary side edge
Similar split the heavy chain, and even up to each point there will only be a solid strand to the child node, even to put the solid side is called the real son son
Solid side chain at some point the connection is called the real configuration of the chain, there is no common link between the real prone
Note that is not a real edge point (some of the leaf nodes) are also considered a no real edge real chain
Thus it must be used between the solid virtual edge chain link
To delete connected to dynamic operating side, so the use of splay to maintain a solid strand, a splay tree auxiliary LCT
Here splay depth by preorder strictly increasing
Since a maintenance splay, LCT hard edges are dynamic, can be varied
Core Operating
Access (x) : Let x to the root of all edges are solid side, and x is not real son
The recommended flash_hu blog, easy to understand
Say a little bit, each first current operation point to be connected to the root of the current splay splay, since the depth splay incremented by inorder traversal, real roots chain case right son must be connected before, need to be removed
So the point is connected to the right before the son of the current root on the line
Note that at this time some of the \ (fa, son, isroot \ ) information like change, you need to \ (the Push \) _ \ (up \)
void access(int x){
for(int y=0;x;y=x,x=fa[x]){ //y是之前的根,x是当前需要连的点
splay(x); ch[x][1]=y;
push_up(x);
}
}
Other operations
makeroot
In other root operation
After access (x) x is the deepest point
So, after splay (x), x is not necessarily in the right child splay tree, this time to flip an entire splay, the depth of all the points have been reversed on, x becomes minimum depth of a point, that is the root node
void pushr(int x){ swap(ch[x][0],ch[x][1]); r[x]^=1; } void makeroot(int x){ access(x); splay(x); pushr(x); }
findroot
Get where tree roots, can be used to determine connectivity (the same points where the tree has a unique between two points is the same root
int findroot(int x){ access(x);splay(x); while(c[x][0]) push_down(x),x=ch[x][0];//寻找深度最小的点,此处push_down是为了x到跟的标记放完,好判连通性 splay(x);//多多splay有益健康 return 0; }
split
Pulled into the path a splay
void spilt(int x,int y){ makeroot(x);access(y); splay(y); }
link
Even one side to ensure complete or even a tree
We do not guarantee the legitimate:
int link(int x,int y){ makeroot(x); if(findroot(y)==x) return 0; fa[x]=y; //把x作为y的儿子 return 1; }
To ensure that legitimate:
void link(int x,int y){ makeroot(x); fa[x]=y; }
Even here virtual edge side (easy to feel the real chain of the strike split
cut
Broken edge
To ensure that there is:
void cut(int x,int y){ split(x,y); fa[x]=ch[y][0]=0; }
It does not exist when this edge is what happens then?
A first x \ (makeroot \) to the root
x and y are not in communication ( \ (the findroot \) )
Splay the same side but not directly connected ( \ (F [Y] == X \) and \ (! C [Y] [0] \) )
(Where is considering other points, x after findroot to the root node, if a bit between x and y, y can only be in the path to the root of the left son or y)
int cut(int x,int y){ makeroot(x); if(findroot(y)!=x||fa[y]!=x||ch[y][0]) return 0; fa[y]=ch[x][1]=0; push_up(x); return 1; }
nroot
naiive operation, it is determined whether the current point is not the root splay
int nroot(int x){ return (ch[fa[x]][1]==x||ch[fa[x]][0]==x); }
splay particularity
Here splay marks must, from top to bottom place, which is to open a stack and then rotate the mark is done
Complete template
#include<bits/stdc++.h>
#define R register int
#define I inline void
#define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
#define lc c[x][0]
#define rc c[x][1]
using namespace std;
const int SZ=1<<19,N=3e5+9;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int in(){
G;while(*ip<'-')G;
R x=*ip&15;G;
while(*ip>'-'){x*=10;x+=*ip&15;G;}
return x;
}
int f[N],c[N][2],v[N],s[N],st[N];
bool r[N];
inline bool nroot(R x){//判断节点是否为一个Splay的根(与普通Splay的区别1)
return c[f[x]][0]==x||c[f[x]][1]==x;
}//原理很简单,如果连的是轻边,他的父亲的儿子里没有它
I pushup(R x){//上传信息
s[x]=s[lc]^s[rc]^v[x];
}
I pushr(R x){R t=lc;lc=rc;rc=t;r[x]^=1;}//翻转操作
I pushdown(R x){//判断并释放懒标记
if(r[x]){
if(lc)pushr(lc);
if(rc)pushr(rc);
r[x]=0;
}
}
I rotate(R x){//一次旋转
R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;//额外注意if(nroot(y))语句,此处不判断会引起致命错误(与普通Splay的区别2)
if(w)f[w]=y;f[y]=x;f[x]=z;
pushup(y);
}
I splay(R x){//只传了一个参数,因为所有操作的目标都是该Splay的根(与普通Splay的区别3)
R y=x,z=0;
st[++z]=y;//st为栈,暂存当前点到根的整条路径,pushdown时一定要从上往下放标记(与普通Splay的区别4)
while(nroot(y))st[++z]=y=f[y];
while(z)pushdown(st[z--]);
while(nroot(x)){
y=f[x];z=f[y];
if(nroot(y))
rotate((c[y][0]==x)^(c[z][0]==y)?x:y);
rotate(x);
}
pushup(x);
}
/*当然了,其实利用函数堆栈也很方便,代替上面的手工栈,就像这样
I pushall(R x){
if(nroot(x))pushall(f[x]);
pushdown(x);
}*/
I access(R x){//访问
for(R y=0;x;x=f[y=x])
splay(x),rc=y,pushup(x);
}
I makeroot(R x){//换根
access(x);splay(x);
pushr(x);
}
int findroot(R x){//找根(在真实的树中的)
access(x);splay(x);
while(lc)pushdown(x),x=lc;
splay(x);
return x;
}
I split(R x,R y){//提取路径
makeroot(x);
access(y);splay(y);
}
I link(R x,R y){//连边
makeroot(x);
if(findroot(y)!=x)f[x]=y;
}
I cut(R x,R y){//断边
makeroot(x);
if(findroot(y)==x&&f[y]==x&&!c[y][0]){
f[y]=c[x][1]=0;
pushup(x);
}
}
int main()
{
R n=in(),m=in();
for(R i=1;i<=n;++i)v[i]=in();
while(m--){
R type=in(),x=in(),y=in();
switch(type){
case 0:split(x,y);printf("%d\n",s[y]);break;
case 1:link(x,y);break;
case 2:cut(x,y);break;
case 3:splay(x);v[x]=y;//先把x转上去再改,不然会影响Splay信息的正确性
}
}
return 0;
}
Maybe later make up their own questions of LCT (goo
In the process of the creation of this article, reference is made to the following articles:
[flash_hu Gangster blog] [ https://www.cnblogs.com/flashhu/p/8324551.html ]
[Super-level data structure of the NOI --Link-cut-tree (dynamic tree) Learning small note] [ https://blog.csdn.net/qq_36551189/article/details/79152612 ]
VII Chengdu LCT courseware (a bit of it
Yang Zhe 2007 paper