cf1153D 树形dp+思维

一千八的题也不会做了呜呜呜

size[u]表示结点u下的叶子结点,

思维:可以想到一个子树对其父亲会有一个消耗值

   考虑一个点如果是max,那么其最大值可以是size[u]-p,p是消耗值最小的子树

   一个点如果是min,那么其最大值是size[u]-所有子树的消耗值之和

那么dp[u]表示结点u的最大值为size[u]-dp[u]+1

dp[u]表示结点u的消耗值

叶子结点的消耗值为1,

max结点的消耗值为消耗值最小的子树

  dp[u]=min(dp[v])

那么这个结点的结果是size[u]-dp[u]+1

min结点的消耗值为子树的消耗值之和dp[u]=sum(dp[v])

最后的答案是size[1]-dp[1]+1

#include<bits/stdc++.h>
using namespace std;
#define maxn 300005
struct Edge{int to,nxt;}edge[maxn<<1];
int flag[maxn],a[maxn],head[maxn],tot,n;
void addedge(int u,int v){
    edge[tot].to=v;edge[tot].nxt=head[u];head[u]=tot++;
} 
void init(){
    tot=0;
    memset(head,-1,sizeof head);
}
int size[maxn];
void getsize(int u,int fa){
    if(flag[u]==0){size[u]=1;return;}
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==fa)continue;
        getsize(v,u);
        size[u]+=size[v]; 
    } 
}
int dp[maxn];
void dfs(int u,int fa){
    if(flag[u]==0){dp[u]=1;return;}
    int sum=0,Min=0x3f3f3f3f;
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==fa)continue;
        dfs(v,u);
        sum+=dp[v];
        Min=min(Min,dp[v]);
    }
    if(a[u])dp[u]=Min;
    else dp[u]=sum;
}

int main(){
    init();
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int u=2;u<=n;u++){
        int fa;
        cin>>fa;
        flag[fa]=1;
        addedge(u,fa);
        addedge(fa,u);
    }
    getsize(1,0);
    dfs(1,0);
    cout<<size[1]-dp[1]+1<<endl;
}

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/10708335.html