平衡樹(三)——FHQ Treap
阿新 • • 發佈:2021-06-12
目錄
前言
上文介紹了普通的平衡樹,它簡單(奇怪,鬼畜)的旋轉操作確實死難寫也難調(剛寫掛一個),於是跑去學了一個不用旋轉的平衡樹,無旋 \(Treap (FHQ~~Treap)\)
只需要兩個操作達到 \(splay\) 全部功能 ?? 太炫酷了
概況
\(FHQ~~Treap\) 和普通的 \(Treap\) 一樣每個節點維護兩個值,一個是權值,一個是隨機值
但是它不再是用旋轉來維護,而是通過 \(split\) 和 \(merge\) 進行維護
操作
split(分樹)
把一個 \(Treap\) 分成兩個
兩種:按權值分,按子樹大小分
複雜度 \(O(log n)\)
按權值分
把權值小於 \(k\) 的節點都分到一棵樹中,其餘的點都分到另一棵樹中
如果當前節點權值小於 \(k\) 那麼它的左子樹都會分到一棵樹內,然後向右孩子查詢
否則該節點的右節點都會分到另一個子樹內,然後向右查詢
void split(int p, int k, int &x, int &y) { if (!p) x = y = 0; else { if (val[p] <= k) x = p, split(rs(p), k, rs(p), y); else y = p, split(ls(p), k, x, ls(p)); update(p); } }
按子樹大小分
把一棵樹分成兩棵樹,其中一棵的大小為 \(k\)
和 \(Treap\) 的 \(Kth\) 操作類似
如果當前點的左子樹大小大於 \(k\) ,向左子樹繼續查詢
否則的話該點的左子樹一定在大小為 \(k\) 的樹中,然後使右子樹分出 \(k - siz[p] - 1\) 大小的子樹
int split(int p, int k, int &x, int &y) { if(!p) x = y = 0; else { if(k <= siz(ls(p))) y = p, split(ls(p), k, x, ls(p)); else x = p, split(rs(p), k - siz[ls(p)] - 1, rs(p), y); update(p); } }
merge(合併)
先咕著,明天寫……