Vijos P1706 舞会

舞会

Description

Arthur公司是一个等级森严的公司,它们有着严格的上司与下属的关系,公司以总裁为最高职位,他有若干个下属,他的下属又有若干个下属,他的下属的下属又有若干个下属……现接近年尾,公司组织团拜活动,活动中有一部分是自由舞会,公司的每个职员都有一个搞笑值,现要你制定一套哪些人上台的方案,使得台上所有演员的搞笑值最大。当然,职员们是不会和他们的顶头上司一起上台

Input

第一行一个整数N,表示这个公司总共的职员个数。

接下来一行有N个整数,由空格隔开,第i个整数表示职员i的搞笑值Ai(-1327670≤Ai≤1327670)。

接下来N-1行,每行一个1到N的整数,第i个整数表示职员i+1的顶头上司是谁,当然总裁就是职员1。

Output

一个整数,表示台上所有职员搞笑值之和的最大值。

Sample Input

7
1 1 1 1 1 1 1
1
1
5
1
4
4

Sample Output

5

Answer

/**
这是一个树形DP
设dp[i][0]为在下标为i的节点的子树上得到的最大值(不取根节点i)
设dp[i][1]为在下标为i的节点的子树上得到的最大值(取根节点i)
那么dp[i][0] += max(dp[q][0],dp[q][1]);   ==>q∈{i点的子节点}
而dp[i][1] += dp[q][0];                   ==>q∈{i点的子节点}
记忆化搜索即可
**/

#include 
   
   
    
    
#define maxn (5000 + 10)
using namespace std;

int dp[maxn][2];
vector
    
    
     
      Vec[maxn];
int va[maxn];
int n;


void DFS(int p) {
//    printf("%d \n",p);
    if(p > n)   return;
    if(dp[p][0] != -1 || dp[p][1] != -1)    return;
    if(Vec[p].size() == 0) {
        dp[p][1] = va[p];
        dp[p][0] = 0;
        return ;
    }
    for(int i = 0; i < Vec[p].size(); i ++)   DFS(Vec[p][i]);
    dp[p][0] = 0;
    dp[p][1] = va[p];
    for(int i = 0; i < Vec[p].size(); i ++) {
        int q = Vec[p][i];
        dp[p][0] += max(dp[q][0],dp[q][1]);
        dp[p][1] += dp[q][0];
    }

}

int main() {
//    freopen("in.txt","r",stdin);
    memset(dp,-1,sizeof(dp));
    scanf("%d",&n);
    for(int i = 1; i <= n; i ++) {
        scanf("%d",&va[i]);
    }
    for(int i = 1; i <= n; i ++) {
        if(i == 1)  continue;
        int pre;
        scanf("%d",&pre);
        Vec[pre].push_back(i);
    }
    DFS(1);
    printf("%d\n",max(dp[1][0],dp[1][1]));
    return 0;
}

    
    
   
   


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值