[编程题] 黑白树
时间限制:1秒
空间限制:32768K
一棵n个点的有根树,1号点为根,相邻的两个节点之间的距离为1。树上每个节点i对应一个值k[i]。每个点都有一个颜色,初始的时候所有点都是白色的。
你需要通过一系列操作使得最终每个点变成黑色。每次操作需要选择一个节点i,i必须是白色的,然后i到根的链上(包括节点i与根)所有与节点i距离小于k[i]的点都会变黑,已经是黑的点保持为黑。问最少使用几次操作能把整棵树变黑。
你需要通过一系列操作使得最终每个点变成黑色。每次操作需要选择一个节点i,i必须是白色的,然后i到根的链上(包括节点i与根)所有与节点i距离小于k[i]的点都会变黑,已经是黑的点保持为黑。问最少使用几次操作能把整棵树变黑。
输入描述:
第一行一个整数n (1 ≤ n ≤ 10^5) 接下来n-1行,每行一个整数,依次为2号点到n号点父亲的编号。 最后一行n个整数为k[i] (1 ≤ k[i] ≤ 10^5) 样例解释: 对节点3操作,导致节点2与节点3变黑 对节点4操作,导致节点4变黑 对节点1操作,导致节点1变黑
输出描述:
一个数表示最少操作次数
输入例子:
4 1 2 1 1 2 2 1
输出例子:
3
首先的想法是叶子节点肯定是要染色的,因为没有人会给它染色。那么就从叶子节点开始向上看。最关键的部分是我们虽然是从下往上看的,但是最终染色的步骤却是从上往下的,从上往下可以忽略那个只能选白色节点的那个条件。明确了这个关键点之后,我们就可以在从下往上的时候尽量要走远一些,因为走的越远可选择的机会越多。所以我们贪心策略,从下往上的时候记录这个点最远能走到多远,同时也记录一下这个点从之前某个点走过来还能再走几步。当遍历到某个点的时候,这个店不能再往前走了,ans++。便利的同时更新最远的距离和还能走多远的距离。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
int a[1111111];
int n;
int edge[1111111];
int have[1111111];
int vis[1111111];
int mx[1111111];
int main() {
cin >> n;
memset(edge, 0, sizeof(edge));
for (int i = 2; i <= n; i++) {
cin >> edge[i];
have[edge[i]]++;
}
queue<int> que;
memset(vis, -1, sizeof(vis));
edge[1] = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (have[i] == 0) {
que.push(i);
}
}
int ans = 0;
while (!que.empty()) {
int t = que.front();
que.pop();
if (t == 0) {
continue;
}
mx[t] = max(mx[t], a[t]);
if (vis[t] == 0 || vis[t] == -1) {
vis[t] = mx[t];
ans++;
}
int u = edge[t];
vis[u] = max(vis[u], vis[t] - 1);
mx[u] = max(mx[u], mx[t] - 1);
have[u]--;
if (have[u] == 0) {
que.push(u);
}
}
cout << ans << endl;
return 0;
}