题目链接:https://codeforces.com/contest/1363/problem/E
题意
有一棵 $n$ 个结点,根为结点 $1$ 的树,每个结点有一个选取代价 $a_i$,当前 $b_i$,目标数字 $c_i$ 。每次可以选择以一个结点为根节点的子树中的 $k$ 个结点交换它们的 $b_i$,总代价为 $k imes a_{root}$ ,判断能否把所有结点都变为目标数字以及最小代价。
题解
因为每棵子树都可以被包含进更大的子树中,所以对于每棵子树的根节点,它的最小选取代价可以取它自身和所有可能的父节点的最小值。
计算每棵子树中需要交换的 $0$ 和 $1$ 的个数,用根节点的最小选取代价交换后,多余的 $0$ 或 $1$ 累加至父节点所在的子树即可。
代码
#include <bits/stdc++.h> using ll = long long; using namespace std; const int N = 2e5 + 10; vector<int> G[N]; int a[N], b[N], c[N]; int cnt[N][2]; ll ans; void dfs(int u, int pre) { if (pre != 0) a[u] = min(a[u], a[pre]); for (auto v : G[u]) { if (v != pre) { dfs(v, u); cnt[u][0] += cnt[v][0]; cnt[u][1] += cnt[v][1]; } } if (b[u] != c[u]) cnt[u][b[u]]++; int mi = min(cnt[u][0], cnt[u][1]); ans += 2LL * mi * a[u]; cnt[u][0] -= mi; cnt[u][1] -= mi; } int main() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i] >> b[i] >> c[i]; for (int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; G[u].push_back(v); G[v].push_back(u); } dfs(1, 0); cout << ((cnt[1][0] or cnt[1][1]) ? -1 : ans) << " "; }