持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
题目链接
题目
题目大意
给定一棵 个节点的树和一个空串 ,最初树中每个节点的值是一个 到 的排列,可以随便指定。
进行 次操作,每次操作可以选一个叶子节点把它加入 的末尾,然令它父节点的值为原来的值与被选的节点的值中小的那一个,问 次操作后最终序列 的最长不下降子序列长度最长是多少。
思路
由于最初树中每个节点的值是一个 到 的排列,每次操作可以选一个叶子节点把它加入 的末尾,然令它父节点的值为原来的值与被选的节点的值中小的那一个,所以每个节点可以被加入 时,它的值一定不超过以它为根节点的子树中所有节点的最小值。即每个节点只能和其子树中的一条链在同一个最长不下降子序列中。而若干棵兄弟子树的大小和选择顺序可以随便指定,即他们各自形成的最长不下降子序列可以都在同一个最长不下降子序列中。
设 表示 的子节点集合; 表示以 为根节点的子树中以 为端点的最长链的长度; 表示以 为根节点的子树形成的最长不下降子序列的长度。则对于每一个节点 :
DFS 整棵树转移即可。最终的答案是 。
代码
#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;
}