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;
}
posted @ 2020-06-02 17:45  GsjzTle  阅读(201)  评论(0编辑  收藏  举报