模板:左偏树
文章目錄
- 解析
- 可以解決的問題
- 定義:
- 左偏樹的基本性質
- 基本結論
- 操作
- 合并
- 訪問與刪除堆頂元素
- 插入元素
- 批量插入
- 刪除已知元素
所謂左偏樹,就是往左偏的樹
下面介紹一下它的一個兄弟:
《右偏樹》
(逃)
解析
所謂左偏樹,確實就是往左偏的樹
它舍棄了平衡的性質,使這個堆在合并時變得極為高效
所以又叫做可并堆
代碼實現起來還是很好寫的
可以解決的問題
似乎基本上是起一個工具人的作用
出現在題解中“…對于某某信息,維護可并堆即可”這樣的地方
不會確實不行呀 qwq
定義:
外結點 :左兒子或右兒子是空結點的結點。
距離 : 一個結點 x 的距離 dist(x)定義為其子樹中與結點 x 最近的外結點到 x 的距離。特別地,定義空結點的距離為 -1 。
左偏樹的基本性質
左偏樹具有堆性質 ,即若其滿足小根堆的性質,則對于每個結點 x 有vx<vlsv_x<v_{ls}vx?<vls?且vx<vrsv_x<v_{rs}vx?<vrs?
左偏樹具有 左偏性質 ,即對于每個結點 x ,有 distlc≥distrcdist_{lc}\ge dist_{rc}distlc?≥distrc?
基本結論
結點 x 的距離 distx=distrc+1dist_x=dist_{rc}+1distx?=distrc?+1
距離為 n 的左偏樹至少有 2n+1?12^{n+1}-12n+1?1個結點。此時該左偏樹的形態是一棵滿二叉樹。
有 n 的結點的左偏樹的根節點的距離是 O(log?2n)O(\log_2 n)O(log2?n)
(以上參考自:https://www.luogu.com.cn/blog/hsfzLZH1/solution-p3377)
上面的性質還是比較顯然的
下面我們來講講具體的操作
操作
合并
左偏樹的靈魂
設當前是小根堆,要把x堆與y堆合并
首先,如果x、y有一個為空,直接返回另一個
否則,把值較小的作為根,把根的右兒子與另一個堆合并
遞歸即可
遞歸回來的時候還要更新dist并維護左偏的性質
由于左偏樹極右鏈是不超過logn的
因此復雜度為logn
寫起來也很好寫
訪問與刪除堆頂元素
把堆頂的左右兒子合并并返回即可
int del(int &x){int res=val[x];x=merge(ls[x],rs[x]);return res; }插入元素
把一個元素當成一棵樹,與大樹合并即可
void insert(int &r,int v){int x=New(v);r=merge(r,x); }批量插入
直接插入n次nlogn
開一個隊列,把所有元素建成單點的樹push進去
每次從隊首提兩棵樹合并并放到隊尾
直至只剩下一棵樹
復雜度O(n)
刪除已知元素
這是一個左偏樹的重要優勢
它可以在logn的時間內刪除任意位置的已知元素
注意這里的“已知”是指已知編號而不是已知權值
刪除指定權值的操作是堆很難做到的 (至少對我的知識儲備來說)
注意樹的性質可能變,所以要一直往上更新
thanks for reading!
總結
- 上一篇: YBTOJ洛谷P4074:糖果公园(树上
- 下一篇: 烹饪1到375攻略 需要怎么做