codeforces 600E. Lomsat gelral(教育场 树形dp)

该博客探讨了如何利用树形动态规划方法解决codeforces上的一道竞赛问题——E. Lomsat gelral。题目要求找到一棵有n个节点的树中,以节点v为根的子树的所有控制颜色的总和。控制颜色是指在子树内没有其他颜色出现次数超过它的颜色。博客中指出,递归过程中关键在于使用map记录子树中不同颜色出现的次数。
摘要由CSDN通过智能技术生成

题目链接:【E. Lomsat gelral】

一棵树有n(1<=n<=10^5)个节点,每个节点有一种颜色c(1<=c<=n)

一棵树的控制颜色的定义:在节点k的子树中,不存在另一种颜色出现的总次数大于颜色ci,那么ci就是以k为根的树的控制颜色,也就是说一棵树可以有多个控制颜色

求以节点v为根的树的控制颜色总和

样例

4
1 2 3 4
1 2
2 3
2 4

这一题难点以及特点就是向上一层递归时要用map[ i ][ ci ][ num ]来合并树,map的意思是节点i的子树中,颜色ci出现的次数是num

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
using namespace std;
#define inf 200005
#define ll __int64
vector<int>vec[inf];
map<int, int>s[inf];
int color[inf], n, mx[inf], w[inf];
ll sum[inf], cnt[inf];
void conbine(int a, int b)
{
	if(s[w[a]].size() < s[w[b]].size()) //防止超内存,每次都树小的加到树大的上面去 
	{
		swap(w[a], w[b]);
	}
	int id = w[a];
	map<int, int>::iterator it;
	for(it=s[w[b]].begin(); it!=s[w[b]].end(); ++it)
	{
		int col = (*it).first;
		int num = (*it).second;
		s[id][col]+=num;
		if(s[id][col] > mx[id])
		{
			mx[id] = s[id][col];
			cnt[id] = 0;
		}
		if(s[id][col] == mx[id]) cnt[id]+=(ll)col;
	}
}
void dfs(int p, int u)
{
	int flag = 0;
	for(int i=0; i<vec[u].size(); i++)
	{
		int v = vec[u][i];
		if(v != p)
		{
			dfs(u, v);
			conbine(u, v);
		} 
	}
	sum[u] = cnt[w[u]];
}
int main()
{
	scanf("%d", &n);
	for(int i=1; i<=n; i++)
	{
		scanf("%d", &color[i]);
		s[i][color[i]] = 1;
		mx[i] = 1;
		w[i] = i;
		cnt[i] = (ll)color[i];
	}
	for(int i=1; i<n; i++)
	{
		int u, v;
		scanf("%d%d", &u, &v);
		vec[u].push_back(v);
		vec[v].push_back(u);
	}
	dfs(-1, 1);
	for(int i=1; i<=n; i++)
	{
		if(i == n) printf("%I64d\n", sum[i]);
		else printf("%I64d ", sum[i]);
	}
	return 0;
}    


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值