#551 (Div. 2)___D Serval and Rooted Tree —— 树dp

题目链接:点我啊╭(╯^╰)╮

题目大意:

     一棵树,每个叶子有一个 1 1 1~ k k k 的数字,不重复且共有 k k k 个叶子,每个非叶子结点有一个 m i n min min m a x max max 操作,代表从它的子节点中进行 m i n min min 操作或者 m a x max max 操作,问根节点的最大值是多少???

解题思路:

    明显用数值进行操作是不行的,那么就用树 d p dp dp 的思想:
     d p [ i ] dp[i] dp[i] 表示结点 i i i 保存着第 d p [ i ] dp[i] dp[i] 大的叶子结点,要使根节点最大,则 d p dp dp 维护的就是排名最小的叶子结点

代码思路:

    有了 d p dp dp 的思路,对于两个操作:
    若是 m a x max max ,则代表从子节点中取最大值,在 d p dp dp 所代表的的排名操作中,也就是取更小的排名,则 d p [ i ] = m i n ( d p [ j ] ) dp[i] = min(dp[j]) dp[i]=min(dp[j])
    若是 m i n min min ,则代表从子节点中取最小值,由于 d p dp dp 表示的是排名,取最小值也就是两者的排名和(叶子从 1 1 1 k k k ),则 d p [ i ] = s u m ( d p [ j ] ) dp[i] = sum(dp[j]) dp[i]=sum(dp[j])
    最终的答案也就是 c n t + 1 − d p [ 1 ] cnt + 1 - dp[1] cnt+1dp[1]

核心:树dp + 贪心,妙啊

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5+10;
int n, cnt, op[maxn], dp[maxn];
vector <int> e[maxn];

void dfs(int k){
	if(e[k].empty()) {
		cnt++; dp[k] = 1;
		return ;
	}
	if(op[k]) dp[k] = INT_MAX; // 注意初始为 0 的情况 
	for(auto i : e[k]){
		dfs(i);
		if(op[k]) dp[k] = min(dp[k], dp[i]);
		else dp[k] += dp[i];
	}
}

int main(){
	scanf("%d", &n);
	for(int i=1; i<=n; i++) scanf("%d", op+i);
	for(int i=2, tmp; i<=n; i++){
		scanf("%d", &tmp);
		e[tmp].push_back(i);
	}
	dfs(1);
	printf("%d\n", cnt+1-dp[1]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值