专栏文章

题解:CF1153D Serval and Rooted Tree

CF1153D题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqgae1l
此快照首次捕获于
2025/12/04 04:19
3 个月前
此快照最后确认于
2025/12/04 04:19
3 个月前
查看原文
题目传送门
首先,我们先考虑二分一个 mid\text{{mid}} ,检查“根结点的最大值会不会 mid\ge \text{{mid}} ”。那么对于叶子结点 [1,k][1,k] 的值,就可以化为 0011 ,表示这个值是不是mid\ge \text{mid} 。要使根结点的值尽可能大,就要使 11 的使用次数尽可能小,所以设 dpidp_{i} 表示以 ii 为根的子树中叶子结点最少使用多少个 11 ,才能使 ii 这个点的值为 11 。先考虑 ii 点的操作为取 min\minii 的儿子一定都要是 11 ,所以 dpi=jdpjdp_{i}=\sum \limits_{j} dp_{j} (其中 jjii 的儿子)。再考虑 ii 点的操作为取 max\maxii 的儿子只要有一个为 11 即可,所以 dpi=minj{dpj}dp_{i}=\min \limits_{j} \{ dp_{j} \} (其中 jjii 的儿子)。列出转移方程,我们发现貌似没有用到 mid\text{mid} ,所以把二分去掉,答案就为 kdp1+1k-dp_{1}+1
code:
CPP
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,opt[N],dp[N];
vector<int> e[N];

void dfs(int x)
{
	if(e[x].size()==0)
	{
		dp[x]=1;
		return ;
	}
	int ans1=1e9,ans2=0;
	for(int i=0;i<e[x].size();i++)
	{
		int y=e[x][i];
		dfs(y);
		ans1=min(ans1,dp[y]),ans2+=dp[y];
	}
	if(opt[x]) dp[x]=ans1;
	else dp[x]=ans2;
	return ; 
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",opt+i);
	for(int i=2;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		e[x].push_back(i);
	}
	for(int i=2;i<=n;i++) m+=(e[i].size()==0);
	dfs(1);
	cout<<m-dp[1]+1;
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...