洛谷P2986 偉大的奶牛聚集

2022-08-03 02:06:13 字數 1409 閱讀 3435

給定一棵樹,樹上節點有點權、邊有邊權,求出乙個點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 2

using

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 }

ac code

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 然後問題就變成了更換這棵樹的根...