CF-1363E Tree Shuffling【树上贪心】

题意:

给出一棵 \(n\)个节点的树,每个节点有三个值:\(a[i],b[i],c[i]\),分别为该点的花费,该点的当前状态,该点的目标状态。
每次可以选择点 \(u\) 的子树中的 \(k\) 个点,将它们的当前状态进行重新排序,使之达到目标状态,花费为 \(k*a[u]\)。求出最小的花费,使得所有的点达到目标状态。
数距范围:\(1≤n≤2⋅10^5,1≤a_i≤10^9,0≤b_i,c_i≤1\)

分析:

把最小值按路径从上到下传递下去,如果当前点的花费不大于祖先中的最小花费,那么可以以该点为根进行处理。

代码:

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int inf=0x3f3f3f3f;
vector<int>pic[N];
int a[N],b[N],c[N],num[N][2];
int n;
ll ans;
void dfs(int v,int p,int minn)
{
    if(b[v]!=c[v])
    {
        if(b[v]==0) num[v][0]++;
        else num[v][1]++;
    }
    for(int i=0;i<pic[v].size();i++)
    {
        int u=pic[v][i];
        if(u==p) continue;
        dfs(u,v,min(minn,a[v]));
        num[v][0]+=num[u][0];
        num[v][1]+=num[u][1];
    }
    if(minn>=a[v])//保证贪心
    {
        int t=min(num[v][0],num[v][1]);
        ans+=2LL*t*a[v];
        num[v][0]-=t;
        num[v][1]-=t;
    }
}
int main()
{
    int u,v;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        pic[u].pb(v);
        pic[v].pb(u);
    }
    ans=0;
    dfs(1,0,inf);
    if(num[1][0]||num[1][1])
        printf("-1\n");
    else
        printf("%lld\n",ans);
    return 0;
}

posted @ 2020-06-03 17:24  xzx9  阅读(261)  评论(0编辑  收藏  举报