专栏文章

题解:CF1153D Serval and Rooted Tree

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

文章操作

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

当前评论
0 条
当前快照
1 份
快照标识符
@minsk96p
此快照首次捕获于
2025/12/02 07:39
3 个月前
此快照最后确认于
2025/12/02 07:39
3 个月前
查看原文

题目大意

给定一个有 n 个结点的以 1 为根的树,每个结点上有一个操作类型 0 或 1 。
操作类型 0 代表该节点的权值为其所有儿子的权值的最小值,操作类型 1 代表该节点的权值为其所有儿子的权值的最大值。叶子结点的权值没有意义,可以忽略。
假设这棵树有 k 个叶子,你需要在每个叶子上填入数字 1−k ,使得按如上计算结点权值后,结点 1 的权值最大,输出这个最大值。

解题思路

假设答案为 ,如果一个结点上的操作为 ,则其要求其每个儿子结点的值都大于 ,如果一个结点上的操作为 ,其要求其中一个儿子结点的值大于 。 按照上面的操作,如果我们到达了一个叶子结点,那么我们就需要一个大于等于 的数来填入这个格子中,由于 在遍历全树时不会改变,我们只需要找到一种方式,使得最后到达的叶子结点数最少。 我们发现在这个过程中唯一能控制到达叶子结点数的是操作类型 ,在计算该节点信息的过程中,我们只需选择一个叶子结点数最小的子树,即对其所有儿子能选择的最小叶子节点数取 。 在操作 时,由于其要求每个儿子结点的值都大于 ,我们要对其儿子能选择的最小叶子结点数求和,作为该节点能选择的最小叶子结点数。 最后,我们发现根节点能选择的最小叶子结点数 是和 无关的,而这个结点数的意义是至少需要选择 个值大于等于 的数,那么我们的 最大为 。

代码展示

CPP
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=600010;
int n,op[maxn],x,k;
int cur,h[maxn],nxt[maxn],p[maxn];
int f[maxn];
void add_edge(int x,int y)
{
	cur
++;
	nxt
[cur]=h[x];
	h
[x]=cur;
	p
[cur]=y;
}
void dfs(int x,int fa)
{
	int ch=0;
	if(op[x]==1)f[x]=2e9;
	for(int j=h[x];j;j=nxt[j])if(p[j]!=fa)
	{
		ch
++;
		dfs(p[j],x);
		if(op[x]==0)f[x]+=f[p[j]];
		else f[x]=min(f[x],f[p[j]]);
	}
	if(!ch)k++,f[x]=1;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",op+i);
	for(int i=2;i<=n;i++)scanf("%d",&x),add_edge(i,x),add_edge(x,i);
	dfs(1,-1);
	printf("%d\n",k+1-f[1]);
	return 0;
}

评论

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

正在加载评论...