Codeforces Round #831 (Div. 1 + Div. 2) E(树形dp)

91 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情
本文已参与「新人创作礼」活动,一 起开启掘金创作之路

题目

Pak Chanek has nn blank heart-shaped cards. Card 11 is attached directly to the wall while each of the other cards is hanging onto exactly one other card by a piece of string. Specifically, card ii (i>1i > 1) is hanging onto card pip_i (pi<ip_i < i). In the very beginning, Pak Chanek must write one integer number on each card. He does this by choosing any permutation aa of [1,2,,n][1, 2, \dots, n]. Then, the number written on card ii is aia_i.
After that, Pak Chanek must do the following operation nn times while maintaining a sequence ss (which is initially empty):
Choose a card xx such that no other cards are hanging onto it. Append the number written on card xx to the end of ss. If x1x \neq 1 and the number on card pxp_x is larger than the number on card xx, replace the number on card pxp_x with the number on card xx. Remove card xx. After that, Pak Chanek will have a sequence ss with nn elements. What is the maximum length of the longest non-decreasing subsequence^\dagger of ss at the end if Pak Chanek does all the steps optimally? ^\dagger A sequence bb is a subsequence of a sequence cc if bb can be obtained from cc by deletion of several (possibly, zero or all) elements. For example, [3,1][3,1] is a subsequence of [3,2,1][3,2,1], [4,3,1][4,3,1] and [3,1][3,1], but not [1,3,3,7][1,3,3,7] and [3,10,4][3,10,4].

中文大意

给定一棵 n 个节点的树和一个空串 S,最初树中每个节点的值是一个 1 到 n 的排列,时随机的。 进行 n 次操作,每次操作可以选一个叶子节点把它加入 S 的末尾,然令它父节点的值为原来的值与被选的节点的值中小的那一个,问 n 次操作后最终序列 S 的最长不下降子序列长度最长是多少。

解法

我们发现每次对这个结点操作时如果这个结点的值小于它父节点的值时他会将它父节点的值改为它的值, 也就是说当我们按照贪心的想法来放时就可以保证在一条长链上的值是可以保证是不下降子序列,然后我们又可以发现如果是针对uu的子树来说 如果是以u为结尾的最长不下降子序列为的最大值为dp[u]dp[u] = max(dp[u],lenmax[u])max(dp[u],len_{max}[u]) dp[u]=dp[(pi=u)]dp[u] = \sum dp[(p_i=u)],因为他们的数字是可以随机的

代码

vector<int> v[N];
int len[N];
int dp[N];
void dfs(int x) {
   for(auto u : v[x]) {
      dfs(u);
      len[x] = max(len[x],len[u]);
      dp[x] += dp[u];
   }
   len[x] ++;
   dp[x] = max(dp[x],len[x]);
}
void solve()
{
   int n; cin >> n;
   rep(i,n) v[i].clear();
   for(int i = 2; i <= n; i++) {
      int x; cin >> x;
      v[x].pb(i);
   }
   dfs(1);
   cout << dp[1] << endl;
}