1. 程式人生 > >noip模擬賽 蒜頭君的樹

noip模擬賽 蒜頭君的樹

max n) amp ios clas 分析 alt string 統計

技術分享

技術分享

技術分享

分析:這道題問的是樹上整體的答案,當然要從整體上去考慮.

一條邊對答案的貢獻是這條邊一端連接的點的個數*另一端連接的點的個數*邊權,可以用一次dfs來統計答案,之後每次更改操作在原答案的基礎上增減就好了.

千萬不要傻傻地去求LCA......事實證明只有10分.問的是任意兩點最短距離之和,樹上兩個點的最短路徑只有一條,所以才要去考慮每條邊的貢獻的.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace
std; const int maxn = 100010; long long n, head[maxn], nextt[maxn * 2], tot = 1, to[maxn * 2], w[maxn * 2], num[maxn], fa[maxn], d[maxn], m; long long ans; void add(long long x, long long y, long long z) { to[tot] = y; w[tot] = z; nextt[tot] = head[x]; head[x] = tot++; } void dfs(long
long u, long long fa) { for (int i = head[u]; i; i = nextt[i]) { int v = to[i]; if (v != fa) { dfs(v, u); num[u] += num[v]; ans += w[i] * num[v] * (n - num[v]); } } num[u]++; } int main() { scanf("%lld", &n);
for (int i = 2; i <= n; i++) { long long x, y; scanf("%lld%lld", &x, &y); fa[i] = x; d[i] = y; add(x, i, y); } dfs(1, fa[1]); printf("%lld\n", ans); scanf("%lld", &m); for (int i = 1; i <= m; i++) { long long a, b; scanf("%lld%lld", &a, &b); ans += num[a] * (n - num[a]) * (b - d[a]); printf("%lld\n", ans); d[a] = b; } return 0; }

noip模擬賽 蒜頭君的樹