很久沒PO文了 來放個教學文好了
之前想要學 dsu on tree 所以就跑去看CF的這篇
不過看了好久還是看不懂 決定還是自己來紀錄一下DSU on Tree
為什麼叫做 dsu on tree?
dsu on tree 其實跟並查集(dsu)沒有什麼關聯
但是他用到了啟發式合併 也就是 dsu 常會用到的一種降低複雜度的作法
DSU 的啟發式合併
1 | void unite(int u, int v){ |
樹上問題的 Naive Solution
首先 在進入 dsu on Tree 之前 先來看看一個例題
給予一棵以 $1$ 為根的一棵樹
在 $O(1)$ 的時間詢問以 $x$ 為根的子樹有幾個顏色為 $c$ 的節點?
這個問題 我們可以很輕易的想到他的作法 也就是直接 dfs 去存數量
但是這並不是一個很好的方法 因為預處理的時候 會花 $O(n^2)$ 的時間
$O(n^2)$ 的程式碼
1 | void add(int u, int par, int x){ |
使用 dsu on tree
要改進上面的解法 我們就可以使用 dsu on tree
dsu on tree 的概念
我們可以先考慮樹鏈剖分的概念 先做一次找出子樹的大小
1 | void dfs_size(int u, int par){ |
之後要找答案再做另一次 dfs
先去對輕鏈做 dfs 找到輕鏈上的答案
之後再對重鏈去找到重鏈上的答案 將輕重鏈的答案合併
1 |
|
例題
Codeforces 600D - Lomsat gelral
給予一棵以 $1$ 為根的樹以及每一個節點的顏色
問以 $1$ ~ $n$ 為根的子樹內 出現最多次的顏色 $c$ 的總和為?
這題也是 dsu on tree 可以輕鬆解掉的題目
只要維護出現最多次的顏色就能解決了
1 |
|