[JZOJ5776]【NOIP2008模擬】小x遊世界樹
阿新 • • 發佈:2018-08-14
+= 不一定 truct 一行 自己 平臺 更新 return print
考慮不換根怎麽做, 那麽每條邊經過的次數就是它的子樹大小。
如果換根, 那麽考慮root的兒子x, 它的答案中只有root到x的邊的貢獻發生變化了。
發生的變化是減去root到x的貢獻, 加上x到root的貢獻。
於是求出root為1的答案, 然後再換根, 這樣統計答案是O(1)的, 總共是O(N)的。
註意更新的順序一定要按照dfs順序, 還要開Long long.
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <map> #define int long long using namespace std; inline int read() { int res=0;char c=getchar();bool f=0; while(!isdigit(c)) {if(c==‘-‘)f=1;c=getchar();} while(isdigit(c))res=(res<<3)+(res<<1)+(c^48),c=getchar(); return f?-res:res; } #define reg register #define N 700005 int n; struct edge { int nxt, to, val; }ed[N*2]; int head[N], cnt; int ine[N]; inline void add(int x, int y, int z) { ed[++cnt] = (edge){head[x], y, z}; head[x] = cnt; } int a[N], siz[N], fat[N]; int ans, root = 1, res; int f[N]; void dfs(int x, int fa) { siz[x] = 1; for (reg int i = head[x] ; i ; i = ed[i].nxt) { int to = ed[i].to; if (to == fa) continue; fat[to] = x; ine[to] = i; dfs(to, x); siz[x] += siz[to]; } } int efs(int x, int fa, int in) { int sum = 0; for (reg int i = head[x] ; i ; i = ed[i].nxt) { int to = ed[i].to; if (to == fa) continue; sum += efs(to, x, i); } sum += siz[x] * (ed[in].val - a[fa]); return sum; } void ffs(int x, int fa, int in) { if (x != 1) f[x] = f[fa] - (siz[x] * (ed[in].val - a[fa])) + (n - siz[x]) * (ed[in].val - a[x]); for (reg int i = head[x] ; i ; i = ed[i].nxt) { int to = ed[i].to; if (to == fa) continue; ffs(to, x, i); } } signed main() { freopen("yggdrasil.in", "r", stdin); freopen("yggdrasil.out", "w", stdout); n = read(); for (reg int i = 1 ; i <= n ; i ++) a[i] = read(); for (reg int i = 1 ; i < n ; i ++) { int x = read(), y = read(), z = read(); add(x, y, z);add(y, x, z); } dfs(1, 0); res = efs(1, 0, 0); ans = res; f[1] = ans; ffs(1, 0, 0); for (reg int i = 2 ; i <= n ; i ++) if (f[i] < ans) {ans = f[i], root = i;} printf("%lld\n%lld\n", root, ans); return 0; }
[JZOJ5776]【NOIP2008模擬】小x遊世界樹