大致步驟
換根dp 大致步驟
方法一:(up陣列)
(1) g[i] 以i為根的子樹(不是整棵樹),由孩子節點推過來
(2) up[i] i節點往上走的最大屬性
(3) f[i] 整棵樹(不是子樹) 記錄一些值
方法二:加減法
(1) g[i] 以i為根的子樹(不是整棵樹),由孩子節點推過來
(2) f[i] 整棵樹(不是子樹) 記錄一些值(透過加減法,用g陣列計算f陣列)
這就是一些通用套路了,下面會詳細講解如何使用
深度最大(方法一)
給定一個 n 個點的樹,請求出一個結點,使得以這個結點為根時,該樹深度最大。深度定義為葉子節點到根的簡單路徑上邊的數量最大值。1≤n≤1e6,1≤u,v≤n
輸入格式
第一行有一個整數,表示樹的結點個數 n。
接下來 (n−1) 行,每行兩個整數 u,v,表示存在一條連線 u,v 的邊。
輸出格式
輸出一行一個整數表示你選擇的結點編號。如果有多個結點符合要求,輸出節點編號最小值。
輸入/輸出例子1
輸入:
2
1 2
輸出:
1
樣例解釋
無
例題1(換根1:up陣列)
g(i, 0/1):以i為根的子樹,0:次大深度,1:最大深度
通常記錄最大的情況下,要記錄次大值
第一步. O(n)
如何更新次大值,最大值?
假設v是i的子樹,子推父
1) if (g[v][1]+w >= g[i][1])
g[i][0]=f[i][1], g[i][1]=g[v][1]+w //注意順序,先更新最大值,再更新次大值
son[i]=v //後面解釋
2) if (g[v][1]+w<f[i][1])
g[i][0]=max(g[i][0], g[v][1]+w)
3) 最重要的陣列:
son[i] 以i為根的子樹,是哪個兒子給i最大貢獻
第二步. O(n)
怎麼更新up陣列?
up[root]=0
父推子,假設i是u的孩子,i-u直接相連的邊權值為w
分情況,u往上走,u往下走
1) up[i]=max(w+up[u], up[i])
u往下走的最遠距離,是不是i往上能走到的?那不就是最遠距離了嗎,但是要注意u走過的路徑不能和i重疊,不然i就變成往下走了,所以如果重疊,換次長路,這是肯定不會經過i
2) if (son[u]==i) up[i]=max(up[i], w+g[u][0])
else up[i]=max(up[i], w+g[u][1])
第三步
f[i]=max(g[i][1], up[i])
ans=max(ans, f[i])