替罪羊树 普通平衡树

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]
  1 #include<bits/stdc++.h>
  2 using namespace std; 
  3 #define lc ch[x][0]  
  4 #define rc ch[x][1]   
  5 #define ff fa[x]  
  6 int const N=1000000+10;  
  7 int ch[N][2],v[N],tot[N],sz[N],trsz[N],whsz[N],fa[N],tf[N],sv[N],st[N];
  8 int len,n,root,ck[N],t,tt;  
  9 double alp=0.75;  
 10 multiset<int> s;  
 11 int kk(){
 12     if(t)  return ck[t--];  
 13     else return ++len;  
 14 }      
 15 int find(int val,int x){  
 16     if(val<v[x]  &&  lc) return find(val,lc);  
 17     if(val>v[x]  &&  rc) return find(val,rc);   
 18     return x;  
 19 }  
 20 void build(int val,int x,int f){
 21     lc=rc=tf[x]=0;  
 22     ff=f;  
 23     v[x]=val;  
 24     tot[x]=sz[x]=trsz[x]=whsz[x]=1;  
 25 }    
 26 void update(int x,int y,int z,int k){
 27     if(!x) return; 
 28     trsz[x]+=y;  
 29     sz[x]+=z;  
 30     whsz[x]+=k;  
 31     update(ff,y,z,k);  
 32 }  
 33 void dfs(int x){            
 34     if(!x) return;  
 35     dfs(lc);  
 36     if(!tf[x]) sv[++tt]=v[x],st[tt]=tot[x];  
 37     ck[++t]=x;   
 38     dfs(rc);  
 39 }  
 40 int readd(int l,int r,int f){
 41     if(l>r) return 0;  
 42     int mid=(l+r)/2;  
 43     int x=kk();   
 44     ff=f;  
 45     v[x]=sv[mid];  
 46     tot[x]=st[mid];  
 47     lc=readd(l,mid-1,x);  
 48     rc=readd(mid+1,r,x);  
 49     whsz[x]=st[mid]+whsz[lc]+whsz[rc];  
 50     sz[x]=trsz[x]=r-l+1; 
 51     tf[x]=0;
 52     return x;    
 53 }  
 54 void rebuild(int x){
 55     tt=0; 
 56     dfs(x);  
 57     if(x==root) root=readd(1,tt,0);  
 58     else {
 59         update(ff,0,-(sz[x]-trsz[x]),0);  
 60         if(ch[ff][0]==x) ch[ff][0]=readd(1,tt,ff);  
 61         else ch[ff][1]=readd(1,tt,ff);  
 62     } 
 63 }
 64 void find_rebuild(int x,int val){
 65     if(sz[lc]>sz[x]*alp ||  sz[rc]>sz[x]*alp || sz[x]-trsz[x]>sz[x]*0.3)   rebuild(x);  
 66     else if(val!=v[x])  find_rebuild(val<v[x]? lc: rc,val);  
 67 } 
 68 
 69 void add(int val){
 70     if(!root){
 71         build(val,root=kk(),0);  
 72         return ;  
 73     } 
 74     int x=find(val,root);  
 75     if(val==v[x]){
 76         tot[x]++;  
 77         if(tf[x]) tf[x]=0,update(x,1,0,1);  
 78         else update(x,0,0,1);  
 79     }
 80     else if(val<v[x]) build(val,lc=kk(),x),update(x,1,1,1);  
 81     else build(val,rc=kk(),x),update(x,1,1,1); 
 82     find_rebuild(root,val); 
 83 }  
 84 void del(int val){
 85     int x=find(val,root); 
 86     if(v[x]!=val) return;    
 87     tot[x]--;  
 88     if(!tot[x]) tf[x]=1,update(x,-1,0,-1);  
 89     else update(x,0,0,-1);  
 90     find_rebuild(x,val);  
 91 }  
 92 int rk(int val){
 93     int ret=0,x=root;  
 94     while (x){
 95         if(v[x]>val) x=lc;  
 96         else if(v[x]==val){
 97             ret+=whsz[lc]+1; return ret;
 98         }  
 99         else ret+=whsz[lc]+tot[x],x=rc; 
100     } 
101 }  
102 int nth(int k){
103     int x=root;  int num=0;  
104     while (1){
105         if(whsz[lc]>=k) x=lc;  
106         else  if(k>whsz[lc]+tot[x]) k-=whsz[lc]+tot[x],x=rc;  
107         else  return v[x];  
108     }  
109 } 
110 int pre(int k){
111     return *(--s.lower_bound(k));     
112 }  
113 int nxt(int k){
114     return *(s.upper_bound(k));  
115 }  
116 int main(){
117     scanf("%d",&n);   
118     while (n--){
119         int id,x;  
120         scanf("%d%d",&id,&x);   
121         if(id==1) add(x),s.insert(x);  
122         if(id==2) del(x),s.erase(s.find(x));  
123         if(id==3) printf("%d\n",rk(x));  
124         if(id==4) printf("%d\n",nth(x));   
125         if(id==5) printf("%d\n",pre(x));    
126         if(id==6) printf("%d\n",nxt(x));    
127     }   
128     return 0;  
129 }       
View Code

 

 
替罪羊树的核心思想:  暴力重构,不平衡就重构,总之就是一眼不合就重构。  
这里的这种标记每个被删除的写法,非常不适合求前趋和后继,还是建议删除的时候,真的删除就可以了,因为如果不平衡了以后可以重构。  
前趋和后继写的我心累,直接给了一个multiset 
 
 
posted @ 2019-07-04 20:44  zjxxcn  阅读(194)  评论(0编辑  收藏  举报