平衡树 fhqTreap

//Treap fhq版(不旋转) 
//所有操作依靠split()(分离)和merge()(合并)完成 
//可支持区间操作和可持久化 比普通Treap更通用 
//所有Treap中序遍历均为递增序列 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
using namespace std;
int n,cnt,size,root,x,y,z;
//x为小Treap的根节点 y为中Treap的根节点 z为大Treap的根节点 root为总Treap的根节点 
int son[100001][2],siz[100001],val[100001],rd[100001];
//左右儿子,子树大小+自己大小,点值,随机权值 
int new_node(int m)//建立新节点 
{
    siz[++size]=1;
    val[size]=m;
    rd[size]=rand();
    return size;
}
void update(int now)
{
    siz[now]=siz[son[now][0]]+siz[son[now][1]]+1;
}
void split(int now,int k,int &a,int &b)
{
    if(!now)
    {
        a=b=0;
        return;
    }
    if(val[now]<=k)
        a=now,split(son[now][1],k,son[now][1],b);
        //将此节点及其左子树接到小Treap上,并遍历此节点的右节点 
    else b=now,split(son[now][0],k,a,son[now][0]);
        //将此节点及其右子树接到大Treap上,并遍历此节点的左节点 
    update(now);
}
int merge(int a,int b)
{
    if(!a||!b)
        return a+b;
    if(rd[a]<rd[b])
    {
        son[a][1]=merge(son[a][1],b);
        //将小Treap节点及其左子树接在总Treap上,并遍历此节点的右节点 
        update(a);
        return a; 
    }
    else
    {
        son[b][0]=merge(a,son[b][0]);
        //将大Treap节点及其右子树接在总Treap上,并遍历此节点的左节点 
        update(b);
        return b;
    }
}
int k_th(int now,int k)
{
    while(1)
    {
        if(k<=siz[son[now][0]])
            now=son[now][0];
        else if(k==siz[son[now][0]]+1)
            return now;
        else
        {
            k-=siz[son[now][0]]+1;
            now=son[now][1];
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int u,k;
        scanf("%d%d",&u,&k);
        if(u==1)//插入 
        {
            split(root,k,x,z);//先分成两个Treap 此时k(若有)在小Treap中 
            root=merge(merge(x,new_node(k)),z);//重新合并 
        }
        if(u==2)//删除 
        {
            split(root,k,x,z);//先分成两个Treap 此时k在小Treap中 
            split(x,k-1,x,y);//再把小Treap分成两个Treap 此时k在中Treap中 且为中Treap根节点 
            y=merge(son[y][0],son[y][1]);//把中Treap根节点的两个子树合并 此时已删除k 
            root=merge(merge(x,y),z);//重新合并 
        }
        if(u==3)//查找权值为k的排名
        {
            split(root,k-1,x,z);//先分成两个Treap 此时小Treap中包含了所有小于k的数 
            printf("%d\n",siz[x]+1);//k的排名即为小于k的权值数目+1 
            root=merge(x,z);//重新合并 
        }
        if(u==4)//查找排名为k的权值 
            printf("%d\n",val[k_th(root,k)]);//直接输出 
        if(u==5)//求前驱 
        {
            split(root,k-1,x,z);//先分成两个Treap 此时k是大Treap中最小的数 
            printf("%d\n",val[k_th(x,siz[x])]);//前驱即为小Treap中最大的数 即最右节点 
            root=merge(x,z);//重新合并 
        }
        if(u==6)//求后继 
        {
            split(root,k,x,z);//先分成两个Treap 此时k是小Treap中最大的数 
            printf("%d\n",val[k_th(z,1)]);//后继即为大Treap中最小的数 即最左节点 
            root=merge(x,z);//重新合并 
        }
    }
    return 0;
}

 

posted @ 2018-07-08 18:41  radishえらい  阅读(832)  评论(0编辑  收藏  举报