CF1153D 题解

思路

对于每个 min\min 合并,肯定会有一些较大数受到浪费,例如把 4,54,5 进行 min\min 合并,得数是 44,这里就浪费了 54=15-4=1。我们设 dpxdp_x 表示以 xx 为根的子树里最少得浪费,然后从 n1n\sim1 的顺序枚举 ^\dag 每个 xx,依次更新 dpfidp_{f_i}。若这是叶子结点,dpx=1dp_x=1dpxdp_x 是指 能选的颜色数最大答案+1\text{能选的颜色数}-\text{最大答案}+1)。若 numx=1num_{x}=1,因为是取所有子树的最大值,这个最大值肯定要是所有子树中浪费最小的那个,dpx=mindpsonxdp_x=\min dp_{son_x};否则就是取最小值,就是取所有子树中值最小的那个,但因为在它之前还有别的所有子树,所以 dpx=dpsonxdp_x=\sum dp_{son_x}。另外注意这是浪费的值,所以答案是 kdpx+1k-dp_x+1

^\dag 因为 fi<if_i<i,所以倒着枚举即可。

代码

# include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int inf = 1e9;
int n, f[300005], dp[300005], k;
bool a[300005];
bitset <300005> leaf;
int main () {
	ios::sync_with_stdio (0);
	cin.tie (0);
	cout.tie (0);
	cin >> n;
	for (int i = 1; i <= n; ++ i) {
		cin >> a[i];
		leaf[i] = 1;
		if (a[i])
			dp[i] = inf;
	}
	for (int i = 2; i <= n; ++ i)
		cin >> f[i], leaf[f[i]] = 0;
	for (int i = n; i; -- i) {
		if (leaf[i])
			++ k, dp[i] = 1;
		if (a[f[i]])
			dp[f[i]] = min (dp[f[i]], dp[i]);
		else
			dp[f[i]] += dp[i];
	}
	cout << k - dp[1] + 1;
	return 0;
}
posted @   sz_jinzikai  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示