平衡树 Treap

//平衡树 Treap
//维护一个堆使得随机权值小(大)的数始终在上方
//使用随机权值目的:防止出题人卡 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
struct uio{
    int l,r,siz,num,rd,tim;//左儿子,右儿子,子树大小+自己大小,点值,随机权值,出现次数 
}treap[100001];//此代码为小根堆 即随机权值小的在上方 
int n,size,ans,root;//size树的大小 
void update(int k)//更新 
{
    treap[k].siz=treap[treap[k].l].siz+treap[treap[k].r].siz+treap[k].tim;
}
void right(int &k)//右旋 
{
    int x=treap[k].l;
    treap[k].l=treap[x].r;
    treap[x].r=k;
    treap[x].siz=treap[k].siz;
    update(k);
    k=x;
}
void left(int &k)//左旋 
{
    int x=treap[k].r;
    treap[k].r=treap[x].l;
    treap[x].l=k;
    treap[x].siz=treap[k].siz;
    update(k);
    k=x;
} 
void insert(int &k,int x)
{
    if(k==0)//到达叶节点就开始插入
    {
        size++;
        k=size;
        treap[k].siz=1;
        treap[k].tim=1;
        treap[k].num=x;
        treap[k].rd=rand();
        return;
    }
    treap[k].siz++;//插入节点的每个父节点子树大小都加一 
    if(treap[k].num==x)//若已有此节点 
        treap[k].tim++;//出现次数加一 
    else
    {
        if(x>treap[k].num)//在右子树中
        {
            insert(treap[k].r,x);
            if(treap[treap[k].r].rd<treap[k].rd)//子节点随机数比父节点小
                left(k);//左旋 
        } 
        else//在右子树中 
        {
            insert(treap[k].l,x);
            if(treap[treap[k].l].rd<treap[k].rd)//子节点随机数比父节点小 
                right(k);//右旋 
        }
    }
}
void del(int &k,int x)
{
    if(k==0)//树中已无节点 
        return;
    if(treap[k].num==x)//找到了 
    {
        if(treap[k].tim>1)//出现次数大于一,直接删除即可 
        {
            treap[k].tim--;
            treap[k].siz--;
            return;
        }
        if(treap[k].l*treap[k].r==0)//左右子树有一棵为空
            k=treap[k].l+treap[k].r;//直接把非空子树接在原树上 
        else
        {
            if(treap[treap[k].l].rd<treap[treap[k].r].rd)//每次下沉时与随机权值小的交换 以确保小根堆性质不变 
                right(k),del(k,x);
            else left(k),del(k,x);
        }
    }
    else//没找到 
    {
        if(x>treap[k].num)//在右子树中 
        {
            treap[k].siz--;
            del(treap[k].r,x);
        }
        else//在左子树中 
        {
            treap[k].siz--;
            del(treap[k].l,x);
        }
    } 
}
int get_no(int k,int x)
{
    if(k==0)//树中没有节点 
        return 0;
    if(treap[k].num==x)//找到x 
        return treap[treap[k].l].siz+1;//结果为自己加左子树的大小 
    else if(x>treap[k].num)//在右子树 
        return treap[treap[k].l].siz+treap[k].tim+get_no(treap[k].r,x);//结果为递归回的结果加自己的大小加左子树的大小 
    else return get_no(treap[k].l,x);//在左子树  结果为递归回的结果 
}
int get_num(int k,int x)
{
    if(k==0)//树中没有节点 
        return 0;
    if(x<=treap[treap[k].l].siz)//在左子树中
        return get_num(treap[k].l,x);
    else if(x>(treap[treap[k].l].siz+treap[k].tim))//在右子树中
        return get_num(treap[k].r,x-treap[treap[k].l].siz-treap[k].tim);
    else return treap[k].num;//在这个点上
}
void pre(int k,int x)
{
    if(k==0)
        return;
    if(treap[k].num<x)//在右子树中
    {
        ans=k;
        pre(treap[k].r,x); 
    }
    else pre(treap[k].l,x);//在左子树中 
}
void nxt(int k,int x)
{
    if(k==0)
        return;
    if(treap[k].num>x)//在左子树中
    {
        ans=k;
        nxt(treap[k].l,x);
    }
    else nxt(treap[k].r,x);
} 
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        if(u==1)
            insert(root,v);
        if(u==2)
            del(root,v);
        if(u==3)
            printf("%d\n",get_no(root,v));
        if(u==4)
            printf("%d\n",get_num(root,v));
        if(u==5)
        {
            pre(root,v);
            printf("%d\n",treap[ans].num);
        }
        if(u==6)
        {
            nxt(root,v);
            printf("%d\n",treap[ans].num);
        }
    }
     return 0;
}

猜你喜欢

转载自www.cnblogs.com/water-radish/p/9280875.html