AT_abc409_e 题解

题目传送门
[洛谷]
Atcoder

题面:

你会获得一个带有n个顶点的树,这些顶点被标号为1到n,边也被标号为1到n-1 ,第j条边连接着vi和vj,权值为wi,并且每个顶点也有一个数字xi, 如果xi > 0 那么有xi个正电子在这个顶点上,如果xi < 0 那么有-xi个负电子在这个顶点上, 如果xi == 0 那么说明这个顶点上什么都没有。题目保证所有xi的和=0

你需要移动一些电子,当一个电子移动过了j号边,那么就需要wj的能量。当a个正电子和b个负电子相遇时,会有min(a, b) 个正电子和min(a, b)个负电子消失。 你的目标是使所有的电子全部消失,求最少需要的能量。

题目思路:

当我们思考这道题是,会发现下面这个重要的推论。
很明显:当一条边的两侧需要抵消掉一部分时,当然是将靠边的移向靠中间的,否则其他电子就需要更多能量过来。
有了这个就可以从边缘向中间 BFS 并依次向中间合并。
所以这道题可以用 BFS , 先用f数组对每个节点的度数进行统计,再将每一个度为1的点(最靠边的点)放入队列。从周围向中间合并。每次有ai个从vj节点到uj节点的时候就会产生|ai*wj|, 注意:这里需要使用绝对值,因为ai可能为负数(那并不代表有负数个电子,那代表的是|ai|个负电子)。
还有就是在BFS时,当一条边的两侧的电子合并完成,那么此时必有一端到一个边缘点为空,那么就可以将这一段舍去(即代码中的f[t]--)
在 BFS 时,还可以将f数组重复利用,当我们处理过fi时,就可以将fi设为0,因为处理过之后fi就没有别的用处了。

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#define int long long
using namespace std;
int a[100001];
int f[100001];
vector<pair<int, int> > graph[100001];
signed main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 1; i < n; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        graph[u].push_back( { v, w } );
        graph[v].push_back( { u, w } );
        f[u]++;  // 统计度数
        f[v]++;  // 统计度数
    }
    queue<int> q;
    for (int i = 1; i <= n; i++)
    {
        if (f[i] == 1)
        {
            q.push(i); // 将边缘点放入q
        }
    }
    int ans = 0;
    while (!q.empty())
    {
        int p = q.front();
        q.pop();
        f[p] = 0; // 重复利用
        for (pair<int, int> pii : graph[p])
        {
            int t = pii.first;
            int w = pii.second;
            if (!f[t]) // 重复利用
            {
                continue;
            }
            f[t]--; // 舍去该无用边
            ans += abs(a[p] * w); // 计算本次能量消耗(注意绝对值哦)
            a[t] += a[p]; // 正+负正好抵消掉一部分正和一部分负
            if (f[t] == 1) // 此时f[t]成为了的边缘点(与他连接的f[p]被割了)
            {
                q.push(t); // 将新的边缘点放入q
            }
        }
    }
    cout << ans << endl;
    return 0;
}
posted @ 2025-06-15 00:17  MichaelZeng  阅读(14)  评论(0)    收藏  举报