Balanced tree learning (2) - Splay

Splay is a balanced tree, its code complexity and time complexity are slightly weaker than Treap, but because it can support interval operations, it still has many uses in actual combat.
Let's first take a look at the definition and basic ideas of Splay.

A Splay Tree, also known as a split tree, can perform insertion, search, and deletion operations in O(log n). General operations on stretch trees are based on stretch operations: suppose you want to perform a series of search operations on a binary search tree, in order to make the overall search time smaller, those entries that are frequently searched should always be located close to the root of the tree. s position. So I thought of designing a simple method to reconstruct the tree after each search, and move the searched item to a place closer to the root of the tree. The stretch tree came into being. A splay tree is a self-adjusting form of binary search tree that moves the node to the root through a series of rotations along the path from a node to the root.
Its advantage is that there is no need to record redundant information for balancing the tree.

Ps: The Splay we introduced is a double spin operation Splay.


Array definition:
struct node{
    int fa,siz,ct,val,son[2];
}T[MAXN];
//fa记录父亲节点,siz记录子树大小,val记录当前节点值,ct表示与当
//前节点值相同的点个数,son[2]记录其左儿子和右儿子。

Pre-operation:

1.clear: clear the data in point k

void clear(int k){
    T[k].siz=T[k].ct=T[k].fa=T[k].val=T[k].son[0]=T[k].son[1]=0;
} 

2.up: Count the subtree size of k

void up(int k){
    T[k].siz=T[L].siz+T[R].siz+T[k].ct;
} 

3. get: Query whether k is the left son or the right son of the father

int get(int k){
    return T[T[k].fa].son[1]==k;
}

Rotation:

For Splay, the most important thing is rotate and splay stretch operation.
For the rotate operation, we can analogize the rotation of Treap.

void rotate(int &k){
    int fa=T[k].fa,gran=T[fa].fa;
    int d1=get(k),d2=get(fa);
    T[T[k].son[d1^1]].fa=fa;
    T[fa].son[d1]=T[k].son[d1^1];T[k].son[d1^1]=fa;
    T[k].fa=gran;T[fa].fa=k;
    if(gran) T[gran].son[d2]=k;;
    up(fa);up(k);
}

The splay operation is an upgraded version of Rotate, which rotates the child node to the root to maintain the complexity of Splay.
For each splay operation, we rotate it to the root node. For the stretch operation of Splay, we need to discuss:
1. When there is a root node in the rotated point, the rotation can be performed directly.
write picture description here

2. When the point x is collinear with its father and grandfather, rotate the father of x first, then rotate x.
write picture description here
3. If x is not collinear with its father and grandfather, rotate x twice.

void splay(int k){
    for(int fa;fa=T[k].fa;rotate(k))
      if(T[fa].fa) rotate(get(fa)==get(k)?fa:k);
    root=k; 
}

delete:

The deletion operation needs to be discussed. If there are more than one value x, the size and ct of the node k where x is located can be directly reduced by 1. If this is not the case, we continue to discuss, if k has no son, just clear node k directly. If k has only one son, just connect its son. If k has two sons, connect its predecessor to its father, and then connect k's right son to its predecessor, thus deleting k nodes.

int find(int k,int val){   //先求出要删除点的位置,并进行splay伸展
    if(!k) return 0;
    if(val==T[k].val){
        splay(k);return k;
    }
    return find(T[k].son[val>T[k].val],val);
}
void delet(int x){
    int pl=find(root,x);
    if(!pl) return;
    if(T[root].ct>1){
        T[root].ct--,T[root].siz--;return;
    }
    if(!T[root].son[1]&&!T[root].son[0]){
        clear(root),root=0;return;
    }
    if(!T[root].son[1]||!T[root].son[0]){
        int rt=root;
        root=T[root].son[0]+T[root].son[1];
        T[root].fa=0;clear(rt);return;
    }
    int rt=root;
    pre(root,x);splay(dist);
    T[T[rt].son[1]].fa=root;T[root].son[1]=T[rt].son[1];
    clear(rt);up(root);T[root].fa=0;
    return;
}

Other operations:

Such as obtaining the predecessor, successor and other operations, similar to Treap

void insert(int &k,int val,int pos){   //插入操作
    if(!k){
        k=++sz;
        T[k].ct=T[k].siz=1;T[k].fa=pos;T[k].son[0]=T[k].son[1]=0;T[k].val=val;
        dist=k;return; 
    }
    if(val==T[k].val){
        dist=k;T[k].siz++;T[k].ct++;return;
    }
    if(val<T[k].val) insert(T[k].son[0],val,k);
    if(val>T[k].val) insert(T[k].son[1],val,k);
    up(k);
}
int searchRANK(int k,int x){  //查询x排在第几
    if(!k) return 0;
    if(x<T[k].val) return searchRANK(L,x);
    if(x==T[k].val) return T[L].siz+1; 
    if(x>T[k].val) return T[L].siz+T[k].ct+searchRANK(R,x);
}
int searchPLACE(int k,int x){    //查询排在x的数是几
    if(!k) return 0;
    if(x<=T[L].siz) return searchPLACE(L,x);
    x-=T[L].siz;
    if(x<=T[k].ct) return T[k].val;
    x-=T[k].ct;
    return searchPLACE(R,x);
}
void pre(int k,int val){   //前驱,dist记录位置
    if(!k) return;
    if(val<=T[k].val) pre(L,val);
    else dist=k,pre(R,val);
}
void ahe(int k,int val){   //后继
    if(!k) return;
    if(val>=T[k].val) ahe(R,val);
    else dist=k,ahe(L,val);
}

merge:

① When all the elements in S1 are smaller than S2 (for example, S1 and S2 are just split), you only need to stretch the largest point of S1 to the root, and then connect the edges.
② When the size of S1 and S2 is arbitrary, the heuristic is merged, and the smaller is moved to the larger.
Split: (with k as the limit, the left is less than or equal to k, and the right is greater than or equal to k)


BZOJ3224 Template:
#include<bits/stdc++.h>
#define L T[k].son[0]
#define R T[k].son[1]
#define MAXN 100005
using namespace std;
int read(){
    char c;int x=0,y=1;while(c=getchar(),(c<'0'||c>'9')&&c!='-');if(c=='-') y=-1;else x=c-'0';
    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x*y;
}
int root,dist,sz,n;
struct node{
    int fa,siz,ct,val,son[2];
}T[MAXN];
void clear(int k){
    T[k].siz=T[k].ct=T[k].fa=T[k].val=T[k].son[0]=T[k].son[1]=0;
} 
void up(int k){
    T[k].siz=T[L].siz+T[R].siz+T[k].ct;
} 
int get(int k){
    return T[T[k].fa].son[1]==k;
}
void rotate(int &k){
    int fa=T[k].fa,gran=T[fa].fa;
    int d1=get(k),d2=get(fa);
    T[T[k].son[d1^1]].fa=fa;
    T[fa].son[d1]=T[k].son[d1^1];T[k].son[d1^1]=fa;
    T[k].fa=gran;T[fa].fa=k;
    if(gran) T[gran].son[d2]=k;;
    up(fa);up(k);
}
void splay(int k){
    for(int fa;fa=T[k].fa;rotate(k))
      if(T[fa].fa) rotate(get(fa)==get(k)?fa:k);
    root=k; 
}
void insert(int &k,int val,int pos){
    if(!k){
        k=++sz;
        T[k].ct=T[k].siz=1;T[k].fa=pos;T[k].son[0]=T[k].son[1]=0;T[k].val=val;
        dist=k;return; 
    }
    if(val==T[k].val){
        dist=k;T[k].siz++;T[k].ct++;return;
    }
    if(val<T[k].val) insert(T[k].son[0],val,k);
    if(val>T[k].val) insert(T[k].son[1],val,k);
    up(k);
}
int searchRANK(int k,int x){
    if(!k) return 0;
    if(x<T[k].val) return searchRANK(L,x);
    if(x==T[k].val) return T[L].siz+1; 
    if(x>T[k].val) return T[L].siz+T[k].ct+searchRANK(R,x);
}
int searchPLACE(int k,int x){
    if(!k) return 0;
    if(x<=T[L].siz) return searchPLACE(L,x);
    x-=T[L].siz;
    if(x<=T[k].ct) return T[k].val;
    x-=T[k].ct;
    return searchPLACE(R,x);
}
void pre(int k,int val){
    if(!k) return;
    if(val<=T[k].val) pre(L,val);
    else dist=k,pre(R,val);
}
void ahe(int k,int val){
    if(!k) return;
    if(val>=T[k].val) ahe(R,val);
    else dist=k,ahe(L,val);
}
int find(int k,int val){
    if(!k) return 0;
    if(val==T[k].val){
        splay(k);return k;
    }
    return find(T[k].son[val>T[k].val],val);
}
void delet(int x){
    int pl=find(root,x);
    if(!pl) return;
    if(T[root].ct>1){
        T[root].ct--,T[root].siz--;return;
    }
    if(!T[root].son[1]&&!T[root].son[0]){
        clear(root),root=0;return;
    }
    if(!T[root].son[1]||!T[root].son[0]){
        int rt=root;
        root=T[root].son[0]+T[root].son[1];
        T[root].fa=0;clear(rt);return;
    }
    int rt=root;
    pre(root,x);splay(dist);
    T[T[rt].son[1]].fa=root;T[root].son[1]=T[rt].son[1];
    clear(rt);up(root);T[root].fa=0;
    return;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++){
        int x=read(),y=read();
        if(x==1) insert(root,y,0),splay(dist);
        if(x==2) delet(y);
        if(x==3) printf("%d\n",searchRANK(root,y));
        if(x==4) printf("%d\n",searchPLACE(root,y));
        if(x==5) dist=0,pre(root,y),printf("%d\n",T[dist].val);
        if(x==6) dist=0,ahe(root,y),printf("%d\n",T[dist].val); 
    }
    return 0;
}

Documentation: The picture is transferred from the blog ZigZagK, thanks to ZZK boss

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325613462&siteId=291194637