CF1098A Sum in the tree 题解 树+贪心

Sum in the tree

传送门

Mitya has a rooted tree with n n n vertices indexed from 1 1 1 to n n n, where the root has index 1 1 1. Each vertex v v v initially had an integer number a v ≥ 0 a_v \ge 0 av0 written on it. For every vertex v v v Mitya has computed s v s_v sv: the sum of all values written on the vertices on the path from vertex v v v to the root, as well as h v h_v hv — the depth of vertex v v v, which denotes the number of vertices on the path from vertex v v v to the root. Clearly, s 1 = a 1 s_1=a_1 s1=a1 and h 1 = 1 h_1=1 h1=1.

Then Mitya erased all numbers a v a_v av, and by accident he also erased all values s v s_v sv for vertices with even depth (vertices with even h v h_v hv). Your task is to restore the values a v a_v av for every vertex, or determine that Mitya made a mistake. In case there are multiple ways to restore the values, you’re required to find one which minimizes the total sum of values a v a_v av for all vertices in the tree.

Input

The first line contains one integer n n n — the number of vertices in the tree ( 2 ≤ n ≤ 1 0 5 2 \le n \le 10^5 2n105). The following line contains integers p 2 p_2 p2, p 3 p_3 p3, … p n p_n pn, where p i p_i pi stands for the parent of vertex with index i i i in the tree ( 1 ≤ p i < i 1 \le p_i < i 1pi<i). The last line contains integer values s 1 s_1 s1, s 2 s_2 s2, …, s n s_n sn ( − 1 ≤ s v ≤ 1 0 9 -1 \le s_v \le 10^9 1sv109), where erased values are replaced by − 1 -1 1.

Output

Output one integer — the minimum total sum of all values a v a_v av in the original tree, or − 1 -1 1 if such tree does not exist.

Examples

input #1

5
1 1 1 1
1 -1 -1 -1 -1

output #1

1

input #2

5
1 2 3 1
1 -1 2 -1 -1

output #2

2

input #3

3
1 2
2 -1 1

output #3

-1

题目翻译

米迪亚有一棵有根的树,树上有 n n n 个顶点,索引从 1 1 1 n n n ,其中根的索引为 1 1 1 。每个顶点 v v v 最初都写有一个整数 a v ≥ 0 a_v \ge 0 av0 。对于每个顶点 v v v 米迪亚计算了 s v s_v sv :从顶点 v v v 到根的路径上写在顶点上的所有值的总和,以及 h v h_v hv - 顶点 v v v 的深度,即从顶点 v v v 到根的路径上的顶点数。显然, s 1 = a 1 s_1=a_1 s1=a1 h 1 = 1 h_1=1 h1=1

然后米迪亚删除了所有数字 a v a_v av ,并且意外地删除了偶数深度顶点(偶数顶点 h v h_v hv )的所有数值 s v s_v sv 。你的任务是恢复每个顶点的值 a v a_v av ,或者确定 Mitya 犯了一个错误。如果有多种还原数值的方法,你需要找到一种,使树中所有顶点的数值总和 a v a_v av 最小。

输入格式

第一行包含一个整数 n n n - 树的顶点数( 2 ≤ n ≤ 1 0 5 2 \le n \le 10^5 2n105 )。下面一行包含整数 p 2 p_2 p2 , p 3 p_3 p3 , … p n p_n pn ,其中 p i p_i pi 代表树中索引为 i i i 的顶点的父顶点( 1 ≤ p i < i 1 \le p_i < i 1pi<i )。最后一行包含整数值 s 1 s_1 s1 s 2 s_2 s2 、…、 s n s_n sn − 1 ≤ s v ≤ 1 0 9 -1 \le s_v \le 10^9 1sv109 ),其中已删除的值由 − 1 -1 1 代替。

输出格式

输出一个整数 - 原始树中所有值 a v a_v av 的最小总和,如果不存在这样的树,则输出 − 1 -1 1

注明

以上来自 C o d e F o r c e s ,翻译: D e e p L 以上来自CodeForces,翻译:DeepL 以上来自CodeForces,翻译:DeepL

解题思路

简要解释一下题意:给出一棵以 1 1 1 为根节点的树,大小为 n n n。记根节点深度为 1 1 1。树上每个节点都有一个非负权值 a i a_i ai(不给出),记 s i s_i si 表示从 i i i 号节点到根节点的路径上所有点的权值和,包括根节点及其本身
现在给你每个深度为奇数节点的 s i s_i si。深度为偶数的节点的 s i s_i si 不给出,值为 − 1 −1 1。请你还原树的每个节点的权值。使得其满足所有给出的值不为 − 1 -1 1 s i s_i si。并输出最小的 Σ a i \Sigma a_i Σai。若无解,则输出 −1。

想一想就能明白,让一个 a i a_i ai 尽可能的去给更多的 s i s_i si 做贡献,即可使 Σ a i \Sigma a_i Σai 最小。所以对每个 − 1 -1 1 s i s_i si 搜索出其孩子中的最小 s i s_i si(因为要求每个子节点 s i s_i si 总会大于父节点 s i s_i si),最后判断如果有子节点 s i s_i si 小于父节点 s i s_i si,则输出 − 1 -1 1

AC Code

#include<bits/stdc++.h>
using namespace std;
char buf[1048576], *p1, *p2;
template<typename T>inline void Super_Quick_Read(T &x) {
	bool f = 1;
	x = 0;
	char ch = (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? 0 : *p1++);
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = !f;
		ch = (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? 0 : *p1++);
	}
	while (ch >= '0' && ch <= '9')x = (x << 1) + (x << 3) + (ch ^ 48), ch = (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? 0 : *p1++);
	x = (f ? x : -x);
	return;
}
template<typename T>inline void Quick_Write(T x) {
	if (x < 0) putchar('-'), x = -x;
	if (x > 9) Quick_Write(x / 10);
	putchar(x % 10 + '0');
	return;
}
int n;
long long s[200005];
int U[200005], V[200005], W[200005], Fst[200005], Next[200005], Father[200005], Length;
long long Answer = 0;
inline void Add(int a, int b) {
	U[++Length] = a, V[Length] = b, Next[Length] = Fst[a], Fst[a] = Length;
}
inline long long Dfs(int n) {
	if (s[n] != -1)	return s[n];
	else {
		int k = Fst[n];
		long long _min = 1e9 + 5;
		while (k != -1)_min = min(Dfs(V[k]), _min), k = Next[k];
		s[n] = _min;
		return s[n];
	}
}
signed main() {
	Super_Quick_Read(n);
	for (register int i = 0; i <= n + 1; i++)Fst[i] = -1;
	for (register int i = 2, t; i <= n; ++i)Super_Quick_Read(t), Add(t, i), Father[i] = t;
	for (register int i = 1; i <= n; ++i)Super_Quick_Read(s[i]);
	int flag = 0;
	for (register int i = 1, t1, t2; i <= n; ++i) {
		t1 = Dfs(i), t2 = Dfs(Father[i]);
		if (t1 != 1e9 + 5) {
			if (t2 > t1)flag = 1;
			Answer += (t1 - t2);
		}
	}
	if (flag)puts("-1");
	else Quick_Write(Answer);
	return 0;
}

重要提醒

CSDN你什么时候完善你的 L a T e X LaTeX LaTeX 公式显示啊!

  • 28
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述: 给定一些文件夹和文件,要求将它们按照层级关系输出成一个形结构。 输入格式: 输入的第一行包含一个整数 n,表示文件夹和文件的个数。 接下来 n 行,每行包含一个字符串,表示一个文件夹或者文件。 其中,文件名和文件夹名都不包含空格和斜杠,文件名包含一个小数点,表示文件后缀。 输出格式: 输出一个形结构,每行表示一个文件夹或者文件,按照层级关系缩进,文件夹名称后面要加上一个斜杠。 注意,最后一个文件夹或者文件名称后面不能有空格。 样例: 输入: 6 /root /etc /root/abcd.txt /root/bcd/ /etc/test/ /root/bcd/efg.txt 输出: /root /abcd.txt /bcd/ /efg.txt /etc /test/ 算法1 (模拟) $O(n)$ 思路: 本题需要我们输出文件夹和文件的层级结构,因此可以考虑使用哈希表记录每个文件夹和文件的层级结构。 对于每个文件夹和文件,我们可以通过判断其路径中"/"的数量来确定其所在的层级结构,具体来说,每个"/"表示一层。因此,我们可以将路径按"/"分开,然后统计"/"的数量,就可以得到该文件夹或文件所在的层级结构。 同时,由于本题要求输出形结构,因此我们需要对每个文件夹和文件进行缩进处理,使其在输出时具有层级关系。具体来说,我们可以通过其所在的层级结构来确定输出时需要添加的缩进空格数量。 最后,我们可以按照文件夹和文件的层级结构从小到大的顺序进行输出,这样能够保证每个文件夹和文件的父节点已经被输出过了。 时间复杂度 哈希表的查询和插入操作都是常数级别的,因此总时间复杂度为 $O(n)$。 C++ 代码 算法2 (模拟) $O(nlogn)$ 思路: 本题可以使用字典来实现,具体来说,我们可以将每个文件夹和文件的路径看作一个字符串,然后将所有字符串插入到字典中。 同时,我们可以定义一个结构体,用来存储每个字符串的层级结构和缩进空格数量,具体来说,每个字符串的层级结构可以通过其在字典中的深度来确定,而每个字符串的缩进空格数量则可以通过其所在的层级结构来确定。 最后,我们可以按照字符串的层级结构从小到大的顺序进行输出,这样能够保证每个字符串的父节点已经被输出过了。 时间复杂度 插入字符串的时间复杂度为 $O(nlogn)$,输出字符串的时间复杂度也为 $O(nlogn)$,因此总时间复杂度为 $O(nlogn)$。 C++ 代码

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值