Nowcoder13249.黑白树(树形DP)

一棵n个点的有根树,1号点为根,相邻的两个节点之间的距离为1。树上每个节点i对应一个值k[i]。每个点都有一个颜色,初始的时候所有点都是白色的。
你需要通过一系列操作使得最终每个点变成黑色。每次操作需要选择一个节点i,i必须是白色的,然后i到根的链上(包括节点i与根)所有与节点i距离小于k[i]的点都会变黑,已经是黑的点保持为黑。问最少使用几次操作能把整棵树变黑。

//先记一遍每个子树的最大向上高度
//然后对每个叶子节点染色 
//遇到没染色的节点,去子树里找最大的高度,更新高度

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
int n,k[maxn];
vector<int> g[maxn];
int dep[maxn];
int ans;
int h[maxn];//h_x表示x子树内可以往上走的最高高度
int f[maxn];//f_x表示x子树内当前往上走的最高高度 
void dfs (int x,int pre) {
	dep[x]=dep[pre]+1;
	h[x]=dep[x]-k[x]+1; 
	for (int y:g[x]) {
		if (y==pre) continue;
		dfs(y,x);
		h[x]=min(h[x],h[y]);
	}
}
void dfs1 (int x,int pre) {
	dep[x]=dep[pre]+1;
	int Min=1e9;
	for (int y:g[x]) {
		if (y==pre) continue;
		dfs1(y,x);
		Min=min(Min,f[y]);
	}
	if (Min<=dep[x]) {
		f[x]=Min;
	}
	else {
		f[x]=h[x];
		ans++;
	}
}
int main () {
	scanf("%d",&n);
	for (int i=2;i<=n;i++) {
		int x;
		scanf("%d",&x);
		g[x].push_back(i);
	} 
	for (int i=1;i<=n;i++) scanf("%d",k+i),f[i]=1e9;
	dfs(1,0);
	dfs1(1,0);
	printf("%d
",ans);
}
原文地址:https://www.cnblogs.com/zhanglichen/p/14605899.html