百度之星6049-没有兄弟的舞会(贪心)

Problem Description

度度熊、光羽、带劲三个人是好朋友。

度度熊有一棵n个点的有根树,其中1号点为树根。除根节点之外,每个点都有父节点,记i号点的父节点为fa[i]。

度度熊称点i和点j是**兄弟**(其中i≠j)当且仅当fa[i]=fa[j]。

第i个点的权值为Ai。现要求选出一个点集,该点集合法当且仅当**点集中至多只有一对兄弟**。

度度熊想知道,在所有可行的点集中,权值和**最大**以及**最小**的点集权值和分别是多少?

Input

第一行一个数,表示数据组数T。

每组数据第一行一个整数n;第二行n−1个数,表示fa[2],fa[3],..,fa[n];第三行n个数,表示Ai。

数据组数T=100,满足:

- 1≤n≤105
- −109≤Ai≤109
- 1≤fa[i]<i

其中90%的数据满足n≤1000。

Output

每组数据输出一行,每行包含两个数,分别表示权值和的**最大值**和**最小值**。

Sample Input

2

5

1 1 2 2

-4 -4 -1 -2 -5

5

1 1 3 2

-1 -4 2 0 -2

Sample Output

0 -15 
2 -7

思路:这道题最容易想到的就是贪心,最大值时只取大于0的权值,最小值只去小于0的权值。等我学会了树形DP再回来优化..

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const int N = 1e5;
struct node {
	int w, fa;
};
node a[N];
//对结构体排序
bool cmp1(node x, node y)
{
	if (x.w > y.w)
		return true;
	else
		return false;
}
bool cmp2(node x, node y)
{
	if (x.w < y.w)
		return true;
	else
		return false;
}
void solve() 
{
	int n;
	cin >> n;
	int mp[N] = { 0 };
	a[1].fa = N - 1;
	for (int i = 2; i <= n; i++)
	{
		cin >> a[i].fa;
	}
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i].w;
	}
	sort(a + 1, a + n + 1, cmp1);
	ll sum1 = 0, sum2 = 0;
	int flag1 = 0, flag2 = 0;
	for (int i = 1; i <= n; i++)
	{
		int fa = a[i].fa, w = a[i].w;
		if (mp[fa] == 1 && flag1 == 0 && w>0)//flag用来标志至多只有一对兄弟的要求
		{
			flag1 = 1;
			sum1 += w;
		}
		else if (mp[fa] == 0 && w>0)
		{
			mp[fa]++;
			sum1 += w;
		}
		else if (w <= 0)
		{
			break;
		}
	}
	memset(mp, 0, sizeof(mp));
	sort(a + 1, a + n + 1,cmp2);
	for (int i = 1; i <= n; i++)
	{
		int fa = a[i].fa, w = a[i].w;
		if (mp[fa] == 1 && flag2 == 0 && w<0)//至多一个兄弟结点
		{
			flag2 = 1;
			sum2 += w;
		}
		else if (mp[fa] == 0 && w<0)
		{
			mp[fa]++;
			sum2 += w;
		}
		else if (w >= 0)
		{
			break;
		}
	}
	cout << sum1 << " " << sum2 << endl;
}
int main()
{
	int T;
	cin >> T;
	while (T--)
	{
		solve();
	}
	return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值