3224: Tyvj 1728 普通平衡树 P3369 【模板】普通平衡树(Treap/SBT)Treap

Description

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

Input

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

Output

对于操作3,4,5,6每行输出一个数,表示对应答案

Sample Input

10

1 106465

4 1

1 317721

1 460929

1 644985

1 84185

1 89851

6 81968

1 492737

5 493598

Sample Output

106465

84185

492737

HINT

1.n的数据范围:n<=100000

2.每个数的数据范围:[-2e9,2e9]
Source

平衡树

今日新学一数据结构曰:treap,其原理就是当数据随机输入时,二叉平衡树的均摊复杂度是(logn)的,所以就有了以下操作,我们给每个树节点都随机附一个fix值,按照fix建立小根堆,同时满足二叉搜索树的性质,每次插入时先将其插到二叉树的位置,然后rand一个fix后调整:如果他比他爸爸fix小就rotate他。

每次删除时可作以下判断:如果说他的儿子不满,就把他的儿子来替换他(没有就直接删了)否则比较两个儿子的fix值把fix值小的旋上来,一直旋直到他的儿子不满直接操作。

今天因为不能够直接splay,还学了对非根节点求前驱、后缀、求他的排名的操作,得好好看。

#include<bits/stdc++.h>
using namespace std;
#define N 2000001
int ch[N][2],val[N],fix[N],fa[N],S[N],num[N];
int sz,n,opt,k,root;
void pushup(int x){S[0]=0;S[x]=S[ch[x][1]]+S[ch[x][0]]+num[x];return;}
bool gets(int x)
{
    return (ch[fa[x]][1]==x);
}
int find(int x)
{
    int p=root;
    while(val[p]!=x)
    {
        if(val[p]<x) {if(ch[p][1]) p=ch[p][1];else return p;}
        else{if(ch[p][0]) p=ch[p][0];else return p;}
    }
    return p;
}
void rotate(int x)
{
    if(!x) return;bool d=gets(x);
    int F=fa[x];int GF=fa[F];
    if(GF) ch[GF][gets(F)]=x;
    fa[x]=GF;fa[F]=x;fa[ch[x][!d]]=F;ch[F][d]=ch[x][!d];ch[x][!d]=F;
    pushup(F);pushup(x);
    if(fa[x]==0) root=x;
}
void change(int no)
{while(fa[no]&&fix[no]<fix[fa[no]]) rotate(no); }
void insert(int x)
{
    if(!root){root=++sz;val[sz]=x;fix[sz]=rand();fa[sz]=0;num[sz]=1;pushup(sz);return;}
    int kk=find(x);
    if(val[kk]!=x)
    {
        fix[++sz]=rand();val[sz]=x;fa[sz]=kk;S[sz]=1;num[sz]=1;
        if(x>val[kk]){ch[kk][1]=sz;}else ch[kk][0]=sz;
        for(int i=sz;i;i=fa[i])pushup(i);
        change(sz);
    }
    else
    {
        num[kk]++;for(int i=kk;i;i=fa[i])pushup(i);
    }
}
int getn(int no)
{
    return fix[ch[no][1]]<=fix[ch[no][0]];
}
void del(int x)
{
    int no=find(x);
    num[no]--;
    for(int i=no;i;i=fa[i]) pushup(i);//必要的话 
    if(num[no]==0)
    {
        while(ch[no][1]*ch[no][0])
        {
            int ll=getn(no);
            rotate(ch[no][ll]);
        }
        int tt=ch[no][1]+ch[no][0];
        ch[fa[no]][gets(no)]=tt;fa[tt]=fa[no];fa[no]=0;
        if(fa[tt]==0) root=tt;
        for(int i=tt;i;i=fa[i])pushup(i);
    }
    return;
}
int qrank(int x,int p)
{
    if(p==0) return 0;
    if(val[p]==x) return S[ch[p][0]]+1;
    if(val[p]>x) return qrank(x,ch[p][0]);
    return S[ch[p][0]]+num[p]+qrank(x,ch[p][1]);
}
int element(int k)
{
    int r=root;
    if(k>S[root]) return 0;
    while(1)
    {
        if(S[ch[r][0]]<k&&S[ch[r][0]]+num[r]>=k) return val[r];
        if(S[ch[r][0]]>=k) r=ch[r][0];
        else if(S[ch[r][1]]) {k-=num[r]+S[ch[r][0]];r=ch[r][1];}
    }
}
int succ(int x){int p=root;int ans=0;while(p){if(val[p]<x) ans=max(ans,val[p]),p=ch[p][1];else p=ch[p][0];}return ans;}
int pred(int x){int p=root;int ans=2e9+1e8;while(p){if(val[p]>x) ans=min(ans,val[p]),p=ch[p][0];else p=ch[p][1];}return ans;}
int main()
{
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d%d",&opt,&k);
        if(opt==1) insert(k);
        if(opt==2) del(k);
        if(opt==3) {printf("%d\n",qrank(k,root));}
        if(opt==4) {printf("%d\n",element(k));}
        if(opt==5) {insert(k);printf("%d\n",succ(k));del(k);}
        if(opt==6) {insert(k);printf("%d\n",pred(k));del(k);}
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值