HDU 6035 Colorful Tree [树形dp]

题意:给一颗树,定义树上路径u到v的价值为路径上不同颜色的节点的数量,问所有路径的总价值为多少

题解:根据题意,所需要求解的价值可以转换为,假设每条路径上包含所有的颜色,也就是n*(n-1)/2*(总颜色个数),然后减去每个颜色对不存在这个颜色的的所有路径的贡献。

dfs树上的每一个节点,对于当前节点,我们对每一个子树,用sum数组记录每一个颜色的截断值,于是这个子树的size-父节点颜色的截断值 来表示该子树与父节点颜色不同的连通块的总个数。

AC代码:

#include<stdio.h>
#include<vector>
#include<string.h>
#define N 200005
using namespace std;
typedef long long ll;
ll col[N],size[N];
ll mark[N];
vector<ll>vt[N];
ll sum[N];
ll ans=0;
void dfs(ll u,ll fa)
{
	ll all=0;
	size[u]=1;
	for(ll i=0;i<vt[u].size();i++)
	{
		ll to=vt[u][i];
		if(to==fa)continue;
		ll s=sum[col[u]];
		dfs(to,u);
		size[u]+=size[to];
		ll step=sum[col[u]]-s;
		all+=step;
		ans+=(size[to]-step)*(size[to]-step-1)/2;
	}
	sum[col[u]]+=-all+size[u];
}
int main()
{
	ll n;
	ll cas=1;
	while(~scanf("%lld",&n))
	{
		memset(mark,0,sizeof(mark));
		memset(size,0,sizeof(size));
		memset(sum,0,sizeof(sum));
		for(ll i=0;i<N;i++)vt[i].clear();
		ll gg=0;
		ans=0;
		for(ll i=1;i<=n;i++)
		{
			scanf("%lld",&col[i]);
			gg+=mark[col[i]]^1;
			mark[col[i]]=1;
		}
		for(ll i=0;i<n-1;i++)
		{
			ll u,v;
			scanf("%lld%lld",&u,&v);
			vt[u].push_back(v);
			vt[v].push_back(u);
		}
		dfs(1,-1);
		ll ANS=n*(n-1)*gg/2;
		for(ll i=1;i<=n;i++)
		{
			if(gg==col[1]||!mark[i])continue;
			ans+=(n-sum[i])*(n-sum[i]-1)/2;
		}
		printf("Case #%lld: %lld\n",cas++,ANS-ans);
	}
}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值