Serval and Rooted Tree CodeForces - 1153D

http://codeforces.com/problemset/problem/1153/D

遍历到第i个节点时 假设以i为根的子树上有sum[i]个叶子节点 就只考虑1到sum[i]这些数对i节点的贡献 dp[i]即为此时的最大值

dp[i]是从其子节点转移而来 假设i是min型 min从dp[j1] dp[j2]...得来为 使min最大 就把1到sum[i]中最小的一些数都填到(dp[j1]-1)+(dp[j2]-1)...中去 这样就使得dp[j1] dp[j2]...中的最小值最大 再假设i是max型 那就尽量使dp[j1] dp[j2]...最大得最大 就找sum[j]-dp[j]最小的一个即可(sum[j]-dp[j]为子树上必须要浪费的叶节点数 越小越好)

最后输出dp[1]即可

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
const int maxn=3e5+10;

struct node
{
    int v,next;
};

node edge[maxn];
int first[maxn],type[maxn],sum[maxn],dp[maxn];
int n,num;

bool cmp(int u,int v)
{
    return u>v;
}

void addedge(int u,int v)
{
    edge[num].v=v;
    edge[num].next=first[u];
    first[u]=num++;
}

void dfsI(int cur)
{
    int i,v;
    if(first[cur]==-1) sum[cur]=1;
    for(i=first[cur];i!=-1;i=edge[i].next){
        v=edge[i].v;
        dfsI(v);
        sum[cur]+=sum[v];
    }
}

void dfsII(int cur)
{
    int i,v,tot,minn;
    if(first[cur]==-1){
        dp[cur]=1;
        return;
    }
    if(type[cur]==0) tot=0;
    else minn=sum[cur];
    for(i=first[cur];i!=-1;i=edge[i].next){
        v=edge[i].v;
        dfsII(v);
        if(type[cur]==0) tot+=dp[v]-1;
        else minn=min(minn,sum[v]-dp[v]);
    }
    if(type[cur]==0) dp[cur]=tot+1;
    else dp[cur]=sum[cur]-minn;
}

int main()
{
    int i,j,f,tmp,cnt;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%d",&type[i]);
    }
    memset(first,-1,sizeof(first));
    num=0;
    for(i=2;i<=n;i++){
        scanf("%d",&f);
        addedge(f,i);
    }
    dfsI(1);
    dfsII(1);
    printf("%d\n",dp[1]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sunyutian1998/article/details/89469885