4732: 【GESP2512六级】路径覆盖
内存限制:512 MB
时间限制:1.000 S
评测方式:文本比较
命题人:
提交:3
解决:3
题目描述

样例输入 复制
4
1 2 3
5 6 2 3
样例输出 复制
2
提示
/*
* 试题名称:路径覆盖
* 题目大意:给定一棵根为1的有根树,叶子到根的每一条路径上至少存在一个黑色结点。
* 将结点i染黑代价c[i],求满足条件的总最小染色代价。
* 数据范围:n ≤ 1e5,父结点f[i] < i,可逆序遍历代替DFS后序遍历
*/
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;
int n;
int f[N]; // f[i]:i的父节点编号
int c[N]; // c[i]:把i染黑的代价
int cnt[N]; // cnt[ u ]:u的子节点数量,cnt[ u ]==0代表u是叶子
long long ans[N]; // ans[i]:以i为根的子树全部满足条件的最小总代价
int main()
{
scanf("%d", &n);
// 读入2~n每个点的父节点,统计每个父节点的子节点计数
for (int i = 2; i <= n; i++)
{
scanf("%d", &f[i]);
cnt[f[i]]++;
}
// 读入每个结点染色代价
for (int i = 1; i <= n; i++)
scanf("%d", &c[i]);
/*
* 逆序循环 i从n到1,因为父节点编号一定小于子节点
* 保证处理父i的时候,i的所有子节点已经全部处理完成(等价后序遍历)
*/
for (int i = n; i >= 1; i--)
{
// 如果i是叶子结点:叶子本身这条路径必须有黑点,只能选把自己染黑
if (cnt[i] == 0)
ans[i] = c[i];
// 决策:当前结点i可以选择染黑,代价c[i]
ans[i] = min(ans[i], 1ll * c[i]);
// 将i的最小代价贡献加到父节点f[i]上,父节点汇总所有子树的最小代价
ans[f[i]] += ans[i];
}
// 根结点1的子树就是整棵树,输出根节点的答案
printf("%lld\n", ans[1]);
return 0;
}