题目链接:【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;
}