牛客

牛客黑白树

链接:https://ac.nowcoder.com/acm/problem/13249
来源:牛客网

题目描述
一棵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变黑

输出描述:

一个数表示最少操作次数

示例1
输入
4
1
2
1
1 2 2 1
输出
3

首先说说我们的思路,这道题很明显是动态规划,这里我们用数组dp来维护当前节点的某个k[i]值最大的子节点在该节点后还能影响的距离,如果dp[i]为0就要对它进行更新,说明点黑这个点之前的任意一个点都不能使它变黑;然后我们需要找到这个点之前的某个点,使其能够影响的绝对位置最远,我们点黑这个点;虽然看上去我们这个操作在题目规定上看起来不合法,但我们采取的是逆向思维,我们只需要考虑我们需要点黑哪些点,至于先后顺序不用考虑,因为这不影响结果;具体维护的操作如下面代码的两个动态转移方程,我们并不需要具体知道点的位置,我们只要知道这个点的值,然后对dp进行k[i]赋值时就相当于点黑的操作。

#include<iostream>
#include<vector>
#include<string>
using namespace std;
vector<int>G[100005];
int fa[100005];
int dp[00005],k[100005];
int ans;
void dfs(int u){
for(int i=0;<G[u_.isel();++)/实际上是对这个父亲进行操作,例子,上次遍历到底端, 回溯到最年轻的爸爸
int v=G[u][i];
dfs(v);
k[u]=max(k[u],k[v]-1);
dp[u]=max(dp[u],dpl[1-1);//每回溯一次往上升-层/实际上这个是判断子节点中K[j最大的,不信细
品,-1是回溯带来的后果
if(dp[u]==0){
dp[u]=k[u];//新迭代式k用来维护该次点黑所能到达的最远位置,而dp维护其当前位置所有子节点所能覆
盖到且最远的
int main(){
int n,m;
cin>>n;
for(int i=2;i<=n;i++) {
cin>>m;
G[m].push_ back();
for(int i=1;i<=n;++){
cin>>K[)];
}
dfs(1); .
cout<<ans<<endl;
return 0;
}//dp初始不赋值,有一个孩子时就是这 个孩子的值,有n个孩子就是这n个孩子的最大值;

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值