【Codeforces】Codeforces Round #831 (Div. 1 + Div. 2) E. Hanging Hearts | 动态规划

258 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情

题目链接

Problem - 1740E - Codeforces

题目

image.png

题目大意

给定一棵 nn 个节点的树和一个空串 SS,最初树中每个节点的值是一个 11nn 的排列,可以随便指定。

进行 nn 次操作,每次操作可以选一个叶子节点把它加入 SS 的末尾,然令它父节点的值为原来的值与被选的节点的值中小的那一个,问 nn 次操作后最终序列 SS 的最长不下降子序列长度最长是多少。

思路

由于最初树中每个节点的值是一个 11nn 的排列,每次操作可以选一个叶子节点把它加入 SS 的末尾,然令它父节点的值为原来的值与被选的节点的值中小的那一个,所以每个节点可以被加入 SS时,它的值一定不超过以它为根节点的子树中所有节点的最小值。即每个节点只能和其子树中的一条链在同一个最长不下降子序列中。而若干棵兄弟子树的大小和选择顺序可以随便指定,即他们各自形成的最长不下降子序列可以都在同一个最长不下降子序列中。

sonuson_u 表示 uu 的子节点集合;lenulen_u 表示以 uu 为根节点的子树中以 uu 为端点的最长链的长度;dpudp_u 表示以 uu 为根节点的子树形成的最长不下降子序列的长度。则对于每一个节点 uu

  • lenu=maxvsonu{lenv}+1len_u=\max_{v\in son_u}\{len_v\}+1
  • dpu=max(vsonudpv,lenu)dp_u=\max(\sum_{v\in son_u}{dp_v},len_u)

DFS 整棵树转移即可。最终的答案是 dp1dp_1

代码

#include <bits/stdc++.h>
#define nnn printf("No\n")
#define yyy printf("Yes\n")
using namespace std;
using LL=long long;
typedef pair<int,int> PII;
const int N=500001;
vector<int> e[N];
int n,m,k,f[N];
int a[N],dp[N],len[N];
void dfs(int u)
{
	int sum=0;
	for (auto v:e[u])
	{
		dfs(v);
		len[u]=max(len[v],len[u]);
		dp[u]+=dp[v];
	}
	len[u]++;
	dp[u]=max(dp[u],len[u]);
}
int solve()
{
	scanf("%d",&n);
	for (int i=2;i<=n;++i)
	{
		scanf("%d",&f[i]);
		e[f[i]].push_back(i);
	}
	dfs(1);
	printf("%d\n",dp[1]);
	return 1;
}
int main()
{
	solve();
	return 0;
}