FHQ treap學習(複習)筆記

.....好吧....最後一篇學習筆記的flag它倒了.....node

好吧,這篇筆記也鴿了很久很久了...c++

比賽前刷模板,纔想着仍是補個坑吧...數據結構

FHQ,這個神仙(範浩強大佬),發明了這個神仙的數據結構,ide

首先,本篇博客使用洛谷普通平衡樹爲背景,即函數

  • 查找前驅
  • 查找後記
  • 查找kth的數
  • 查找k的排名
  • 插入一個數
  • 刪除一個數

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; } }
View Code

經過這樣一個遞歸,不斷拆分節點&&合併的過程當中,就創建了一棵新樹。

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); } }
View Code

這樣,咱們就能夠幹以上的事了。

前置:查找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]; } } } }
View Code

而後就能夠A掉普通平衡樹了。

插入新節點:首先暴力新建一個節點

int new_node(int k) { tot++; t[tot].size=1; t[tot].v=k; t[tot].key=rand(); return tot; }
View Code

而後把樹從k地方斷開,把新節點看作一棵樹,把它和上下樹合在一塊兒就好了

split(rt,a,x,y); rt=merge(merge(x,new_node(a)),y);
View Code

刪除節點:

把樹從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);
View Code

查找排名:

把樹從k分開,則k所在的數的size即便排名

split(rt,a-1,x,y); printf("%d\n",t[x].size+1); rt=merge(x,y);
View Code

查找kth:

直接用kth函數便可

printf("%d\n",t[kth(rt,a)].v);
View Code

前驅:

把樹從k分開,則size-1大小的那個kth點就是前驅

split(rt,a-1,x,y); printf("%d\n",t[kth(x,t[x].size)].v); rt=merge(x,y);
View Code

後繼:同上

split(rt,a,x,y); printf("%d\n",t[kth(y,1)].v); rt=merge(x,y);
View Code

完整高清無碼代碼:

#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; }
相關文章
相關標籤/搜索