时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K 64bit IO Format:%lld
题目描述
一棵n个点的有根树,1号点为根,相邻的两个节点之间的距离为1。树上每个节点i对应一个值k[i]。每个点都有一个颜色,初始的时候所有点都是白色的。
你需要通过一系列操作使得最终每个点变成黑色。每次操作需要选择一个节点i,i必须是白色的,然后i到根的链上(包括节点i与根)所有与节点i距离小于k[i]的点都会变黑,已经是黑的点保持为黑。问最少使用几次操作能把整棵树变黑。
输入描述:
第一行一个整数n (1 ≤ n ≤ 105) 接下来n-1行,每行一个整数,依次为2号点到n号点父亲的编号。 最后一行n个整数为k[i]
(1 ≤ k[i] ≤ 105)样例解释:
对节点3操作,导致节点2与节点3变黑 对节点4操作,导致节点4变黑 对节点1操作,导致节点1变黑
输出描述:
一个数表示最少操作次数
示例1
输入
4
1
2
1
1 2 2 1
输出
3
题解:
一开始以为是红黑树的姐妹黑白树。。
求出最少的操作,用dfs
我们要不断更新染色的最远距离,还要把子节点的染色范围更新的父亲节点
比如1->2->3-.>4->5->6->7
f[2]=5,f[3]=2
2节点就可以直接染色到6
操作完2之后,如果3就已经被染色了,如果3能染色的范围比fa[ 2 ]-1(因为2已经染色了本身,所以减一)还大,那染色范围可以更远
如果fa[3]<fa[2]-1,就把f3的最远距离更新到fa[2]-1
总结就是fa[fa]=max( fa [ fa ] , fa [ son ] - 1 )
因为染色都是从下向上的。如果一个节点没办法被它子树的节点染色,那这个节点的父亲节点也没办法将它染色,他只能自己染色了
代码:
#include<bits/stdc++.h>
#define forr(n) for(int i=1;i<=n;i++)
using namespace std;
const int maxn=100004;
int fa[maxn];
int sum;
vector<int>w[maxn];
int a[maxn];
void dfs(int x)
{
for(int j=0;j<w[x].size();j++)
{
dfs(w[x][j]);
fa[x]=max( fa[ w[x][j] ]-1 , fa[x] );
a[x]=max( a[ w[x][j] ]-1 , a[x] );
}
if(fa[x]==0)
{
sum++;
fa[x]=a[x];
}
}
int main()
{
int n,m;
cin>>n;
forr(n-1)
{
cin>>m;
w[m].push_back(i+1);
}
forr(n)
{
cin>>a[i];
}
dfs(1);
cout<<sum;
return 0;
}