黑白树(树形dp+牛客)

链接:题目链接
来源:牛客网

时间限制: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 ≤ 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

思路:
先能看出是个树形结构,然后找的是最值问题,应该想到是贪心,即为动态规划。k[x]表示更新以他为根节点的子树的最远覆盖距离 ,f[x]来自其他子节点能覆盖它的最远距离。不能被子节点覆盖的节点更新 f[x]或最下层的节点更新f[x],应该更新为k[x],因为应该新增一个节点,该节点应该是越过这个节点能覆盖到最远的节点,并将其染成黑色。
树形结构可看前面的文章!!!
代码:

#include
using namespace std;
typedef long long int ll;
const ll N=1e5+7;
vector<int> son[N];
int f[N],k[N],n,ans=0;
void dfs(int x,int fa)
{
 for(int i=0;i<son[x].size();i++)
 {
  int nev=son[x][i];
  dfs(nev,x);
  k[x]=max(k[x],k[nev]-1);//k[x]更新以他为根节点的子树的最远覆盖距离 
  f[x]=max(f[x],f[nev]-1);//f[x]来自其他子节点能覆盖它的最远距离 
 }
 if(!f[x])
 {
  ans++;
  f[x]=k[x];//不能被子节点覆盖的节点更新 f[x]或最下层的节点更新f[x] 
 }
 } 
int main()
{
 cin>>n;
 for(int i=2;i<=n;i++)
 {
  int x;
  cin>>x;
  son[x].push_back(i);//注意父子关系 
 }
 for(int i=1;i<=n;i++)
 cin>>k[i];
 dfs(1,0);//初始父节点只要不是树上的节点就可 
 cout<<ans<<endl;
 return 0;
}

你可能感兴趣的:(数据结构,动态规划,dfs,动态规划,树结构)