HDU 5886 Tower Defence(2016青島網絡賽 I題,樹的直徑 + DP)
阿新 • • 發佈:2018-02-25
printf true IT spa clear 期望 post const href
題目鏈接 2016 Qingdao Online Problem I
題意 在一棵給定的樹上刪掉一條邊,求剩下兩棵樹的樹的直徑中較長那的那個長度的期望,答案乘上$n-1$後輸出。
先把原來那棵樹的直徑求出來。顯然刪掉的邊不是這條直徑上的邊,那麽這時答案就是這條直徑的長度。
否則就是直徑的某個端點到某一個點(要求連通)的距離的最大值。
在整條鏈上做兩次$DP$之後枚舉取較大值即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define fi first #define se second typedef long long LL; const int N = 100010; vector <pair<int, LL > > v[N]; int T, n, L, R, x, cnt; int a[N], f[N], father[N]; LL b[N], c[N], s[N], cl[N], cr[N], c1, c2, num, ans = 0; void dfs1(int x, int fa, LL now){ if (now > c1){ c1 = now; L = x; } for (auto node : v[x]){ int u = node.fi; LL w = node.se; if (u == fa) continue; dfs1(u, x, now + w); } } void dfs2(int x, int fa, LL now){ father[x] = fa; s[x] = now; if (now > c2){ c2 = now; R = x; } for (auto node : v[x]){ int u = node.fi; LL w = node.se; if (u == fa) continue; dfs2(u, x, now + w); } } void dfs3(int w, int x, LL now){ f[x] = 1; c[w] = max(c[w], now); for (auto node : v[x]){ int u = node.fi; if (f[u]) continue; dfs3(w, u, now + node.se); } } int main(){ for (scanf("%d", &T); T--; ){ scanf("%d", &n); rep(i, 0, n + 1) v[i].clear(); rep(i, 2, n){ int x, y; LL z; scanf("%d%d%lld", &x, &y, &z); v[x].push_back({y, z}); v[y].push_back({x, z}); } L = -1; c1 = -1; dfs1(1, 0, 0); R = -1, c2 = -1; memset(father, 0, sizeof father); dfs2(L, 0, 0); x = R; cnt = 0; while (true){ a[++cnt] = R; R = father[R]; if (R == 0) break; } rep(i, 1, cnt) b[i] = s[a[i]]; reverse(a + 1, a + cnt + 1); reverse(b + 1, b + cnt + 1); num = b[cnt]; ans = num * (n - cnt); memset(f, 0, sizeof f); rep(i, 1, cnt) f[a[i]] = 1; rep(i, 1, cnt){ c[i] = 0; dfs3(i, a[i], 0); } cl[1] = b[1]; rep(i, 2, cnt) cl[i] = max(cl[i - 1], b[i] + c[i]); cr[cnt] = 0; dec(i, cnt - 1, 1) cr[i] = max(cr[i + 1], b[cnt] - b[i] + c[i]); rep(i, 1, cnt - 1) ans = ans + max(cl[i], cr[i + 1]); printf("%lld\n", ans); } return 0; }
HDU 5886 Tower Defence(2016青島網絡賽 I題,樹的直徑 + DP)