給定一棵樹,樹上節點有點權、邊有邊權,求出乙個點ans,使得cost最小,其中$cost=\sum\limits_^$
樹形dp
依舊是通過兩次dfs解決
核心思想還是「二次掃瞄與換根法」(名詞出自lyd《演算法競賽高階指南》)
我們假定1為根並且第一遍dfs求出當ans位於1時的代價dis
顯然存在$dis[i]=\sum\limits_$,其中tot[j]表示以j為根的子樹中的節點的點權之和
那麼我們再進行一遍dfs實現「換根」
假設當前節點為i,並且i的父親已經正確計算,我們記ans位於其父親時的代價為$f[fa]$,那麼我們考慮怎樣通過$f[fa]$求出$f[i]$
$f[fa]$包括兩部分:以i為根的子樹的代價和其餘部分。那麼我們先將$f[fa]$減去i為根的子樹的代價,然後加上i為根的子樹走到i的代價,再加上剩餘部分走到i的代價即可
詳細實現見**。
時間複雜度為$o(n)$
1 #include 2ac codeusing
namespace
std;
3 typedef long
long
ll;4
const
int maxn = 100010
;5 inline int
read()
12while
(isdigit(c))
16return ret *op;17}
18struct
node a[maxn << 1
];21
intnum, head[maxn], n, val[maxn];
22ll tot[maxn], dis[maxn], f[maxn];
23ll sum;
24 inline void add(int
from, int to, int
dis)
30 ll dfs(int now, int
fa)
38return tot[now] = tot[now] +val[now];39}
40void dp(int now, int
fa) 47}
48int
main()
55 dfs(1, 1
);56 f[1] = dis[1
];57 dp(1, 1
);58 ll ans =9223372036854775806ll;
59for (register int i = 1; i <= n; ++i) ans =min(ans, f[i]);
60 printf("
%lld\n
", ans);
61return0;
62 }
Luogu 2986 偉大的奶牛聚集
題目描述 bessie正在計畫一年一度的奶牛大集會,來自全國各地的奶牛將來參加這一次集會。當然,她會選擇最方便的地點來舉辦這次集會。每個奶牛居住在 n 1 n 100,000 個農場中的乙個,這些農場由n 1條道路連線,並且從任意乙個農場都能夠到達另外乙個農場。道路i連線農場a i和b i 1 a ...
P2986 USACO10MAR 偉大的奶牛聚集
題意 給一棵 n 個點的邊 點權樹,求帶權重 思路 其實這題和之前那個 sta 有點像,我們同樣只需要預處理出乙個f u 代表以 u 為集合點的方便程度,那麼我們就可以o 1 的轉移了 假設 v 是 u 的兒子,f v f u siz v len n siz v len f u n 2 siz v ...
USACO10MAR 偉大的奶牛聚集
因為是英文題,題目不再重複。給你一棵無根樹,每條邊有邊權,每個點有點權,要你選乙個點,使每個點到這個點的距離 點權的和最小,求這個值。設dis u 為u所有後代到它的距離 點權,sum u 為u所有後代的點權和包括u 先以1為根dfs一遍,預處理出所有的dis,sum 然後問題就變成了更換這棵樹的根...