本題解是題解欄內一些常見思路的集合。數組
爲了篇幅緊湊,在一些地方我可能跳過了證實/闡述的不是怎麼詳細,若是但願看到某一個思路的詳細闡述/代碼,能夠點擊相關的超連接。數據結構
本題的部分分啓發咱們去找性質:spa
性質:blog
計數方法:get
考慮一個點\(u\),咱們想要知道,它會成爲幾回重心。class
將樹在\(u\)處定根,設其最大的子樹大小爲\(S=siz_w\),則能夠分爲兩種狀況:二叉樹
所以,咱們考慮處理出以\(u\)爲根,各個兒子的\(\{siz\}\)的可重集合的狀況,再查詢一段區間內的\(siz\)的個數便可。方法
能夠用可持久化線段樹(可能能夠線段樹合併/將全部查詢離線化)維護。數據
特別地,\(fa_u\)的狀況,至關於\(tree-anc_u-tree_u\)與\(\{u\}+anc_u-\{rt\}\)取反。(其中,\(anc_u\)表示\(u\)的全部祖先節點)
咱們先找到重心\(rt\),並以它做爲根。這樣和隨意選根有什麼區別呢?
性質:若\(x\ne rt\)爲重心,則刪去的邊\((u,v)\)必定不在\(tree_x\)內。
所以,對一個點\(u\ne rt\),他做爲重心僅當刪去了一條邊\((x,y)\),且:\((x,y)\)不在\(tree_u\)內,\(n-2s_x\le S\le n-2g_x\)。(設樹減小的大小爲\(S\))
對於根的狀況,能夠另外(分紅割去的邊在重兒子子樹內與不在重兒子子樹內)判斷。
能夠用樹狀數組維護,具體見這篇題解。
考慮一種刪邊狀況,咱們須要快速求出,劃分後的全部重心。
考慮如何求一棵樹的重心:由於重心必定在根節點所在重鏈上,從根一直跳重兒子,直到找到最深的\(v\)使得,\(2s_v > s_u\),則\(v\)(可能還有它的重兒子)爲重心。此過程能夠用倍增長速。
由這種作法,咱們能夠在樹鏈剖分,並預處理倍增數組以後\(O(\log n)\)地求出任何子樹的重心。
咱們考慮一個劃分\((u,v)\),不妨設\(dep_u>dep_v\):
考慮如何求\(tree_u\)的重心:咱們從\(u\)出發,一直向重兒子跳,跳到找到重心(即,重兒子的子樹大小不超過原樹的一半)爲止。
考慮如何求出\(tree-tree_u\)的重心:咱們先將根換到\(v\)處(此時只改變了兩個節點的關係),這樣實際上就至關於求\(tree_u\)的重心!
具體實如今此。
就如以前所說的,能夠在\(O(n)\)計算出全部子樹的重心,可是很難對去掉子樹的部分找到一個重心單調移動的計算序列……
以重心爲根,考慮刪去的邊在哪棵子樹內:
這樣就用純圖論方法完成了這題。