Lomsat gelral
You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour.
Let's call colour c dominating in the subtree of vertex v if there are no other colours that appear in the subtree of vertex v more times than colour c. So it's possible that two or more colours will be dominating in the subtree of some vertex.
The subtree of vertex v is the vertex v and all other vertices that contains vertex v in each path to the root.
For each vertex v find the sum of all dominating colours in the subtree of vertex v.
Input
The first line contains integer n (1 ≤ n ≤ 105) — the number of vertices in the tree.
The second line contains n integers ci (1 ≤ ci ≤ n), ci — the colour of the i-th vertex.
Each of the next n - 1 lines contains two integers xj, yj (1 ≤ xj, yj ≤ n) — the edge of the tree. The first vertex is the root of the tree.
Output
Print n integers — the sums of dominating colours for each vertex.
Examples
Input
4 1 2 3 4 1 2 2 3 2 4
Output
10 9 3 4
Input
15 1 2 3 1 2 3 3 1 1 3 2 2 1 2 3 1 2 1 3 1 4 1 14 1 15 2 5 2 6 2 7 3 8 3 9 3 10 4 11 4 12 4 13
Output
6 5 4 3 2 3 3 1 1 3 2 2 1 2 3
题目链接:http://codeforces.com/problemset/problem/600/E
题目大意:有一棵n个节点的树,1为根节点,每个节点被染了一个颜色,问 i 节点的子树上 颜色最多的颜色 的和。
思路: 树上启发式合并能在O(nlogn) 的复杂度里快速统计子树的信息。主要思路就是:先遍历轻儿子记录轻儿子的答案,把记录信息的数组清空,最后遍历重儿子,保留重儿子的信息,传递上去。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define ll long long
const int N=100005;
int n,first[N],tot,fa[N],dep[N],siz[N],son[N];
int vis[N],num[N],top;
ll c[N],sum[N],ans[N];
struct node
{
int v,nex;
}e[N<<1];
void init()
{
tot=top=0;
memset(first,-1,sizeof(first));
}
void adde(int u,int v)
{
e[tot].v=v;
e[tot].nex=first[u];
first[u]=tot++;
}
void dfs1(int u,int pre,int depth) //标记dep,fa,siz,son
{
dep[u]=depth;
fa[u]=pre;
siz[u]=1;
for(int i=first[u];~i;i=e[i].nex)
{
int v=e[i].v;
if(v==pre) continue;
dfs1(v,u,depth+1);
if(siz[son[u]]<siz[v]) son[u]=v;
siz[u]+=siz[v];
}
}
void update(int u,int pre,int t)
{
sum[num[c[u]]]-=c[u];
num[c[u]]+=t;
sum[num[c[u]]]+=c[u];
if(sum[top+1]) top++;
if(!sum[top]) top--;
for(int i=first[u];~i;i=e[i].nex)
{
int v=e[i].v;
if(v==pre||vis[v]) continue;
update(v,u,t); //合并没被保留下来的子节点
}
}
void dfs2(int u,int pre,int so)
{
for(int i=first[u];~i;i=e[i].nex)
{
int v=e[i].v;
if(v==pre||v==son[u]) continue; //如果是父节点或者是重儿子
dfs2(v,u,0);
}
if(son[u]) //最后遍历重儿子
{
dfs2(son[u],u,1);
vis[son[u]]=1; //标记保留下来的节点
}
update(u,pre,1);
vis[son[u]]=0;
ans[u]=sum[top]; //记录答案
if(so==0) update(u,pre,-1); //如果不是重节点清除数组
}
int main()
{
scanf("%d",&n);
init();
for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
adde(u,v);
adde(v,u);
}
dfs1(1,0,1);
dfs2(1,0,1);
for(int i=1;i<=n;i++)
printf("%lld ",ans[i]);
printf("\n");
return 0;
}