因為學了treap,不想棄坑去學splay,終於理解了無旋treap...
好像普通treap沒卵用。。。(再次大霧)
簡單說一下思想免得以后忘記。普通treap因為帶旋轉操作似乎沒卵用,而無旋treap可以不旋轉。
經典地不能再經典的例題
題目描述
您需要寫一種數據結構(可參考題目標題),來維護一些數,其中需要提供以下操作:
-
插入x數
-
刪除x數(若有多個相同的數,因只刪除一個)
-
查詢x數的排名(若有多個相同的數,因輸出最小的排名)
-
查詢排名為x的數
-
求x的前驅(前驅定義為小於x,且最大的數)
- 求x的后繼(后繼定義為大於x,且最小的數)
輸入輸出格式
輸入格式:
第一行為n,表示操作的個數,下面n行每行有兩個數opt和x,opt表示操作的序號(1<=opt<=6)
輸出格式:
對於操作3,4,5,6每行輸出一個數,表示對應答案
輸入輸出樣例
10 1 106465 4 1 1 317721 1 460929 1 644985 1 84185 1 89851 6 81968 1 492737 5 493598
106465 84185 492737
說明
時空限制:1000ms,128M
1.n的數據范圍:n<=100000
2.每個數的數據范圍:[-1e7,1e7]
無旋treap最基本的操作就是merge和split。修改都得靠這個。首先說一下merge和split的操作方法。
merge:給你兩個平衡樹a和b,讓你合並它們,但b中所有權值都得大於a中所有權值以維護treap性質。如果是tree只需要建個根節點然后連兩條邊,但無法維護heap性質。其實操作也很簡單,如果a的rand值小於b的rand值,則merge(a.rs,b),否則merge(a,b.ls)。
split:將平衡樹a分成兩個,一個是1~K名,一個是K+1~size名,返回兩個樹的根,我存在了一個pair中。記左子樹size為s,如果k==s則兩根就是左兒子和根,如果k==s+1則兩根就是根和右兒子。若都不是,繼續向下遞歸,那個就參照以下查詢排名的操作。注意split要將兒子設為0
那么基本操作怎么實現???
查詢排名、查詢排名為x的數、查詢前驅后繼代碼基本不變,只是要注意這里需要合並分離所以不可以記錄出現次數要新開一個數,否則后果自行腦補。
插入操作:先查詢這個數x的排名K,然后把treap分成兩個treap,即執行split(root,K),得到兩根a,b。再合並兩次,即執行root=merge(a,點的新編號),root=merge(root,b)(注意要重設root)
刪除操作:也差不多。先查詢排名K,然后把treap分成三個treap,分別為a=1~K-1,b=K,c=K+1~n,要刪去K,只需再合並a,c子樹即可
不旋轉應該就可以維護一些別的好東西了
然而並不會
然后附上普通平衡樹的AC代碼:

1 // It is made by XZZ 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 #define rep(a,b,c) for(rg int a=b;a<=c;a++) 6 #define drep(a,b,c) for(rg int a=b;a>=c;a--) 7 #define erep(a,b) for(rg int a=fir[b];a;a=nxt[a]) 8 #define il inline 9 #define rg register 10 #define vd void 11 #define mp make_pair 12 typedef long long ll; 13 il int gi(){ 14 rg int x=0,f=1;rg char ch=getchar(); 15 while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar(); 16 while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 17 return x*f; 18 } 19 #define Now tree[now] 20 struct node{int ls,rs,value,rand,size;}tree[100010]; 21 int root,siz; 22 int seed=151806+150605+151127;//mou shen ben xue hao+mou da lao xue hao+mou ju ruo xue hao 23 il int Rand(){return seed=seed*48271%2147483647;} 24 il vd reset(int now){Now.size=tree[Now.ls].size+tree[Now.rs].size+1;} 25 il int merge(int a,int b){ 26 if(!a||!b)return a|b; 27 if(tree[a].rand<tree[b].rand){tree[a].rs=merge(tree[a].rs,b),reset(a);return a;} 28 else {tree[b].ls=merge(a,tree[b].ls),reset(b);return b;} 29 } 30 il pair<int,int>split(int now,int num){ 31 if(!now)return mp(0,0); 32 int ls=Now.ls,rs=Now.rs; 33 if(num==tree[ls].size){Now.ls=0,reset(now);return mp(ls,now);} 34 if(num==tree[ls].size+1){Now.rs=0,reset(now);return mp(now,rs);} 35 if(num<tree[ls].size){ 36 pair<int,int>T=split(ls,num); 37 Now.ls=T.second,reset(now); 38 return mp(T.first,now); 39 }else{ 40 pair<int,int>T=split(rs,num-tree[ls].size-1); 41 Now.rs=T.first,reset(now); 42 return mp(now,T.second); 43 } 44 } 45 il int getrank(int now,int num){ 46 int ret=0,t=1e9; 47 while(now){ 48 if(num==Now.value)t=min(t,ret+tree[Now.ls].size+1); 49 if(num<=Now.value)now=Now.ls; 50 else ret+=tree[Now.ls].size+1,now=Now.rs; 51 } 52 return t==1e9?ret:t; 53 } 54 il int getnum(int now,int num){ 55 while(1){ 56 if(tree[Now.ls].size==num-1)return Now.value; 57 if(tree[Now.ls].size>num-1)now=Now.ls; 58 else num-=tree[Now.ls].size+1,now=Now.rs; 59 } 60 } 61 il int lower(int now,int num){ 62 int ret; 63 while(now)if(tree[now].value<num)ret=tree[now].value,now=Now.rs; 64 else now=Now.ls; 65 return ret; 66 } 67 il int upper(int now,int num){ 68 int ret; 69 while(now)if(tree[now].value>num)ret=tree[now].value,now=Now.ls; 70 else now=Now.rs; 71 return ret; 72 } 73 il vd ins(int num){ 74 int Rank=getrank(root,num),now; 75 pair<int,int>tmp=split(root,Rank); 76 now=++siz; 77 Now.value=num,Now.rand=Rand(),Now.size=1; 78 root=merge(tmp.first,siz); 79 root=merge(root,tmp.second); 80 } 81 il vd del(int num){ 82 int Rank=getrank(root,num); 83 pair<int,int>t1=split(root,Rank),t2=split(t1.first,Rank-1); 84 root=merge(t2.first,t1.second); 85 } 86 int main(){ 87 int n=gi(),opt,x; 88 while(n--){ 89 opt=gi(),x=gi(); 90 switch(opt){ 91 case 1:ins(x);break; 92 case 2:del(x);break; 93 case 3:printf("%d\n",getrank(root,x));break; 94 case 4:printf("%d\n",getnum(root,x));break; 95 case 5:printf("%d\n",lower(root,x));break; 96 case 6:printf("%d\n",upper(root,x));break; 97 } 98 } 99 return 0; 100 }
還有一篇博客代碼寫的不錯,這是鏈接