剛剛跟着EM-LGH大佬學了非旋轉Treapnode
很是慶幸不用再寫萬惡的rotate了(來自高級數據結構的惡意)c++
來記一下數據結構
簡單來講,\(Tree_{二叉搜索樹} * Heap_堆 = Treap_{平衡樹}\)spa
這顯然不是袁隆平爺爺乾的code
顯然這兩樣東西有各自的排列順序——左小右大以及根小(大)兒子大(小)ci
對於尋找答案來說,二叉搜索樹更加方便get
— 那麼堆用來幹嗎呢it
很簡單,用來達到指望平衡class
— 怎麼實現呢
經過另外一個關鍵字
— 爲何是「指望」平衡呢
由於是經過隨機的關鍵字啊!
上面說過了,二叉搜索樹管答案,堆管時間
李雲龍:「你管生活,我管軍事」
如何讓隨機的關鍵字知足堆的性質,同時節點的值知足二叉搜索樹的性質呢
然而這個玩意十分難寫且難理解。。。
因此就出現了……
它與旋轉的Treap很類似
可是它是基於分裂和合並兩個基本操做而不是旋轉
-define表+struct,請對照此表理解代碼-
#define lson t[x].ls #define rson t[x].rs #define si t[x].size #define ra t[x].ran #define lss t[t[x].ls].size #define rss t[t[x].rs].size #define va t[x].val //------------------------- struct node { int val, size, ls, rs, ran; }t[100001];
正常的初始化
inline void newnode(int &x, int val) { ++tot; t[tot].size=1; t[tot].val=val; t[tot].ran=rand(); t[tot].ls=t[tot].rs=0; x=tot; }
指定一個val,將值∈[0, val]的節點與值∈(val, +∞)的節點分紅兩棵樹
實現過程和尋找後繼的過程很像
void split(int x, int &l, int &r, int val) { if(!x) { l = r = 0; return; } if(va <= val) l = x, split(t[x].rs, t[l].rs, r, val);//當前值比val小或等於val,則將它與它的左子樹所有劃分到第一棵樹,繼續尋找它的右子樹 else r = x, split(t[x].ls, l, t[r].ls, val);//反之,則將它與它的右子樹劃分到第二棵樹,尋找它的左子樹 pushup(x);//不要忘記更新size }
分裂的反過程
要求合併的A樹與B樹中\(A_{max} < B_{min}\)
void merge(int &x, int a, int b) { if(!a||!b) { x = a + b; return; } if(t[a].ran < t[b].ran) x = a, merge(t[x].rs, t[a].rs, b);//隨機值在這裏用,用來在合併時維護堆的性質 else x = b, merge(t[x].ls, a, t[b].ls); pushup(x);//更新! }
基於分裂和合並
在\(val - 1\)處分裂->合併節點Z與樹A->合併樹A與樹B
void insert(int val) { int x = 0, y = 0, z = 0; newnode(z, val); split(root, x, y, val - 1); merge(x, x, z); merge(root, x, y); }
和插入很像
將大樹在\(val - 1\)處分裂成AB->將樹B在\(val\)處分裂成BC->合併樹A與樹C
void del(int val) { int x = 0, y = 0, z = 0; split(root, x, y, val); split(x, x, z, val - 1); merge(z, t[z].ls, t[z].rs);//這裏是只刪除一個的操做,所有刪除請忽略本行和下一行 merge(x, x, z); merge(root, x, y); }
和插入很像
在\(val-1\)處分裂->輸出A的size
void ask_rank(int v) { int x = 0, y = 0; split(root, x, y, v - 1); cout << si + 1; merge(root, x, y); }
至關於反着問排名
void ask_num(int x, int kth) { while(lss + 1 != kth) { if(lss >= kth) x = lson; else kth -= (lss + 1), x = rson; } cout << va; }
在\(v-1\)處分裂->詢問A中最大(第size小)->合併
void ask_fr(int v) { int x = 0, y = 0; split(root, x, y, v - 1); ask_num(x, si); merge(root, x, y); }
與前驅相反
在\(v\)處分裂->詢問B中第一小->合併
void ask_ba(int v) { int x = 0, y = 0; split(root, x, y, v); ask_num(y, 1); merge(root, x, y); }
因爲它是指望平衡的,因此它的全部操做都在\(O(logN)\)左右。
#include <bits/stdc++.h> #define lson t[x].ls #define rson t[x].rs #define si t[x].size #define ra t[x].ran #define lss t[t[x].ls].size #define rss t[t[x].rs].size #define va t[x].val using namespace std; int root; namespace treap { int tot; struct node { int val, size, ls, rs, ran; }t[100001]; inline void newnode(int &x, int val) { ++tot; t[tot].size=1; t[tot].val=val; t[tot].ran=rand(); t[tot].ls=t[tot].rs=0; x=tot; } inline void pushup(int x) { si = lss + rss + 1; } void split(int x, int &l, int &r, int val) { if(!x) { l = r = 0; return; } if(va <= val) l = x, split(t[x].rs, t[l].rs, r, val); else r = x, split(t[x].ls, l, t[r].ls, val); pushup(x); } void merge(int &x, int a, int b) { if(!a||!b) { x = a + b; return; } if(t[a].ran < t[b].ran) x = a, merge(t[x].rs, t[a].rs, b); else x = b, merge(t[x].ls, a, t[b].ls); pushup(x); } void insert(int val) { int x = 0, y = 0, z = 0; newnode(z, val); split(root, x, y, val - 1); merge(x, x, z); merge(root, x, y); } void del(int val) { int x = 0, y = 0, z = 0; split(root, x, y, val); split(x, x, z, val - 1); merge(z, t[z].ls, t[z].rs); merge(x, x, z); merge(root, x, y); } void ask_rank(int v) { int x = 0, y = 0; split(root, x, y, v - 1); cout << si + 1; merge(root, x, y); } void ask_num(int x, int kth) { while(lss + 1 != kth) { if(lss >= kth) x = lson; else kth -= (lss + 1), x = rson; } cout << va; } void ask_fr(int v) { int x = 0, y = 0; split(root, x, y, v - 1); ask_num(x, si); merge(root, x, y); } void ask_ba(int v) { int x = 0, y = 0; split(root, x, y, v); ask_num(y, 1); merge(root, x, y); } }; using namespace treap; int main() { int n; cin >> n; srand(2005); while(n--) { int x, y; cin >> x >> y; if(x == 1) insert(y); else if(x == 2) del(y); else if(x == 3) ask_rank(y), cout << endl; else if(x == 4) ask_num(root, y), cout << endl; else if(x == 5) ask_fr(y), cout << endl; else if(x == 6) ask_ba(y), cout << endl; } return 0; }