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
", 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
", ans);
        d[a] = b;
    }

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/7596498.html