D. Serval and Rooted Tree
题意:含有 n n n个节点,并且以 1 1 1为根节点的树的每个节点都有一个操作,用 01 01 01表示,如果为 1 1 1,那么就取这个节点的孩子中的最大值,否则取孩子的最小值。问,如何安排可以使得根节点 1 1 1的值最大。注意如果叶节点有 k k k个,那么取值必须是 1 → k 1\rightarrow k 1→k。
题解:听了某位苣苣的方程解释之后,立刻感觉理解了方程! d p i dp_i dpi表示以 i i i为根的子树与多少个叶子节点有关。那么对于操作值为 1 1 1的节点,它所对应的子树 d p u = m i n { d p v } dp_u = min\{dp_v \} dpu=min{dpv};对于操作值为 0 0 0的节点,它所对应的子树就是 d p u = ∑ v { u } d p v dp_u = \sum_v^{\{u\}}{dp_v} dpu=∑v{u}dpv。最后答案就是叶子节点个数加一再减去根节点与叶子节点相关的数量,即 l e a f + 1 − d p 1 leaf + 1 - dp_1 leaf+1−dp1。
代码
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
using namespace std;
const int N = 3E5+10;
vector<int> E[N];
int dp[N], a[N], leaf, n;
void dfs(int u)
{
if(E[u].size() == 0) {
dp[u] = 1;
leaf++;
return;
}
dp[u] = a[u] ? n : 0;
for(const auto & v : E[u]) {
dfs(v);
if(a[u]) {
dp[u] = min(dp[u],dp[v]);
}else{
dp[u] += dp[v];
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
int x;
cin >> n;
for(int i = 1; i <= n; ++i) {
cin >> a[i];
}
for(int i = 2; i <= n; ++i) {
cin >> x;
E[x].emplace_back(i);
}
dfs(1);
cout << leaf + 1 - dp[1] << endl;
return 0;
}