Splay的一些操作

Posted idqi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Splay的一些操作相关的知识,希望对你有一定的参考价值。

Splay : 十分happy的数据结构(过于灵活)

  推荐:https://blog.csdn.net/Clove_unique/article/details/50630280

 简单的定义:

    fa[x]为x的父亲,son[x][0/1]为x的左右儿子

 简单的操作

    get(x):查找x为父亲的哪一个儿子

    

int get(int x) {return son[fa[x]][1]==x;}

    

    rotate(x):将x旋转到父亲

 

void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=get(x);
        if (z) son[z][get(y)]=x;fa[x]=z;
        son[y][k]=son[x][k^1];
        if(son[y][k]) fa[son[y][k]]=y;
        son[x][k^1]=y;fa[y]=x;update(y);update(x);
    }

 

    Splay(x,goal):将x旋转到goal的儿子

 

void Splay(int x,int goal,int k)
    {
        while(fa[x]!=goal)
        {
            int y=fa[x],z=fa[y];
            if(z!=goal) rotate(get(y)==get(x)?y:x);
            rotate(x);
        }
        if(goal==0) rt[k]=x; 
    }

 

    Splay的任何旋转操作不影响这个树的中序遍历

    因此可以维护一个数组:

      对于每一个节点为 size 表示整个子树的和

      数组的下标   ->  树上排名   ->  中序遍历的位置

      那么直接可以通过互换一个节点左右儿子,改变名次

    Splay之间的互相插入

      遍历一遍 + 插入

      清空x
    

void earse(int x) {fa[x]=son[x][0]=son[x][1]=num[x]=tol[x]=0;}

      插入x到rt[k]的Splay

void inst(int y,int k)
    {
        int x=rt[k],f=0;
        while(x)
        {
            if(vi[x]==vi[y]) 
            {
                num[x]=max(num[x],num[y]);
                tol[x]=max(tol[x],num[x]);
                earse(y);return ;
            }
            f=x;x=son[x][vi[y]>vi[x]];
        }
        fa[y]=f;son[f][vi[y]>vi[f]]=y;
        tol[y]=num[y];update(f);Splay(y,0,k);
    }

    遍历

void merge(int x,int a) // x -> a
    {
        if(!x) return ;
        merge(son[x][0],a);merge(son[x][1],a);
        son[x][0]=son[x][1]=0;inst(x,a);
    }

 汇总:

  

int rt[N];
struct tree 
{
    int son[N][2],vi[N],fa[N],num[N],tol[N],tot;
    void clear() 
    {
        memset(fa,0,sizeof(fa));
        memset(vi,0,sizeof(vi));
        memset(son,0,sizeof(son));
        memset(num,0,sizeof(num));
        memset(tol,0,sizeof(tol));
    }
    int get(int x) {return son[fa[x]][1]==x;}
    void update(int x){if(x) tol[x]=max(num[x],max(tol[son[x][0]],tol[son[x][1]]));}
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=get(x);
        if (z) son[z][get(y)]=x;fa[x]=z;
        son[y][k]=son[x][k^1];
        if(son[y][k]) fa[son[y][k]]=y;
        son[x][k^1]=y;fa[y]=x;update(y);update(x);
    }
    void Splay(int x,int goal,int k)
    {
        while(fa[x]!=goal)
        {
            int y=fa[x],z=fa[y];
            if(z!=goal) rotate(get(y)==get(x)?y:x);
            rotate(x);
        }
        if(goal==0) rt[k]=x; 
    }
    void ins(int d,int fs,int k)
    {
        int x=rt[k],f=0;
        if(!x) {++tot;vi[tot]=d;num[tot]=tol[tot]=fs;Splay(tot,0,k);return ;}
        while(x)
        {
            if(vi[x]==d) {num[x]=max(num[x],fs);tol[x]=max(tol[x],fs);return ;}
            f=x;x=son[x][d>vi[x]];
        }
        ++tot;fa[tot]=f;son[f][d>vi[f]]=tot;vi[tot]=d;
        num[tot]=tol[tot]=fs;update(f);Splay(tot,0,k);
    }
    void earse(int x) {fa[x]=son[x][0]=son[x][1]=num[x]=tol[x]=0;}
    void inst(int y,int k)
    {
        int x=rt[k],f=0;
        while(x)
        {
            if(vi[x]==vi[y]) 
            {
                num[x]=max(num[x],num[y]);
                tol[x]=max(tol[x],num[x]);
                earse(y);return ;
            }
            f=x;x=son[x][vi[y]>vi[x]];
        }
        fa[y]=f;son[f][vi[y]>vi[f]]=y;
        tol[y]=num[y];update(f);Splay(y,0,k);
    }
    int find(int d,int k)
    {
        int x=rt[k],up=0;
        while(x)
        {
            if(vi[x]<d) up=x;
            x=son[x][d>vi[x]];
        }
        return up;
    }
    void merge(int x,int a) // x -> a
    {
        if(!x) return ;
        merge(son[x][0],a);merge(son[x][1],a);
        son[x][0]=son[x][1]=0;inst(x,a);
    }
} T;

 


以上是关于Splay的一些操作的主要内容,如果未能解决你的问题,请参考以下文章

Splay普及版

splay总结

splay

bzoj2733 永无乡 splay树的启发式合并

[转]Splay算法

蒟蒻的splay