题目链接:点我啊╭(╯^╰)╮
题目大意:
一棵树,每个叶子有一个 1 1 1~ k k k 的数字,不重复且共有 k k k 个叶子,每个非叶子结点有一个 m i n min min 或 m a x max max 操作,代表从它的子节点中进行 m i n min min 操作或者 m a x max max 操作,问根节点的最大值是多少???
解题思路:
明显用数值进行操作是不行的,那么就用树
d
p
dp
dp 的思想:
d
p
[
i
]
dp[i]
dp[i] 表示结点
i
i
i 保存着第
d
p
[
i
]
dp[i]
dp[i] 大的叶子结点,要使根节点最大,则
d
p
dp
dp 维护的就是排名最小的叶子结点
代码思路:
有了
d
p
dp
dp 的思路,对于两个操作:
若是
m
a
x
max
max ,则代表从子节点中取最大值,在
d
p
dp
dp 所代表的的排名操作中,也就是取更小的排名,则
d
p
[
i
]
=
m
i
n
(
d
p
[
j
]
)
dp[i] = min(dp[j])
dp[i]=min(dp[j])
若是
m
i
n
min
min ,则代表从子节点中取最小值,由于
d
p
dp
dp 表示的是排名,取最小值也就是两者的排名和(叶子从
1
1
1 到
k
k
k ),则
d
p
[
i
]
=
s
u
m
(
d
p
[
j
]
)
dp[i] = sum(dp[j])
dp[i]=sum(dp[j])
最终的答案也就是
c
n
t
+
1
−
d
p
[
1
]
cnt + 1 - dp[1]
cnt+1−dp[1]
核心:树dp + 贪心,妙啊
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5+10;
int n, cnt, op[maxn], dp[maxn];
vector <int> e[maxn];
void dfs(int k){
if(e[k].empty()) {
cnt++; dp[k] = 1;
return ;
}
if(op[k]) dp[k] = INT_MAX; // 注意初始为 0 的情况
for(auto i : e[k]){
dfs(i);
if(op[k]) dp[k] = min(dp[k], dp[i]);
else dp[k] += dp[i];
}
}
int main(){
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", op+i);
for(int i=2, tmp; i<=n; i++){
scanf("%d", &tmp);
e[tmp].push_back(i);
}
dfs(1);
printf("%d\n", cnt+1-dp[1]);
}