fhq-treap

wscqwq發表於2024-05-01

一些細節

本質是利用合併、分裂實現增、刪、查。

根據用途分為兩類分裂:

第一類:當作 set 一樣使用,就是中序遍歷就把數字排序了。分裂操作按照權值分裂。

如果

  1. \(\le k\),那麼左邊都要歸入 \(x\),遞迴右邊,\(x\) 換成右邊(看還能接上去多少)

  2. \(>k\) 同理,最後 pushup 一下。

第二類:維護序列,要對序列操作的話就按照 size 分裂,基本和上面一樣,需要注意如果是情況1,進入右子樹需要減去已經劃入左邊的 size (即 \(l_{sz}+1\),因為你要保證左邊子樹是 size 個節點啊,就去右邊找剩下的)。

合併方法:

  1. 有一個為空,根返回另一個。
  2. 按照節點生成時的優先順序合併,記小的樹為 \(x\),大的樹為 \(y\)(這是按照分裂時的順序或者權值大小區分的)。 \(y\) 合到 \(x\) 的右邊,或者 \(x\) 合到 \(y\) 的左邊。對合到的點 pushup,返回。

接下來就是針對上面的操作的應用:(以第一類為例)

  1. 插入 \(k\)(建立一個單獨樹,記為 \(a\)),分裂得到 \(<k,\ge k\)(記為 \(b,c\)),合併 \(b,a\),再跟 \(c\) 合併。

  2. 刪除,先分裂得到 \(\le k,>k\)(記為 \(a,b\)),再分裂 \(a\) 得到 \(\le k-1,=k\)(記為 \(a,c\)),把 \(c\) 的兩個兒子合併刪去根,,合併 \(a,c\),再跟 \(b\) 合併。

  3. 排名查詢:分裂利用size

  4. 查詢排名對應的數:從根開始每次考慮往左還是往右找

  5. 前驅:分裂然後小的裡一直往大的走

  6. 後繼:分裂然後大的裡一直往小的走

第二類類比一下。