Luogu P2052 [NOI2011]道路修建

吐槽一下

我开了\(-O2\)优化结果跑的更慢了什么鬼???!!!

我怕不是吸了一口毒氧气

不要脸的放上我的博客,欢迎大家前来面基

题目大意

给定一棵有\(n\)个节点的树,树中有\({n-1}\)条边,每条边花费的价格是这条边两侧的点的数量的差的绝对值和这条边长度的积。求这棵树的总花费。

解题思路

以节点\(1\)作为这棵树的根节点,其实选哪个都可以从题中可以得出一个基本的结论,一条边的两边的点的数量分别等于终点节点儿子的数量\(+1\)和起点节点祖先的数量。我们可以通过遍历整棵树将每个节点儿子的数量预处理出来。

在预处理的同时可以进行统计。到最后输出Ans就可以

附上代码

当然不能少了代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define int long long

using namespace std;

const int maxn = 1e6+3;
int n, fir[maxn], nx[maxn<<1], u[maxn<<1], v[maxn<<1], w[maxn<<1], s[maxn], Ans;
bool vis[maxn];
inline int DFS(int x, int fr) {
    if(s[x] != 1) return s[x];
    int k = fir[x];
    while (k != -1) {
        if(fr != v[k]) {
            s[x] += DFS(v[k], x);
            Ans += abs(n-2*s[v[k]]) * w[k];
        }
        k = nx[k];
    }
    return s[x];
}

main() {
    scanf("%lld", &n);
    memset(fir, -1, sizeof(fir));
    fill(s+1, s+1+n, 1);
    for(int i=1; i<=(n-1)*2; i++) {
        scanf("%lld%lld%lld", &u[i], &v[i], &w[i]);
        nx[i] = fir[u[i]];
        fir[u[i]] = i;
        u[i+1] = v[i], v[i+1] = u[i], w[i+1] = w[i];
        i++;
        nx[i] = fir[u[i]];
        fir[u[i]] = i;
    }
    vis[1] = 1;
    DFS(1, 1);
    printf("%lld", Ans);
}
posted @ 2018-08-06 06:11  Mystical-W  阅读(162)  评论(0编辑  收藏  举报