Splay

来源:互联网 发布:淘宝客服接待人特别少 编辑:程序博客网 时间:2024/04/26 19:46

Splay

Splay是一种平衡树。
既然是一棵平衡树,那么我们一定要想办法让它保持平衡。
解决办法就是旋转,分为zig,zag,zig-zig,zag-zag,zig-zag,zag-zig。
核心:Splay操作,通过进行非常多次的Splay操作来保证所有操作的均摊复杂度为O(logn)。(我不会证明)

详细讲解(转载):
http://blog.csdn.net/clove_unique/article/details/50630280

Q:为什么旋转的时候要向上考虑两层?
A:可以动手画图试试,然后就会发现不考虑两层会出问题。
Q:怎么考虑啊?
A:x和y同为各自父亲的左孩子或者右孩子时,进行zag-zag或者zig-zig,否则zag-zig或者zig-zag。

例题 Luogu 3369

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)

解析

这就是模板啦

代码如下

#include<bits/stdc++.h>using namespace std;#define maxn 1000000#define INF 2147483647int n,fa[maxn],val[maxn],c[maxn][2],root,tot,siz[maxn],cnt[maxn];void Maintain(int x){    siz[x]=siz[c[x][0]]+siz[c[x][1]]+cnt[x];}void NewNode(int &x,int Fa,int key){    x=++tot;    fa[x]=Fa;    c[x][0]=c[x][1]=0;    val[x]=key;    siz[x]=cnt[x]=1;}void Rotate(int x,bool flag){    int y=fa[x];    c[y][!flag]=c[x][flag];    fa[c[x][flag]]=y;    if(fa[y]){        c[fa[y]][c[fa[y]][1]==y]=x;    }    fa[x]=fa[y];    c[x][flag]=y;    fa[y]=x;    Maintain(y);    Maintain(x);}void Splay(int x,int goal){    if(!x){        return;    }    int y;    while((y=fa[x])!=goal){        if(fa[y]==goal){            Rotate(x,c[y][0]==x);        }        else{            if((c[y][0]==x)==(c[fa[y]][0]==y)){                Rotate(y,c[fa[y]][0]==y);            }            else{                Rotate(x,c[y][0]==x);                y=fa[x];            }            Rotate(x,c[y][0]==x);        }    }    Maintain(x);    if(!goal){        root=x;    }}int Find(int key,int x=root){    while(c[x][val[x]<key]){        if(val[x]==key){            return x;        }        x=c[x][val[x]<key];    }    return x;}void Insert(int key){    if(!root){        NewNode(root,0,key);        return;    }    int x=Find(key);    if(val[x]==key){        ++cnt[x];        Splay(x,0);        return;    }    NewNode(c[x][val[x]<key],x,key);    Splay(c[x][val[x]<key],0);}int Findmax(int x=root){    while(c[x][1]){        x=c[x][1];    }    return x;}int Findmin(int x=root){    while(c[x][0]){        x=c[x][0];    }    return x;}void Delete(int key){    int x=Find(key);    Splay(x,0);    if(val[x]==key){        --cnt[x];        if(!cnt[x]){            if(!c[x][0]&&!c[x][1]){                root=0;            }            else if(!c[x][0]||!c[x][1]){                fa[c[x][c[x][0]==0]]=0;                root=c[x][c[x][0]==0];            }            else{                int y=Findmax(c[x][0]);                Splay(y,root);                c[y][1]=c[root][1];                fa[c[root][1]]=y;                root=y;                fa[root]=0;                Maintain(root);            }        }        else{            Maintain(x);        }    }}int Rank(int key){    int x=Find(key);    Splay(x,0);    return siz[c[x][0]]+1;}int Kth(int K,int x=root){    while(1){        int Siz0=siz[c[x][0]];        if(K<=Siz0){            x=c[x][0];        }        else if(K<=Siz0+cnt[x]){            return val[x];        }        else{            K-=(Siz0+cnt[x]);            x=c[x][1];        }    }}int GetPre(int key){    int x=Find(key);    if(val[x]==key){        Splay(x,0);        return val[Findmax(c[x][0])];    }    while(val[x]>key&&fa[x]){        x=fa[x];    }    return val[x];}int GetNex(int key){    int x=Find(key);    if(val[x]==key){        Splay(x,0);        return val[Findmin(c[x][1])];    }    while(val[x]<key&&fa[x]){        x=fa[x];    }    return val[x];}int main(){    int op, x;    scanf("%d",&n);    for(int i=1;i<=n;i++){        scanf("%d%d",&op,&x);        if(op==1){            Insert(x);        }        else if(op==2){            Delete(x);        }        else if(op==3){            printf("%d\n",Rank(x));        }        else if(op==4){            printf("%d\n",Kth(x));        }        else if(op==5){            printf("%d\n",GetPre(x));        }        else{            printf("%d\n",GetNex(x));        }    }    return 0;}

另一道题 洛谷 3391

传送门:http://blog.csdn.net/vanillayi/article/details/78715357

原创粉丝点击