用線段樹維護樹的直徑

2021-07-17 03:42:54 字數 861 閱讀 9072

有時候我們需要快速回答一棵子樹的直徑,或者去掉一棵子樹後形成的樹的直徑。普通的找直徑方法是兩遍bfs,時間o(n),這裡的方法用o(log)的時間回答。

我們做出一棵樹的dfs序,然後以dfs序為軸建立線段樹,每個區間維護直徑 len,以及直徑的兩個端點 x 和 y。

會有這麼乙個問題:你按線段樹劃分區間,那乙個區間內的點可能不連通啊!!!其實沒問題的,因為我們最後詢問的是一棵(子)樹,意思是我們詢問的東西肯定是連通的。所以操作時候不聯通你就當它連通就好啦。

還會有這麼乙個問題:直徑可能不止一條啊!!!隨便記錄一條即可,下文解釋。

區間內只有1個點的時候 len=0,x、y 等於自己。

現在考慮區間的合併。左區間有兩個直徑端點,右區間也有兩個直徑端點,這四個點中的最遠點對,就是新區間的直徑。

注意我們這裡用的距離是原樹的距離(已經說過我們強行讓乙個區間的點是連通的了)。

簡單證明一下。

我們看作是 x 所在的連通塊通過邊(x, y)連向 y 所在的連通塊。

若新直徑不經過(x, y),則就是原來的兩條直徑取 max。

若新直徑經過(x, y),就要考慮 x 延伸到哪兒、y 延伸到哪兒了。由直徑的定義可知,x 能走到的最遠點之一是 x 所在連通塊直徑的端點,y 同理。因此這時新直徑的兩個端點都是舊直徑的端點。

(這個證明也適用於增量法求樹的直徑,即我給一棵樹加乙個新點,那麼新直徑必有一端點是舊直徑的端點)

(注意只能是樹,普通圖沒有這些性質)

有了這個神奇的合併操作,我們就可以求樹中任意乙個聯通塊(子樹或是去掉乙個子樹什麼的)的直徑啦!

我們求點對距離時會用到lca,然而線段樹已經有乙個log了,如果你碰到題目要卡兩個log,請用rmq求lca。

例題1例題2

題解 城鎮 維護樹的直徑

完全沒有時間想這道題,碼了個暴力還忘記清空陣列了。方法其實很簡單,跟以前考的一道題類似。首先把樹建處理出倍增祖先陣列,然後對每個聯通塊維護它的直徑的端點。合併兩個聯通塊時新的直徑的端點一定是這兩個聯通塊的4個端點中的兩個。那麼可以暴力列舉是哪兩個即可。author galaxy yr lang c ...

線段樹求樹的直徑

線段樹求直徑可以求任意子樹 包括連子樹都不算的分散節點集合 的直徑,適用範圍廣。線段樹的每個節點所對應的區間 l,r 指代了 dfn 在 l,r 內節點,其中線段樹上每個節點儲存了 diam 當前區間直徑 及 lp,rp 當前直徑對應的左右端點 每次 merge 操作分為全左區間 全右區間和橫跨兩個...

線段樹 維護序列

老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。有長為 n 的數列,不妨設為 a1,a2,an。有如下三種操作形式 把數列中的一段數全部乘乙個值 把數列中的一段數全部加乙個值 詢問數列中的一段數的和,由於答案可能很大,你只需輸出這個數模 p 的值。輸入格式 第一行兩個整數 n 和 p ...