一些細節
本質是利用合併、分裂實現增、刪、查。
根據用途分為兩類分裂:
第一類:當作 set
一樣使用,就是中序遍歷就把數字排序了。分裂操作按照權值分裂。
如果
-
根 \(\le k\),那麼左邊都要歸入 \(x\),遞迴右邊,\(x\) 換成右邊(看還能接上去多少)
-
\(>k\) 同理,最後
pushup
一下。
第二類:維護序列,要對序列操作的話就按照 size
分裂,基本和上面一樣,需要注意如果是情況1,進入右子樹需要減去已經劃入左邊的 size
(即 \(l_{sz}+1\),因為你要保證左邊子樹是 size
個節點啊,就去右邊找剩下的)。
合併方法:
- 有一個為空,根返回另一個。
- 按照節點生成時的優先順序合併,記小的樹為 \(x\),大的樹為 \(y\)(這是按照分裂時的順序或者權值大小區分的)。 \(y\) 合到 \(x\) 的右邊,或者 \(x\) 合到 \(y\) 的左邊。對合到的點
pushup
,返回。
接下來就是針對上面的操作的應用:(以第一類為例)
-
插入 \(k\)(建立一個單獨樹,記為 \(a\)),分裂得到 \(<k,\ge k\)(記為 \(b,c\)),合併 \(b,a\),再跟 \(c\) 合併。
-
刪除,先分裂得到 \(\le k,>k\)(記為 \(a,b\)),再分裂 \(a\) 得到 \(\le k-1,=k\)(記為 \(a,c\)),把 \(c\) 的兩個兒子合併刪去根,,合併 \(a,c\),再跟 \(b\) 合併。
-
排名查詢:分裂利用size
-
查詢排名對應的數:從根開始每次考慮往左還是往右找
-
前驅:分裂然後小的裡一直往大的走
-
後繼:分裂然後大的裡一直往小的走
第二類類比一下。