Tree data structure --LCT

Tree data structure --LCT

Outline

LCT is a potent tree data structure, supports the following operations:

  1. Chain summation
  2. Most value chain
  3. Wind modification
  4. Modify Subtree
  5. Subtree summing
  6. In other root
  7. Disconnect the trees an edge
  8. 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

  1. 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);
    }
  2. 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;
    }
  3. split

    Pulled into the path a splay

    void spilt(int x,int y){
        makeroot(x);access(y);
        splay(y);
    }
  4. 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

  5. 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

    1. x and y are not in communication ( \ (the findroot \) )

    2. 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;
    }
  6. 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);
    }
  7. 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:

Guess you like

Origin www.cnblogs.com/lcyfrog/p/11391899.html
Recommended