BZOJ3224 普通平衡树(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.每个数的数据范围:[-1e7,1e7]


【代码】

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define INF 20000000
struct Node
{
    Node* ch[2];
    int v,s,r;
    int cmp_v(int x) const
    {
        if(x==v) return -1;
        if(x<v) return 0;
        if(x>v) return 1;
    }
    int cmp_s(int x) const
    {
        if(x==ch[0]->s+1) return -1;
        if(x<=ch[0]->s) return 0;
        if(x>ch[0]->s+1) return 1;
    }
};
Node *root,*null,*t;
int min(int a,int b)
{
    if(a<b) return a;
    return b;
}
int max(int a,int b)
{
    if(a>b) return a;
    return b;
}
void init()
{
    null=new Node();
    null->ch[0]=null->ch[1]=NULL;
    null->v=null->s=null->r=0;
    root=null;
}
void gets(Node* o)
{
    o->s = o->ch[0]->s + o->ch[1]->s + 1;
}
void xz(Node* &o,int d)
{
    Node* k=o->ch[d^1];
    o->ch[d^1]=k->ch[d];
    k->ch[d]=o;
    gets(o);
    gets(k);
    o=k;
}
void tj(Node* &o,int x)
{
    int d=o->cmp_v(x);
    if(o==null)
    {
        o=new Node();
        o->ch[0]=o->ch[1]=null;
        o->v=x;
        o->s=1;
        o->r=rand();
        return;
    }
    o->s++;
    if(d!=1) d=0;
    tj(o->ch[d],x);
    if( o->ch[d]->r > o->r ) xz(o,d^1);
}
void sc(Node* &o,int x)
{
    int d=o->cmp_v(x);
    if(d!=-1)
    {
        o->s--;
        sc(o->ch[d],x);
        return;
    }
    if(o->ch[0]==null) o=o->ch[1];
    else
    {
        if(o->ch[1]==null) o=o->ch[0];
        else
        {
            if( o->ch[0]->r > o->ch[1]->r) d=0;
            else d=1;
            xz(o,d^1);
            o->s--;
            sc(o->ch[d^1],x);
        }
    }
}
int getrank(Node* &o,int x)
{
    int d=o->cmp_v(x);
    if(o==null) return 1;
    if(d==1) return o->ch[0]->s+1+getrank(o->ch[1],x);
    return getrank(o->ch[0],x);
}
int getnum(Node* &o,int x)
{
    int d=o->cmp_s(x);
    if(d==-1) return o->v;
    if(d==1) x = x - o->ch[0]->s - 1;
    return getnum(o->ch[d],x);
}
int last(Node* &o,int x)
{
    int d=o->cmp_v(x);
    if(o==null) return -INF;
    if(d!=1) return last(o->ch[0],x);
    return max(o->v,last(o->ch[1],x));
}
int next(Node* &o,int x)
{
    int d=o->cmp_v(x);
    if(o==null) return INF;
    if(d!=0) return next(o->ch[1],x);
    return min(o->v,next(o->ch[0],x));
}
int main()
{
    int n,i,opt,x;
    scanf("%d",&n);
    init();
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&opt,&x);
        if(opt==1) tj(root,x);
        if(opt==2) sc(root,x);
        if(opt==3) printf("%d\n",getrank(root,x));
        if(opt==4) printf("%d\n",getnum(root,x));
        if(opt==5) printf("%d\n",last(root,x));
        if(opt==6) printf("%d\n",next(root,x));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值