1. 程式人生 > 其它 >點分樹學習筆記

點分樹學習筆記

關於點分樹的一些理解

定義與性質

點分樹,就是把點分治中的每一次的重心連起來,構成一棵樹。
由於重心的性質,點分治最多有 \(\lg n\) 層, 所以點分樹的樹高最多是 \(\lg n\)

維護

一般維護兩個值 \(s1\)\(s2\)\(s1\) 表示這個點的子樹對於這個點的貢獻, \(s2\) 表示這個點的子樹對於這個點的父親的貢獻。\(s2\) 用於對 \(s1\) 進行容斥

每次修改時要在點分樹上不斷跳父親,修改點分樹上父親的資訊。

每次查詢時要在點分樹上不斷跳父親,詢問點分樹上父親的資訊,一般要用到容斥。用 \(s2\) 容斥 \(s1\)

具體看了題就理解了。

用途

一般用於靜態條件下點分治可解,但是強制線上或帶修的題。

注意事項

點分樹上的位置關係,距離關係,父子關係,祖孫關係,和原樹上不同。

luogu6329震波

標籤

點分治, 樹狀陣列

思路

先考慮不帶修的情況,那這就是道點分治裸題,但是這道題要求支援修改且強制線上。那麼點分治就不能用了。

所以我們要用點分樹。

對於每一個節點維護兩棵樹狀陣列 (\(vector\) 存) , \(s1\) 維護距離當前點距離為 \(k\) 的點的價值和, \(s2\) 維護距離當前點的點分樹上的父親距離為 \(k\) 的點的價值和。

對於修改操作,改成增加,然後在點分樹上不斷跳父親,修改 \(s1\)\(s2\)

對於查詢操作,在點分樹上不斷跳父親,設詢問點和父親的距離為 \(d\)

, 那麼對於每一層,把答案加上 \(s1[fa[i]].query(k - d) - s2[i].query(k - d)\) 用於去重,因為當前子樹已經被計算過了。

維護兩棵樹狀陣列多麻煩啊,直接 \(s1[fa[i]].query(k - d) - s1[i].query(k - d - dis(i, fa[i]))\) 或者 \(s1[fa[i]].query(k - d) - s1[i].query(k - dis(i, x))\) 多方便,然而要注意 點分樹上的位置關係,距離關係,父子關係,祖孫關係,和原樹上不同。 所以這樣做是錯誤的。

Code

[ZJOI2007]捉迷藏