[HEOI2015]兔子与樱花

[HEOI2015]兔子与樱花

题面

链接

题解

由题:定义一个节点x对其父节点的贡献为 c[x] + son[x]

考虑贪心:从底向上贪心,每次将子节点按贡献从小到大的顺序删掉所有能删的

可以证明一定不会有更优的情况

首先显然对于一个节点的子节点肯定尽量选小的更优

所以只需要证明是否尽量把能选的选完就是最优的

假设不是,即如果选完了这个点的子节点后,这个点不能再被删

可以发现当这个点选的在多对于上一层只会影响一个答案,而这一层选了后对答案的影响一定不小于1

故贪心正确

#include<bits/stdc++.h>

using namespace std;

#define LL long long

inline LL read()
{
    LL f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f=-1;
    }while(ch<'0'||ch>'9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch>='0'&&ch<='9');
    return f*x;
}

const int MAXN = 2000000 + 10;

int n,m;
int c[MAXN];
vector<int>ve[MAXN];
int ans = 0;
int son[MAXN];

inline bool cmp(int a,int b)
{
    return c[a] + son[a] < c[b] + son[b]; 
}

inline void dfs(int x)
{
    for(int i=0;i<ve[x].size();i++)
    {
        int v = ve[x][i];
        dfs(v);
        son[x] ++;
    }
    sort(ve[x].begin(),ve[x].end(),cmp);
    for(int i=0;i<ve[x].size();i++)
    {
        int v = ve[x][i];
        if(c[x]+son[x]+c[v]+son[v]-1<=m)
        {
            ans++;
            c[x]+=c[v];
            son[x]+=son[v]-1;
        }
        else break;
    }
}

int main()
{
    n = read(),m = read();
    for(int i=1;i<=n;i++) c[i] = read();
    for(int i=1;i<=n;i++)
    {
        int k = read();
        for(int j=1;j<=k;j++)
        {
            int x = read() + 1;
            ve[i].push_back(x);
        }
    }
    dfs(1);
    cout<<ans<<endl;
}

 

posted @ 2019-10-22 23:57  wlzs1432  阅读(110)  评论(0编辑  收藏  举报