qscoj:喵哈哈村的卢西奥

喵哈哈村的卢西奥

发布时间: 2017年3月13日 12:13   时间限制: 1000ms   内存限制: 128M

为了拯救喵哈哈村,这个世界必须要存在英雄。

一名叫做卢西奥的英雄站了出来!他现在面临一个难题:

他被要求将一棵树拆成3份,使得每一份中所有节点的权值和相等。

他希望知道,对于一棵给定的有根树,在选取其中2个非根节点并将它们与它们的父亲节点分开后,所形成的三棵子树的节点权值之和能够两两相等的方案有多少种。

两种方案被看做不同的方案,当且仅当形成方案的2个节点不完全相同。

每个输入文件包含多组输入,在输入的第一行为一个整数T,表示数据的组数。

每组输入的第一行为一个整数N,表示给出的这棵树的节点数。

接下来N行,依次描述结点1~N,其中第i行为两个整数Vi和Pi,分别描述这个节点的权值和其父亲节点的编号。

父亲节点编号为0的节点为这棵树的根节点。

满足3<=N<=100000, |Vi|<=100, T<=10

对于每组输入,输出一行Ans,表示方案的数量。

  复制
2
3
1 0
1 1
1 2
4
1 0
1 1
1 2
1 3
1
0


sum[u]:以u点为根的子树所有节点权值之和

树的总权值为sum[root],既然是平均分成三分那么每一分的值一定是sum[root]/3

总共有两种情况:

①两个切割点属于不同子树

②其中一个切割点在以另一个切割点为根的子树中

对于①:深搜时统计一下就好了

对于②:即是需要找到一个点sum[x] = sum[root]*2/3,并且在以x点为根的子树中有点满足sum[p] = sum/3,也在深

统计一下就好


http://qscoj.cn/problem/43/

#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
#define LL long long
vector<int> G[100005];
LL ans, sum[100005], df, sa;
int root, n, val, pri[100005];
LL Jud(int u, int p)
{
	int i, v;
	sum[u] += pri[u];
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		if(v==p)
			continue;
		sum[u] += Jud(v, u);
	}
	return sum[u];
}
void Sech(int u, int p)
{
	int i, v;
	if(sum[u]==val)
		ans += df+sa;
	if(sum[u]==val*2 && u!=root)
		sa += 1;
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		if(v==p)
			continue;
		Sech(v, u);
	}
	if(sum[u]==val)
		df += 1;
	if(sum[u]==val*2 && u!=root)
		sa -= 1;
}
int main(void)
{
	int T, i, x, y;
	scanf("%d", &T);
	while(T--)
	{
		val = 0;
		scanf("%d", &n);
		for(i=1;i<=n;i++)
			G[i].clear();
		memset(sum, 0, sizeof(sum));
		for(i=1;i<=n;i++)
		{
			scanf("%d%d", &x, &y);
			if(y!=0)
			{
				G[y].push_back(i);
				G[i].push_back(y);
			}
			else
				root = i;
			pri[i] = x;
			val += x;
		}
		ans = df = sa = 0;
		if(val%3!=0)
			printf("0\n");
		else
		{
			val /= 3;
			Jud(root, 0);
			Sech(root, 0);
			printf("%lld\n", ans);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值