noip模拟赛 蒜头君的树
分析:这道题问的是树上整体的答案,当然要从整体上去考虑.
一条边对答案的贡献是这条边一端连接的点的个数*另一端连接的点的个数*边权,可以用一次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; }