Codeforces1363E Tree Shuffling
补上一发被吞了的博客 ˋ(′~‘)ˊ
题目链接
https://codeforces.com/contest/1363/problem/E
题目大意
给你一颗包含 N 个节点以节点 1 为根的树 , 每个节点有它的成本 a , 初始状态 b 和最终状态 c (只有0、1两种状态)
现在你可以从任意节点 u 的子树中选择任意 k 个节点 , 并可以随意排列这些节点的数字 , 产生的代价为 k * au
问要让所有节点都达到最终状态的最小代价是多少
解题思路
对于一个节点 , 如果要将它的状态改变 , 则它可以在自己的轮次改变也可以在祖先的轮次改变
所以改变它的状态的代价为 min ( 它自己的成本 , 它祖先的成本 )
那么假设根节点位于顶层 , 根据贪心思想 , 节点要尽可能在底层改变状态
倘若当前节点为 u , 要在 u 的轮次进行状态重新排列,那么可以到最终状态的节点个数为 2 * min(dp[u][0] , dp[u][1])
其中 dp[u][0] 表示 u 的子树中初态为 0 , 且还未达到终态的节点个数 , dp[u][1] 表示 u 的子树中初态为 1 , 且还未达到终态的节点个数
那么 u 的轮次产生的代价就为 min(dp[u][0] , dp[u][1]) * 2 * min(u 的成本 , u 祖先的成本) , 剩余无法在 u 的轮次达到终态的节点向上传递
写也很好写,在 dfs 的时候带一个 cost 参数表示所有祖先中的最小成本,然后 dfs 到叶子节点后再从下往上更新答案即可
AC_Code
#include<bits/stdc++.h> using namespace std; const int N = 2e5 + 10; vector<int>G[N]; int n , dp[N][2]; long long ans; struct node{ int a , b , c; }x[N]; void dfs(int u , int far , int cost) { if(x[u].b != x[u].c) dp[u][x[u].b] = 1; for(auto v : G[u]) { if(v == far) continue ; dfs(v , u , min(x[u].a , cost)); dp[u][0] += dp[v][0]; dp[u][1] += dp[v][1]; } cost = min(cost , x[u].a); int cnt = min(dp[u][0] , dp[u][1]); ans += 2ll * cnt * cost; dp[u][0] -= cnt , dp[u][1] -= cnt; } signed main() { ios::sync_with_stdio(false); cin >> n; for(int i = 1 ; i <= n ; i ++) cin >> x[i].a >>x[i].b >> x[i].c; for(int i = 1 ; i < n ; i ++) { int u , v; cin >> u >> v; G[u].push_back(v) , G[v].push_back(u); } dfs(1 , -1 , 0x3f3f3f3f); if(dp[1][0] || dp[1][1]) ans = -1; cout << ans << '\n'; return 0; }
凡所不能将我击倒的,都将使我更加强大