20190720

T1普通平衡树:

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入xx
  2. 删除xx数(若有多个相同的数,因只删除一个)
  3. 查询xx数的排名(排名定义为比当前数小的数的个数+1+1。若有多个相同的数,因输出最小的排名)
  4. 查询排名为xx的数
  5. 求xx的前驱(前驱定义为小于xx,且最大的数)
  6. 求xx的后继(后继定义为大于xx,且最小的数)

输入输出格式

输入格式:
 

第一行为nn,表示操作的个数,下面nn行每行有两个数optoptxxoptopt表示操作的序号( 1 \leq opt \leq 61≤opt≤6 )

输出格式:
 

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

输入输出样例

输入样例#1: 复制

10

1 106465

4 1

1 317721

1 460929

1 644985

1 84185

1 89851

6 81968

1 492737

5 493598

输出样例#1: 复制

106465

84185

492737

说明

时空限制:1000ms,128M

1.n的数据范围: n \leq 100000n≤100000

2.每个数的数据范围: [-{10}^7, {10}^7][−107,107]

来源:Tyvj1728 原名:普通平衡树

在此鸣谢

#include<bits/stdc++.h>

using namespace std;

const int SIZE=100010;

struct treap{

         int l,r,val,dat,cnt,size;

}a[SIZE];

int tot,root,n,INF=0x7fffffff;

inline int read(){

         int k=0,f=1;

         char c=getchar();

         for(;!isdigit(c);c=getchar())

           if(c=='-')

             f=-1;

         for(;isdigit(c);c=getchar())

           k=k*10+c-'0';

         return k*f;

}

inline int New(int val){

         a[++tot].val=val;

         a[tot].dat=rand();

         a[tot].cnt=a[tot].size=1;

         return tot;

}

inline void Update(int p){

         a[p].size=a[a[p].l].size+a[a[p].r].size+a[p].cnt;

}

inline void Build(){

         New(-INF),New(INF);

         root=1;

         a[1].r=2;

         Update(root);

}

inline int GetRankByVal(int p,int val){

         if(!p)

           return 0;

           if(val==a[p].val)

             return a[a[p].l].size+1;

         if(val<a[p].val)

           return GetRankByVal(a[p].l,val);

         return GetRankByVal(a[p].r,val)+a[a[p].l].size+a[p].cnt;

}

inline int GetValByRank(int p,int rank){

         if(!p)

           return INF;

         if(a[a[p].l].size>=rank)

           return GetValByRank(a[p].l,rank);

         if(a[a[p].l].size+a[p].cnt>=rank)

           return a[p].val;

         return GetValByRank(a[p].r,rank-a[a[p].l].size-a[p].cnt);

}

inline void zig(int &p){

         int q=a[p].l;

         a[p].l=a[q].r;

         a[q].r=p;

         p=q;

         Update(a[p].r);

         Update(p);

}

inline void zag(int &p){

         int q=a[p].r;

         a[p].r=a[q].l;

         a[q].l=p;

         p=q;

         Update(a[p].l);

         Update(p);

}

inline void Insert(int &p,int val){

         if(!p){

                   p=New(val);

                   return;

         }

         if(val==a[p].val){

                   a[p].cnt++,Update(p);

                   return;

         }

         if(val<a[p].val){

                   Insert(a[p].l,val);

                   if(a[p].dat<a[a[p].l].dat)

                     zig(p);

         }

         if(val>a[p].val){

                   Insert(a[p].r,val);

                   if(a[p].dat<a[a[p].r].dat)

                     zag(p);

         }

         Update(p);

         return;

}

inline int GetPre(int val){

         int ans=1;

         int p=root;

         while(p){

                   if(val==a[p].val){

                            if(a[p].l>0){

                                      p=a[p].l;

                                     while(a[p].r>0)

                                       p=a[p].r;

                                     ans=p;

                            }

                            break;

                   }

                   if(a[p].val<val&&a[p].val>a[ans].val)

                     ans=p;

                   p=val<a[p].val?a[p].l:a[p].r;

         }

         return a[ans].val;

}

inline int GetNext(int val){

         int ans=2;

         int p=root;

         while(p){

                   if(val==a[p].val){

                            if(a[p].r>0){

                                     p=a[p].r;

                                     while(a[p].l>0)

                                       p=a[p].l;

                                     ans=p;

                            }

                            break;

                   }

                   if(a[p].val>val&&a[p].val<a[ans].val)

                     ans=p;

                   p=val<a[p].val?a[p].l:a[p].r;

         }

         return a[ans].val;

}

inline void Remove(int &p,int val){

         if(!p)

           return;

         if(val==a[p].val){

                   if(a[p].cnt>1){

                            a[p].cnt--;

                            Update(p);

                            return;

                   }

                   if(a[p].l||a[p].r){

                            if(a[p].r==0||a[a[p].l].dat>a[a[p].r].dat)

                              zig(p),Remove(a[p].r,val);

                            else

                              zag(p),Remove(a[p].l,val);

                            Update(p);

                   }

                   else 

                     p=0;

                   return;

         }

         val<a[p].val?Remove(a[p].l,val):Remove(a[p].r,val);

         Update(p);

}

int main(){

         Build();

         n=read();

         while(n--){

                   int opt,x;

                   opt=read(),x=read();

                   switch(opt){

                            case 1:

                                     Insert(root,x);

                                     break;

                            case 2:

                                     Remove(root,x);

                                     break;

                            case 3:

                                     cout<<GetRankByVal(root,x)-1<<endl;

                                     break;

                            case 4:

                                     cout<<GetValByRank(root,x+1)<<endl;

                                     break;

                            case 5:

                                     cout<<GetPre(x)<<endl;

                                     break;

                            case 6:

                                     cout<<GetNext(x)<<endl;

                                     break;

                   }

         }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值