化實為虛 點分樹 (動態點分治)

2021-08-19 14:08:07 字數 1278 閱讀 3293

有時做題會想到一些與樹深有關的做法,隨機資料下是可以過的,但深度稍大就無法過。樹深做法的問題在於與深度線性相關。給定的一棵樹,其深度是不定的。但使用點分樹,可以把原樹對應到一顆深度為嚴格log

nlog_n

logn

​的樹上。

建立點分樹時,每次選取當前塊中的重心,我們把子塊的重心作為自己重心的兒子,就形成一顆點分樹。可以證明其深度不超過log

nlog_n

logn​。

這樣,一些嚴重依賴樹形態的演算法,如樹形dp,或從全域性角度統計樹中的某些量的問題,都可以輕易用點分樹動態維護

構建點分樹如下。注意到每次重新getgra是在乙個子樹內完成的,因此不用考慮影響統計其他子樹。

int gra, gras;

int cn;

// 當前塊大小

int siz[maxn]

, vis[maxn]

;void

getgra

(int u,

int pa)

maxs =

max(maxs, cn-siz[u]);

if(gras ==-1

|| maxs < gras)

}struct dt_node dt[maxn]

;void

build

(int u,

int pa)

}int

main()

點分樹的應用很多。維護每個點分樹節點也有多種型別,如維護子樹和對父親貢獻兩個值,或維護乙個堆記錄子節點到它的距離(bzoj1095)等。總之是統計子樹內的資訊,然後每次更新或詢問時就從操作節點在點分樹上往父親走,其實與樹深演算法如出一轍,只是這是正解。

點分樹也與很多其他樹上操作技巧結合。可以參考其他樹上操作技巧或樹上操作技巧總結。

另:標題中「實」指原樹,「虛」指與原樹等效的樹,如lct、點分樹、dfs序線段樹(擴充套件為路徑剖分樹/尤拉旅遊樹)等。

upd on 2019.2.1

點分樹支援的操作一般是單點修改和單點查詢,常帶有距離限制。修改即對該點在點分樹上的結點到點分樹根的鏈修改。可考慮對每個點分樹節點開一顆線段樹表示對應深度的答案,再記錄每個點分樹節點對應的原樹中的子樹以點分樹節點對應的點為根的深度即可。注意每個點分樹節點對應的原樹中子樹的大小和是o(n

log⁡n)

o(n\log n)

o(nlogn)

的。也有不少題目要考慮消去自己對點分父親的影響,因此還要記錄對點分父親的貢獻。

BZOJ 1095 捉迷藏 動態點分治 點分樹

1095 zjoi2007 hide 捉迷藏 time limit 40 sec memory limit 256 mb submit 4152 solved 1756 submit status discuss description 捉迷藏 jiajia和wind是一對恩愛的夫妻,並且他們有很多...

點分治 點分樹題目集

學了這麼久的點分治 點分樹,感覺自己還是只會做點裸題 這都要國賽了感覺自己吃棗藥丸。給定一棵 n 個點的樹,每條邊有乙個邊權。接下來有 m 次操作分為以下兩種 n,m le 3 times 10 5 tl 1.5s 原題範圍 n,m le 10 5,tl 4s 原題的做法是個不太優美的根號演算法,事...

學習筆記 第九課 點分治和點分樹 動態點分治

點分治一般是用來解決樹上路徑統計的問題,而動態點分治 也稱點分樹 是用資料結構樹上路徑資訊。首先顯然的 theta n 2 log n 的列舉演算法 for int i 1 i n i 比較難優化,我們可以換一種考慮方式。以 p 為樹根,則對 p 而言,樹上的路徑可以分為兩種 1.經過 p 的路徑 ...