Codeforces 1153D 树形DP
Posted pkgunboat
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 1153D 树形DP相关的知识,希望对你有一定的参考价值。
题意:有一个游戏,规则如下:每个点有一个标号,为max或min, max是指这个点的值是所有子节点中值最大的那一个,min同理。问如何给这颗树的叶子节点赋值,可以让这棵树的根节点值最大。
思路:很明显的树形dp, 设dp[x]是指以x为根的子树中可以获得的最大的值, sz[x]是指以x为根的子树中叶子节点的个数。
若x是max, 那么dp[x] = max(sz[x] - sz[y] + dp[y]),对应的决策相当于把最大的几个值给dp[y] - sz[y]最大的那颗子树。
若x是min, 首先需要统计每颗子树的sz[y] - dp[y], 这些都不可能被选上了,之后,还要统计有多少棵子树(假设有z棵), 其中z - 1个肯定选不上了,所以答案是sz[x] - Σ(sz[y] - dp[y]) - (z - 1)。
这两条对照这样例的图很容易就能发现了,然而昨晚思路跑偏了,这题都没做出来,含泪掉分。。。
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 300010; vector<int> G[maxn]; int sz[maxn], dp[maxn], a[maxn]; void dfs(int x) { dp[x] = 1; if(G[x].size() == 0) { sz[x] = 1; return; } for (int i = 0; i < G[x].size(); i++) { int y = G[x][i]; dfs(y); sz[x] += sz[y]; } if(a[x] == 1) { for (int i = 0; i < G[x].size(); i++) { int y = G[x][i]; dp[x] = max(dp[x], sz[x] - sz[y] + dp[y]); } } else { int tmp = 0; for (int i = 0; i < G[x].size(); i++) { int y = G[x][i]; tmp += sz[y] - dp[y]; } dp[x] = sz[x] - tmp - G[x].size() + 1; } } int main() { int n, x; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for (int i = 2; i <= n; i++) { scanf("%d", &x); G[x].push_back(i); } dfs(1); printf("%d ", dp[1]); }
以上是关于Codeforces 1153D 树形DP的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 743D:Chloe and pleasant prizes(树形DP)
Codeforces 919D Substring (拓扑排序+树形dp)