Tyvj 1728 普通平衡樹
阿新 • • 發佈:2017-06-04
查詢 pre 序號 med esc desc 5% 其中 數據結構 Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 13242 Solved: 5675
[Submit][Status][Discuss]
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
84185
492737
2.每個數的數據範圍:[-2e9,2e9]
Submit: 13242 Solved: 5675
[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
101 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
Sample Output
10646584185
492737
HINT
1.n的數據範圍:n<=1000002.每個數的數據範圍:[-2e9,2e9]
Source
平衡樹
思路
splay
事實上,哨兵還是挺有用的,減輕邏輯負擔;
由於是模板題:
t節點數值,f節點父親編號,sz以節點為根的子樹尺寸,am節點中數的個數,s節點的左右子編號;
rot()單旋;
splay()伸展(這裏沒有用雙旋,因為腦模單旋和雙旋操作量和結果一樣,實測雙旋也並不比單旋快);
ins()添加數;
find1()把要查找的節點旋到樹根;
find2()查找序號對應節點;
find3()查找前驅;
find4()查找後繼;
del()刪除數;
del():減少root節點的am值或是刪除root節點;
case1:減少root節點的sz和am值並退出;
case2:
將root的右子樹接到root的左子樹中的最右子上,同時更新從root的左子樹到左子樹樹中最右子的路徑上的節點的sz值;
調整嫁接處的值,root改為原root的左子;
將原root的左子樹的最右子旋到根的位置;
代碼實現
1 #include<cstdio> 2 const int maxn=3e5; 3 int n,ope,val; 4 int rt,hd; 5 int t[maxn],f[maxn],sz[maxn],am[maxn],s[maxn][2]; 6 void rot(int x){ 7 int y=f[x],z=f[y],l,r; 8 l=s[y][0]==x?0:1,r=l^1; 9 if(y==rt) rt=x; 10 else{ 11 if(s[z][0]==y) s[z][0]=x; 12 else s[z][1]=x; 13 } 14 f[x]=z,f[y]=x,f[s[x][r]]=y; 15 s[y][l]=s[x][r],s[x][r]=y; 16 sz[y]=sz[s[y][0]]+sz[s[y][1]]+am[y]; 17 sz[x]=sz[s[x][0]]+sz[s[x][1]]+am[x]; 18 } 19 void splay(int x){while(x!=rt) rot(x);} 20 void ins(int k,int x,int fa){ 21 if(!rt){rt=++hd,t[rt]=x,sz[rt]=1,am[rt]++;return;} 22 while(k) fa=k,++sz[k],k=s[k][x>t[k]]; 23 k=s[fa][x>t[fa]]=++hd; 24 t[k]=x,sz[k]=1,f[k]=fa,am[k]++; 25 splay(k); 26 } 27 void find1(int k,int x){ 28 if(!k) return; 29 while(s[k][x>t[k]]&&t[k]!=x) k=s[k][x>t[k]]; 30 splay(k); 31 } 32 int find2(int k,int x){ 33 if(x<=sz[s[k][0]]) return find2(s[k][0],x); 34 if(x==sz[s[k][0]]+1) return t[k]; 35 return find2(s[k][1],x-sz[s[k][0]]-1); 36 } 37 int find3(int k,int x,int sum){ 38 if(!k) return sum; 39 if(x>t[k]) return find3(s[k][1],x,t[k]); 40 else return find3(s[k][0],x,sum); 41 } 42 int find4(int k,int x,int sum){ 43 if(!k) return sum; 44 if(x<t[k]) return find4(s[k][0],x,t[k]); 45 else return find4(s[k][1],x,sum); 46 } 47 void del(int k,int x){ 48 if(am[k]>1){am[k]--,sz[k]--;return;} 49 x=s[k][1]; 50 while(s[x][0]) x=s[x][0],sz[x]+=sz[s[k][0]]; 51 f[s[k][0]]=x,s[x][0]=s[k][0],rt=s[k][1]; 52 f[rt]=0; 53 splay(x); 54 } 55 int main(){ 56 freopen("phs.in","r",stdin); 57 freopen("phs.out","w",stdout); 58 ins(rt,-2e9-10,0),ins(rt,2e9+10,0); 59 scanf("%d",&n); 60 for(int i=1;i<=n;i++){ 61 scanf("%d%d",&ope,&val); 62 if(ope==1) ins(rt,val,0); 63 if(ope==2) find1(rt,val),del(rt,0); 64 if(ope==3) find1(rt,val),printf("%d\n",sz[s[rt][0]]); 65 if(ope==4) printf("%d\n",find2(rt,val+1)); 66 if(ope==5) printf("%d\n",find3(rt,val,0)); 67 if(ope==6) printf("%d\n",find4(rt,val,0)); 68 } 69 return 0; 70 }
Tyvj 1728 普通平衡樹