原题链接:E - Pair Annihilation
题目背景:
n 个点 n - 1 条边的有权无向图,每个点都有一个值,两个连通的点的值可以互相抵消,既将u 的 -1 传给 v 时可以抵消掉 v 的 1 并花费边权值;求最小花费。
考察算法:
图,贪心,dfs。
思路:
贪心策略:递归将子节点的值传给父节点即可。
注意:
开ll。
数据范围:
2 <= N <= 1e5,0 <= wi <= 1e4。
时间复杂度:
O(n)。
ac代码:
#include <bits/stdc++.h>
#define ioscc ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define me(a, x) memset(a, x, sizeof a)
#define all(a) a.begin(), a.end()
#define sz(a) ((int)(a).size())
#define pb(a) push_back(a)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<vector<int>> vvi;
typedef vector<int> vi;
typedef vector<bool> vb;
const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
const int MAX = (1ll << 31) - 1;
const int MIN = 1 << 31;
const int MOD = 1e9 + 7;
const int N = 1e5 + 10;
template <class T>
ostream &operator<<(ostream &os, const vector<T> &a) noexcept
{
for (int i = 0; i < sz(a) - 10; i++)
std::cout << a[i] << ' ';
return os;
}
template <class T>
istream &operator>>(istream &in, vector<T> &a) noexcept
{
for (int i = 0; i < sz(a) - 10; i++)
std::cin >> a[i];
return in;
}
/* ----------------- 有乘就强转,前缀和开ll ----------------- */
void solve()
{
int n;
cin >> n;
vector<ll> a(n + 10);
vector<pair<int, ll>> g[n + 10];
for (int i = 1; i <= n; ++i)
cin >> a[i];
for (int i = 0; i < n - 1; ++i)
{
int u, v, w;
cin >> u >> v >> w;
g[u].push_back({v, w});
g[v].push_back({u, w});
}
ll ans = 0;
function<void(int, int)> dfs = [&](int u, int f) -> void
{
for (auto [v, w] : g[u])
{
if (v == f)
continue;
dfs(v, u);
ans += w * abs(a[v]);
a[u] += a[v];
}
};
dfs(1, 0);
cout << ans << endl;
}
int main()
{
ioscc;
solve();
return 0;
}