.....好吧....最後一篇學習筆記的flag它倒了.....node
好吧,這篇筆記也鴿了很久很久了...c++
比賽前刷模板,纔想着仍是補個坑吧...數據結構
FHQ,這個神仙(範浩強大佬),發明了這個神仙的數據結構,ide
首先,本篇博客使用洛谷普通平衡樹爲背景,即函數
FHQ treap,是一個treap,它仍是和treap同樣,是tree+heap,因此它也有一個鍵值維護堆的性質。學習
它能夠幹任何treap和Splay能幹的事。spa
它的實現主要由兩個函數實現:3d
merge:把兩棵樹合併成一棵code
split:把樹分割成兩棵blog
在這裏介紹兩個函數的實現方法:
merge
能夠看到,它把兩棵樹合併了起來,可是並非簡單地接起來,而是打散,從新組合。
代碼:
int merge(int x,int y)//把xy爲根的兩棵子樹給合併
{ if(!x||!y)//若是一邊沒了
return x+y;//就返回
if(t[x].key<t[y].key)//維護key值,若是x的key值小於y的k值
{ t[x].son[1]=merge(t[x].son[1],y);//說明此時必定不符合堆性質,把x的右兒子和y合併
update(x);//更新相關變量
return x;//返回根節點
} else { t[y].son[0]=merge(x,t[y].son[0]);//同上
update(y); return y; } }
經過這樣一個遞歸,不斷拆分節點&&合併的過程當中,就創建了一棵新樹。
split:
從上圖可得:(把樹從5分開)
split的過程就是把樹拆分紅左右樹,左樹全部節點權值都小於k,右樹的節點權值都大於k。
怎麼實現呢?
代碼:
void split(int now,int k,int &x,int &y)//把一棵樹now給從k分割成x和y
{ if(!now) x=y=0;//若是沒有了,就返回
else { if(t[now].v<=k) //若是當前點的權值小於k,它應該在左子樹
{ x=now;//更新
split(t[now].son[1],k,t[now].son[1],y);分割右兒子,找一個可能的更大的 } else//同上
{ y=now; split(t[now].son[0],k,x,t[now].son[0]); } update(now); } }
這樣,咱們就能夠幹以上的事了。
前置:查找kth
由於創建的事一個二叉查找樹,因此仍是能夠像遍歷二叉查找樹那樣查找kth的。
代碼十分簡單
int kth(int now,int k) { while(1) { if(k<=t[t[now].son[0]].size) now=t[now].son[0]; else { if(k==t[t[now].son[0]].size+1) return now; else { k-=t[t[now].son[0]].size+1; now=t[now].son[1]; } } } }
而後就能夠A掉普通平衡樹了。
插入新節點:首先暴力新建一個節點
int new_node(int k) { tot++; t[tot].size=1; t[tot].v=k; t[tot].key=rand(); return tot; }
而後把樹從k地方斷開,把新節點看作一棵樹,把它和上下樹合在一塊兒就好了
split(rt,a,x,y); rt=merge(merge(x,new_node(a)),y);
刪除節點:
把樹從k斷開,而後把左樹從k-1斷開,而後把上下樹給合併,把k節點扔了就好了
split(rt,a,x,z); split(x,a-1,x,y); y=merge(t[y].son[0],t[y].son[1]); rt=merge(merge(x,y),z);
查找排名:
把樹從k分開,則k所在的數的size即便排名
split(rt,a-1,x,y); printf("%d\n",t[x].size+1); rt=merge(x,y);
查找kth:
直接用kth函數便可
printf("%d\n",t[kth(rt,a)].v);
前驅:
把樹從k分開,則size-1大小的那個kth點就是前驅
split(rt,a-1,x,y); printf("%d\n",t[kth(x,t[x].size)].v); rt=merge(x,y);
後繼:同上
split(rt,a,x,y); printf("%d\n",t[kth(y,1)].v); rt=merge(x,y);
完整高清無碼代碼:
#include<bits/stdc++.h>
using namespace std; const int maxn=1e6+10; struct tree { int son[2],v,key,size; }t[maxn]; int tot=0,rt=0; void update(int p) { t[p].size=t[t[p].son[0]].size+t[t[p].son[1]].size+1; } int new_node(int k) { tot++; t[tot].size=1; t[tot].v=k; t[tot].key=rand(); return tot; } int merge(int x,int y)//o?2¢ò?x£?y?a?ùμ?á???×óê÷
{ if(!x||!y) return x+y; if(t[x].key<t[y].key) { t[x].son[1]=merge(t[x].son[1],y); update(x); return x; } else { t[y].son[0]=merge(x,t[y].son[0]); update(y); return y; } } void split(int now,int k,int &x,int &y)//ò?è¨?μk·?à?nowê÷3éx,y
{ if(!now) x=y=0; else { if(t[now].v<=k) //°??ùóDD?óúkμ?è¨?μμ??úμ?·?μ?ò???ê÷?D
{ x=now; split(t[now].son[1],k,t[now].son[1],y); } else { y=now; split(t[now].son[0],k,x,t[now].son[0]); } update(now); } } int kth(int now,int k) { while(1) { if(k<=t[t[now].son[0]].size) now=t[now].son[0]; else { if(k==t[t[now].son[0]].size+1) return now; else { k-=t[t[now].son[0]].size+1; now=t[now].son[1]; } } } } int x,y,z,n; int main() { srand((unsigned)time(NULL)); scanf("%d",&n); int flag,a,b,c; for(int i=1;i<=n;i++) { scanf("%d",&flag); scanf("%d",&a); if(flag==1) { split(rt,a,x,y); rt=merge(merge(x,new_node(a)),y); } if(flag==2) { split(rt,a,x,z); split(x,a-1,x,y); y=merge(t[y].son[0],t[y].son[1]); rt=merge(merge(x,y),z); } if(flag==3) { split(rt,a-1,x,y); printf("%d\n",t[x].size+1); rt=merge(x,y); } if(flag==4) { printf("%d\n",t[kth(rt,a)].v); } if(flag==5) { split(rt,a-1,x,y); printf("%d\n",t[kth(x,t[x].size)].v); rt=merge(x,y); } if(flag==6) { split(rt,a,x,y); printf("%d\n",t[kth(y,1)].v); rt=merge(x,y); } } return 0; }