题意:
给出一棵树,每个点有三个值 a , b , c a,b,c a,b,c ,分别代表权值,当前的值,希望变成的值, b , c b,c b,c为0或1。
每次操作可以选择一个以 u u u根的子树,然后选择k个点, k k k任意,然后将这些点的 b b b值重排列,花费为 k × a [ u ] k \times a[u] k×a[u]
求最后所有点满足b都变为 c c c 的最小花费。
题解:
设 d p [ u ] [ 0 ] dp[u][0] dp[u][0] 表示以 u u u为根的子树内,有多少个点满足 b = 0 , c = 1 b=0,c=1 b=0,c=1 , d p [ u ] [ 1 ] dp[u][1] dp[u][1] 同理
那么当我们要对 u u u 的子树进行操作时,如果其某个祖先的花费小于 u u u ,那么其实可以选择祖先来进行操作
所以如果存在祖先的花费小,我们可以将 u u u的花费更改为祖先的花费。
再考虑重排列,对于一个点,只能选择 2 × m i n ( d p [ u ] [ 1 ] , d p [ u ] [ 0 ] ) 2 \times min(dp[u][1],dp[u][0]) 2×min(dp[u][1],dp[u][0]) 个点重排列,那么花费自然也就能算出来。
最后,因为每条链的操作其实是独立的,所以不用考虑当前点操作后,会对其他链上的点产生影响。
代码:
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=2e5+5;
const int inf=0x3f3f3f3f;
vector<int> g[MAXN];
int dp[MAXN][2];
int a[MAXN], b[MAXN], c[MAXN];
ll ans = 0;
void dfs(int u,int f)
{
if(u!=1)
a[u] = min(a[u], a[f]);
dp[u][b[u]] += (b[u] != c[u]);
for(auto v:g[u])
{
if(v==f)
continue;
dfs(v, u);
dp[u][1] += dp[v][1];
dp[u][0] += dp[v][0];
}
int mi = min(dp[u][1], dp[u][0]);
ans += 1ll * mi*2 * a[u];
dp[u][1] -= mi;
dp[u][0] -= mi;
}
int main()
{
int n;
cin >> n;
int cnt0 = 0, cnt1 = 0;
for (int i = 1; i <= n;i++){
cin >> a[i] >> b[i] >> c[i];
if(b[i]==1)
cnt0++;
if(c[i]==1)
cnt1++;
}
for (int i = 1; i <= n - 1;i++){
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
if(cnt0!=cnt1){
cout << -1 << endl;
return 0;
}
dfs(1,0);
cout << ans << endl;
}