Sum in the tree CodeForces - 1098A

本文探讨了一种树形DP算法,用于解决在已知部分节点权值和路径和的情况下,恢复整棵树节点权值的问题。通过两次DFS遍历,第一次找到被擦除节点的最小可能值,第二次确定各节点的具体权值,确保整体权值之和最小。若过程中发现不可行情况,则返回-1。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Mitya has a rooted tree with nn vertices indexed from 11 to nn, where the root has index 11. Each vertex vv initially had an integer number av≥0av≥0 written on it. For every vertex vv Mitya has computed svsv: the sum of all values written on the vertices on the path from vertex vv to the root, as well as hvhv — the depth of vertex vv, which denotes the number of vertices on the path from vertex vv to the root. Clearly, s1=a1s1=a1 and h1=1h1=1.

Then Mitya erased all numbers avav, and by accident he also erased all values svsv for vertices with even depth (vertices with even hvhv). Your task is to restore the values avav 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 avav for all vertices in the tree.

Input

The first line contains one integer nn — the number of vertices in the tree (2≤n≤1052≤n≤105). The following line contains integers p2p2, p3p3, ... pnpn, where pipi stands for the parent of vertex with index ii in the tree (1≤pi<i1≤pi<i). The last line contains integer values s1s1, s2s2, ..., snsn (−1≤sv≤109−1≤sv≤109), where erased values are replaced by −1−1.

Output

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

Examples

Input

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

Output

1

Input

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

Output

2

Input

3
1 2
2 -1 1

Output

-1

题意:给出一棵树,以及每个节点到根节点的路径上经过的所有点的权值之和(包括这个节点在内),其中题目把所有深度为偶数的节点的信息全部擦除了,也就是用-1表示,让你求最终所有点权之和(要求最小)。

思路:dfs,找节点为-1的点,按照贪心思想,该点的上的sum值为其子节点sum值的最小值。若为-1的点为叶子,那么sum值为其父亲的sum值。然后再dfs一次,点i的点权为sum[i]-sum[father],如果该值小于0,那么直接输出-1

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=100009;
int head[maxn],cnt,flag;
ll sum[maxn],ans[maxn];
struct node{
	int id;
	int next;
}side[maxn];
void init()
{
	memset(head,-1,sizeof(head));
	memset(sum,0,sizeof(sum));
	memset(ans,0,sizeof(ans));
	cnt=flag=0;
}
void add(int x,int y)
{
	side[cnt].id=y;
	side[cnt].next=head[x];
	head[x]=cnt++;
}
void dfs1(int x,int fa)
{
	ll minn=0x3f3f3f3f;
	if(sum[x]==-1)
	{
		for(int i=head[x];i!=-1;i=side[i].next)
		{
			int y=side[i].id;
			if(y==fa) continue;
			minn=min(minn,sum[y]);
			dfs1(y,x);
		}
		if(minn!=0x3f3f3f3f)
			sum[x]=minn;
		else
			sum[x]=sum[fa];
	}
	else
	{
		for(int i=head[x];i!=-1;i=side[i].next)
		{
			int y=side[i].id;
			if(y==fa) continue;
			dfs1(y,x);
		}
	}
}
void dfs2(int x,int fa)
{
	for(int i=head[x];i!=-1;i=side[i].next)
	{
		int y=side[i].id;
		if(y==fa) continue;
		ans[y]=sum[y]-sum[x];
		if(ans[y]<0)
		{
			flag=1;
			return ;
		}
		dfs2(y,x);
	}
}
int main()
{
	int n,x;
	scanf("%d",&n);
	init();
	for(int i=2;i<=n;i++)
	{
		scanf("%d",&x);
		add(x,i);
	}
	for(int i=1;i<=n;i++)
		scanf("%lld",&sum[i]);
	dfs1(1,-1);
	dfs2(1,-1);
	
	ans[1]=sum[1];
	ll res=0;
//	for(int i=1;i<=n;i++)
//	{
//		printf("%d %d\n",ans[i],sum[i]);
//	}
	for(int i=1;i<=n;i++)
		if(ans[i]>0)
			res+=ans[i];
	if(!flag)
		printf("%lld\n",res);
	else
		printf("-1\n");
	return 0;
}

 

### 关于 Codeforces Problem 1802A 目前提供的引用内容并未涉及 Codeforces 编号为 1802A 的题目详情或解决方案[^1]。然而,基于常见的竞赛编程问题模式以及可能的解决方法,可以推测该类题目通常围绕算法设计、数据结构应用或者特定技巧展开。 如果假设此题属于典型的算法挑战之一,则可以从以下几个方面入手分析: #### 可能的方向一:字符串处理 许多入门级到中级难度的问题会考察字符串操作能力。例如判断子串是否存在、统计字符频率或是执行某种转换逻辑等。以下是 Python 中实现的一个简单例子用于演示如何高效地比较两个字符串是否相匹配: ```python def are_strings_equal(s1, s2): if len(s1) != len(s2): return False for i in range(len(s1)): if s1[i] != s2[i]: return False return True ``` #### 方向二:数组与列表的操作 另一常见主题是对整数序列进行各种形式上的变换或者是查询最值等问题。下面给出一段 C++ 程序片段来展示快速寻找最大元素位置的方法: ```cpp #include <bits/stdc++.h> using namespace std; int main(){ int n; cin >> n; vector<int> a(n); for(auto &x : a){ cin>>x; } auto max_it = max_element(a.begin(),a.end()); cout << distance(a.begin(),max_it)+1; // 输出索引加一作为答案 } ``` 由于具体描述缺失,在这里仅提供通用框架供参考。对于确切解答还需要访问实际页面获取更多信息后再做进一步探讨[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值