平衡树之splay BZOJ3224 普通平衡树

3224: Tyvj 1728 普通平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 12204  Solved: 5199
[Submit][Status][Discuss]

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

平衡树

 

  1 /*f[i]表示i的父结点
  2 ch[i][0]表示i的左儿子
  3 ch[i][1]表示i的右儿子
  4 key[i]表示i的关键字(即结点i代表的那个数字)
  5 cnt[i]表示i结点的关键字出现的次数(相当于权值)
  6 size[i]表示包括i的这个子树的大小
  7 sz为整棵树的大小
  8 root为整棵树的根编号 
  9 */
 10 //借用某神犇的话 没事就多转转 
 11 #include<iostream>
 12 #include<cstdio>
 13 #include<cstring>
 14 #include<algorithm>
 15 using namespace std;
 16  
 17 const int maxn=100010;
 18 int f[maxn],ch[maxn][2],key[maxn],cnt[maxn],size[maxn],sz,root;
 19 int n,opt,num;
 20  
 21 void clean(int x){//清空 
 22     ch[x][0]=ch[x][1]=f[x]=cnt[x]=key[x]=size[x]=0;
 23 }
 24  
 25 int get(int x){//判断当前点是左还是右 
 26     return ch[f[x]][1]==x;//??????
 27 }
 28  
 29 void update(int x){//更新size值 
 30     if(x){
 31         size[x]=cnt[x];
 32         if(ch[x][0]) size[x]+=size[ch[x][0]];
 33         if(ch[x][1]) size[x]+=size[ch[x][1]];
 34     }
 35     return;
 36 }
 37  
 38 void rotate(int x){
 39     int old=f[x];
 40     int oldf=f[old];
 41     int which=get(x);
 42     ch[old][which]=ch[x][which^1];
 43     f[ch[old][which]]=old;
 44     f[old]=x;
 45     ch[x][which^1]=old;
 46     f[x]=oldf;
 47     if(oldf) ch[oldf][ch[oldf][1]==old]=x;
 48     update(old);
 49     update(x); 
 50 }
 51  
 52 void splay(int x){ 
 53     for(int fa;fa=f[x];rotate(x))
 54         if(f[fa]) rotate((get(x)==get(fa)?fa:x));
 55     root=x;
 56 }
 57  
 58 int find(int v){//查询某数的排名 
 59     int ans=0;
 60     int now=root;
 61     while(1){
 62         if(v<key[now]){
 63             now=ch[now][0];
 64         }
 65         else{
 66             ans+=(ch[now][0]?size[ch[now][0]]:0);
 67             if(v==key[now]){
 68                 splay(now);
 69                 return ans+1;
 70             }
 71             ans+=cnt[now];
 72             now=ch[now][1];
 73         }
 74     }
 75 }
 76  
 77 int findx(int x){//查找排名为x的数 
 78     int now=root;
 79     while(1){
 80         if(ch[now][0]&&x<=size[ch[now][0]]) now=ch[now][0];
 81         else{
 82             int temp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
 83             if(x<=temp) return key[now];
 84             x-=temp;
 85             now=ch[now][1];
 86         }
 87     }
 88 }
 89  
 90 int pre(){
 91     int now=ch[root][0];
 92     while(ch[now][1]) now=ch[now][1];
 93     return now;
 94 }
 95  
 96 int next(){
 97     int now=ch[root][1];
 98     while(ch[now][0]) now=ch[now][0];
 99     return now; 
100 }
101  
102 void del(int x){
103     int whatever=find(x);
104     if(cnt[root]>1){
105         cnt[root]--;
106         return;
107     }
108     if(!ch[root][0]&&!ch[root][1]){
109         clean(root);
110         root=0;
111         return;
112     }
113     if(!ch[root][0]){
114         int oldroot=root;
115         root=ch[root][1];
116         f[root]=0;
117         clean(oldroot);
118         return;
119     }
120     else if(!ch[root][1]){
121         int oldroot=root;
122         root=ch[root][0];
123         f[root]=0;
124         clean(oldroot);
125         return;
126     }
127     int leftbig=pre();
128     int oldroot=root;
129     splay(leftbig);
130     f[ch[oldroot][1]]=root;
131     ch[root][1]=ch[oldroot][1];
132     clean(oldroot);
133     update(root);
134     return;
135 }
136  
137 void insert(int v){
138     if(!root){
139         sz++;
140         ch[sz][0]=ch[sz][1]=f[sz]=0;
141         key[sz]=v;
142         cnt[sz]=1;
143         size[sz]=1;
144         root=sz;
145         return;
146     }
147     int now=root;
148     int fa=0;
149     while(1){
150         if(key[now]==v){
151             cnt[now]++;
152             update(fa);
153             splay(now);
154             break;
155         }
156         fa=now;
157         now=ch[now][key[now]<v];//??????
158         if(now==0){
159             sz++;
160             ch[sz][0]=ch[sz][1]=0;
161             f[sz]=fa;
162             key[sz]=v;
163             cnt[sz]=1;
164             ch[fa][key[fa]<v]=sz;
165             update(fa);
166             splay(sz);
167             break;
168         }
169     }
170     return;
171 } 
172  
173 int main(){
174     scanf("%d",&n);
175     for(int i=1;i<=n;i++){
176         scanf("%d%d",&opt,&num);
177         if(opt==1) insert(num);
178         if(opt==2) del(num);
179         if(opt==3) printf("%d\n",find(num));
180         if(opt==4) printf("%d\n",findx(num));
181         if(opt==5){
182             insert(num);
183             printf("%d\n",key[pre()]);
184             del(num);
185         } 
186         if(opt==6){
187             insert(num);
188             printf("%d\n",key[next()]);
189             del(num);
190         }
191     }
192     return 0;
193 }

 

 

存作模板

转载于:https://www.cnblogs.com/sdfzxh/p/6761669.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值