樹上技巧
HLD
heavy-light decomposition
定義
給每條邊分成輕,重兩類
滿足每個非葉子節點恰好有一條往下的重邊,並且重邊是最大的那個子樹
如果把輕邊拔掉的話樹會被分成很多條鏈,這就是我們想要討論的部分
觀察會發現,考慮任何一條只往上走路徑,路徑上最多會經過 O(log n) 條輕邊
證明跟啟發式合併一樣
例題
如果我們對於每條鏈開一棵線段樹,那麼
單點修改就單點修改
路徑查詢可以拆成 O(log n) 條路徑,每條考慮的路徑都是區間查詢
=> O(log n) 次線段樹上查詢 => O(log^2 n)
那就 done 了
HLD 主要用在要算路徑
樹壓平主要用在算子樹
所以不要看到樹上改值就直接砸 HLD 了
我覺得我上次寫 HLD 已經是一年多以前了
重心剖分
有人叫他 cd,有人叫他 dc,請投票
還記得重心吧
重心分治分為三步驟:
- 找到重心
- 對重心算答案
- 把重心拔掉並分治到每一棵子樹下去
有一棵樹,每個點都有一個顏色,你要選出一個顏色的子集 S 滿足
- 對於所有滿足顏色皆屬於 S 的點對,他們之間的簡單路徑上的所有點的顏色都屬於 S
- S 是可能的集合裡面最小的
考慮定根,假設我們選出的 S 一定要包含根
那麼你可以導出一個 greedy algorithm
let V = {與根有相同顏色的點的集合}
每次任意選出一個 V 中的元素,並把他到根的路徑上面的所有顏色都加到 S 裡面,並且把所有還沒看過的並且顏色在 S 裡面的點都加進 V 裡面,直到 V 為空
不難驗證現在的 S 是定根下的最佳解
上面的工作可以用一個 queue 完成
因此考慮重剖,依次考慮過 S 必須包含每個點的情形取最小值就是答案了
來算時間複雜度
根據重心的規則,每次拔掉重心剩下的子樹的大小要 <= n/2
代表只能拔掉 O(log n) 次重心就會退化成一個點
定根在重心的複雜度是 O(n)
一個點只會出現在 O(log n) 棵樹裡面
=> 總複雜度 O(n log n)
算是 JOISC 裡面少數簡單的題目了
題外話是這場的 B 跟 C 也都很有趣,推薦寫
DSU on tree
算是一種 HLD 的應用
直接上步驟:
- 把輕子樹的答案都算好,然後丟掉
- 把重子樹的答案算好,不要丟掉
- 再遍歷一次輕子樹,並且把答案跟重子樹的答案合併然後得到當前節點的答案
時間一樣一個 log,好處是因為可以丟掉資訊通常可以省下空間或是大結構的數量
其他酷東西
啟發式消滅,可以直接去看題解
deck
By alvingogo
deck
- 415