codeforces 1053D 树形DP

题意:给一颗树,1为根节点,有两种节点,min或者max,min节点的值是它的子节点的值中最小的,max节点的值是它的子节点的值中最大的,若共有k个叶子,叶子的值依次为1~k。

问给每个叶子的值赋为几使根节点的值最大。

思路:设\(dp[x]\)为节点x为根的子树中x的最大值,\(sz[x]\)
为节点x的子树中叶子的个数,可以推出x在它的子树中能选的叶子数量即为以x为根的子树中x的最大值。

若x为max节点,\(dp[x]=max(sz[x]-sz[y]+dp[y])\),y是x的子节点,意思是当选择y作为最大值时,x还能再多选\(sz[x]-sz[y]\)个叶子。

若x为min节点,先加上所有的\(sz[y]-dp[y]\),既y的子树中不能选的叶子个数,若x有z个子树,则有z-1个叶子不能选,

所以,\(dp[x]=sz[x]-\sum (sz[y]-dp[y])-z+1\)

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define bug cout<<"--------------"<<endl
    using namespace std;
    typedef long long ll;
    const double PI=acos(-1.0);
    const double eps=1e-6;
    const int inf=1e9;
    const int mod=1e9+7;
    const int maxn=3e5+10;
    int dp[maxn],sz[maxn];
    vector<int>f[maxn];
    int p[maxn];
    int n;
    void dfs(int u)
    {
        if(f[u].size()==0){
            dp[u]=1;
            sz[u]=1;
            return;
        }
        int tmp=0;
        for(int x:f[u]){
            dfs(x);
            sz[u]+=sz[x];
        }
        for(int x:f[u]){
            if(p[u]) tmp=max(tmp,sz[u]-sz[x]+dp[x]);
            else tmp+=sz[x]-dp[x];
        }
        if(p[u]) dp[u]=tmp;
        else dp[u]=sz[u]-tmp-f[u].size()+1;
    }
    int main(){
        ios::sync_with_stdio(false);
        //freopen("in","r",stdin);
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>p[i];
        }
        for(int i=2,x;i<=n;i++){
            cin>>x;
            f[x].push_back(i);
        }
        dfs(1);
        cout<<dp[1]<<endl;
        return 0;
    }
全部评论

相关推荐

过往烟沉:我说什么来着,java就业面就是广!
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务