1. 程式人生 > >洛谷P3369 【模板】普通平衡樹

洛谷P3369 【模板】普通平衡樹

題目描述

題目描述 您需要寫一種資料結構(可參考題目標題),來維護一些數,其中需要提供以下操作:

插入x數 刪除x數(若有多個相同的數,因只刪除一個) 查詢x數的排名(排名定義為比當前數小的數的個數+1。若有多個相同的數,因輸出最小的排名) 查詢排名為x的數 求x的前驅(前驅定義為小於x,且最大的數) 求x的後繼(後繼定義為大於x,且最小的數) 輸入輸出格式 輸入格式: 第一行為n,表示操作的個數,下面n行每行有兩個數optxopt表示操作的序號( 1opt6 )

輸出格式: 對於操作3,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的資料範圍: n100000 2.每個數的資料範圍: [107,107]

題解

一道裸的平衡樹題。。。 就拿來練非旋Treap吧。。。

code

#include <iostream>
#include <cstdlib>
#include <cstdio> #include <ctime> #define fo(a,b,c) for (a=b; a<=c; a++) #define fd(a,b,c) for (a=b; a>=c; a--) #define Max 100000 #define max 10000001 #define min -10000001 using namespace std; int tr[Max+1][2]; int sum[Max+1]; int fa[Max+1]; int heap[Max+1]; int num[Max+1]; bool del[Max+1]; int
n,Q,I,i,j,k,l,x,y,X,Fs,Ls,type,root,Find,Find2,now,fa1,fa2; void up(int t) {sum[t]=sum[tr[t][0]]+sum[tr[t][1]]+1;} void merge(int Fa,int son,int x,int y) { if (heap[x]<heap[y]) { tr[Fa][son]=x; fa[x]=Fa; if (tr[x][1]) merge(x,1,tr[x][1],y); else { sum[x]+=sum[y]; tr[x][1]=y; fa[y]=x; } } else { tr[Fa][son]=y; fa[y]=Fa; if (tr[y][0]) merge(y,0,x,tr[y][0]); else { sum[y]+=sum[x]; tr[y][0]=x; fa[x]=y; } } if (Fa) up(Fa); } void split(int Fa1,int Fa2,int t,int k) { if (sum[tr[t][0]]>=k) { if (!fa1) fa1=t; if (fa[t]) { tr[fa[t]][tr[fa[t]][1]==t]=0; up(fa[t]); } tr[Fa1][0]=t; fa[t]=Fa1; if (k && tr[t][0]) split(t,Fa2,tr[t][0],k); if (Fa1) up(Fa1); } else { if (!fa2) fa2=t; if (fa[t]) { tr[fa[t]][tr[fa[t]][1]==t]=0; up(fa[t]); } tr[Fa2][1]=t; fa[t]=Fa2; if (tr[t][1]) split(Fa1,t,tr[t][1],k-sum[tr[t][0]]-1); if (Fa2) up(Fa2); } } int find(int t,int k) { if (sum[tr[t][0]]>=k) return find(tr[t][0],k); else if (sum[tr[t][0]]+1==k) return num[t]; else return find(tr[t][1],k-sum[tr[t][0]]-1); } void find1(int t,int s) { if (tr[t][0] && num[t]>=s) find1(tr[t][0],s); else if (tr[t][1] && num[t]<s) find1(tr[t][1],s); if (num[t]<s) { Find2+=sum[tr[t][0]]+1; if (num[t]>Find) Find=num[t]; } } void find2(int t,int s) { if (tr[t][1] && num[t]<=s) find2(tr[t][1],s); else if (tr[t][0] && num[t]>s) find2(tr[t][0],s); if (num[t]>s && num[t]<Find) Find=num[t]; } int gf(int t) { for (;fa[t];t=fa[t]); return t; } int main() { srand(time(NULL)); scanf("%d",&Q); fo(i,1,Max) { heap[i]=rand()*32768+rand(); sum[i]=1; } I=1; n=0; now=0; for (;Q;Q--) { scanf("%d%d",&type,&x); switch (type) { case 1: { num[++n]=x; if (!now) { now++; root=n; break; } Find=min; Find2=0; find1(root,x); if (!Find2) merge(0,0,n,root); else if (Find2==now) merge(0,0,root,n); else { fa1=0,fa2=0; split(0,0,root,Find2); merge(0,0,fa2,n); merge(0,0,gf(n),fa1); } root=gf(n); now++; break; } case 2: { Find=min; Find2=0; find1(root,x+1); if (Find!=x) break; Find=min; Find2=0; find1(root,x); if (!Find2) { fa1=0,fa2=0; split(0,0,root,1); root=fa1; } else if (Find2+1==now) { fa1=0,fa2=0; split(0,0,root,now-1); root=fa2; } else { fa1=0,fa2=0; split(0,0,root,Find2); j=fa1,k=fa2; fa1=0,fa2=0; split(0,0,j,1); merge(0,0,k,fa1); root=gf(k); } now--; break; } case 3: { Find2=0; find1(root,x); printf("%d\n",Find2+1); break; } case 4: { printf("%d\n",find(root,x)); break; } case 5: { Find=min; Find2=0; find1(root,x); printf("%d\n",Find); break; } case 6: { Find=max; find2(root,x); printf("%d\n",Find); break; } } } }