学习一下$dsu \ on \ tree$。。
这个东西可以处理很多无修改子树问题,复杂度通常为$O(nlogn)$。
主要操作是:我们先把整棵树链剖一下,然后每次先递归轻儿子,再递归重儿子。
对于每棵子树,我们暴力加入整棵子树的贡献。如果是重儿子的子树则另外处理:加入贡献时不考虑加重儿子所在的子树,而在消除贡献时也不消除重儿子的子树,直到它成为某个点的轻儿子的子树的一部分时再消除贡献。
复杂度:因为每个轻儿子最多被加入$O(logn)$次(递归轻儿子时$size$至少$/2$),每条重链最多只会被加入$O(logn)$次,所以复杂度是$O(nlogn)$的。
说得有点玄学,还是看看代码吧。。
//It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1<<30)
#define N (200010)
#define il inline
#define RG register
#define ll long long using namespace std; struct edge{ int nt,to; }g[N<<]; int head[N],col[N],son[N],sz[N],c[N],n,num,Mx,flag;
ll ans[N],Sum; il int gi(){
RG int x=,q=; RG char ch=getchar();
while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar();
while (ch>='' && ch<='') x=x*+ch-,ch=getchar();
return q*x;
} il void insert(RG int from,RG int to){
g[++num]=(edge){head[from],to},head[from]=num; return;
} il void dfs1(RG int x,RG int p){
sz[x]=; RG int v;
for (RG int i=head[x];i;i=g[i].nt){
v=g[i].to; if (v==p) continue;
dfs1(v,x),sz[x]+=sz[v];
if (sz[son[x]]<=sz[v]) son[x]=v;
}
return;
} il void add(RG int x,RG int p,RG int val){
col[c[x]]+=val; RG int v;
if (Mx<col[c[x]]) Mx=col[c[x]],Sum=c[x];
else if (Mx==col[c[x]]) Sum+=c[x];
for (RG int i=head[x];i;i=g[i].nt){
v=g[i].to; if (v==p || v==flag) continue;
add(v,x,val);
}
return;
} il void dfs2(RG int x,RG int p,RG int fg){
RG int v;
for (RG int i=head[x];i;i=g[i].nt){
v=g[i].to; if (v!=p && v!=son[x]) dfs2(v,x,);
}
if (son[x]) dfs2(son[x],x,),flag=son[x];
add(x,p,),flag=,ans[x]=Sum;
if (fg) add(x,p,-),Mx=Sum=; return;
} int main(){
#ifndef ONLINE_JUDGE
freopen("600E.in","r",stdin);
freopen("600E.out","w",stdout);
#endif
n=gi();
for (RG int i=;i<=n;++i) c[i]=gi();
for (RG int i=,u,v;i<n;++i)
u=gi(),v=gi(),insert(u,v),insert(v,u);
dfs1(,),dfs2(,,);
for (RG int i=;i<=n;++i) printf("%I64d ",ans[i]);
return ;
}