CF1363E. Tree Shuffling(树形dp)

原题链接

给你n个节点,根节点为1,第i个节点花费a_i,装入了数字b_i,它想要最后将数字c_i最后写入第i个节点。

你有一种操作,就是使得u节点的子树的k个节点进行交换,产生的花费为k*a_u,求最小花费

解法:考虑树形dp,题目已知1为根节点,我们可以从上往下遍历,维护一个a[i]的最小值,如果当前遍历节点的值a[i]为最小值,那么就是当前的进行修改花费是最少的,更新答案即可,注意一点更新完之后,1号节点还有剩余未匹配节点,说明无法进行交换输出-1

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
#define sc scanf
#define pr printf
#define INF 0x3f3f3f3f
const int maxn = 2e5 + 5;
vector<int>g[maxn];
ll dp[maxn][2];
struct node{
	ll a,b,c;
}a[maxn];
ll ans;
void dfs(int u, int fa, ll mn){
	mn = min(mn, a[u].a);
	for(int i = 0; i < g[u].size(); i++){
		int j = g[u][i];
		if(j == fa)continue;
		dfs(j, u, mn);
		dp[u][0] += dp[j][0];
		dp[u][1] += dp[j][1];
	}
	if(a[u].b != a[u].c){
		if(a[u].b == 1)dp[u][1]++;
		else dp[u][0]++;
	}
	if(a[u].a == mn){
		ll s = min(dp[u][0],dp[u][1]);
		ans += s*2*a[u].a;
		dp[u][1] -= s;
		dp[u][0] -= s;
	}
}
void solve(){
     int n;
     scanf("%d",&n);
     for(int i = 1; i <= n; i++){
     	scanf("%lld%lld%lld",&a[i].a,&a[i].b,&a[i].c);
	 }
	 for(int i = 1; i < n; i++){
	 	int u,v;
	 	scanf("%d%d",&u,&v);
	 	g[u].push_back(v);
	 	g[v].push_back(u);
	 }
	 dfs(1, 0, INF);
	 //如果当前交换之后根节点还有剩余的节点
	 //那么就是无法进行交换输出-1 
	 if(dp[1][1] || dp[1][0])printf("-1\n");
	 else printf("%lld\n",ans);
}
int main(){
//	freopen("2.in","r",stdin);
//	IOS; 
	int t;
	t = 1;
//	sc("%d",&t);
	while(t--)
	solve();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值