题目链接:Lomsat gelral


题目大意:就是求任意一个子树的出现最多的颜色的值,如果出现次数一样则累加。


然后就是一道树上启发式合并的裸题啦!

我们每次用重链维护信息,往上传递,其他信息暴力更新即可。


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,c[N],cnt[N],mx,sum,res[N],sz[N],son[N],skip;
int head[N],nex[N<<1],to[N<<1],tot;
inline void add(int a,int b){
	to[++tot]=b; nex[tot]=head[a]; head[a]=tot;
}
void dfs(int x,int fa){
	sz[x]=1;
	for(int i=head[x];i;i=nex[i]){
		if(to[i]==fa)	continue;
		dfs(to[i],x);	sz[x]+=sz[to[i]];
		if(sz[to[i]]>sz[son[x]])	son[x]=to[i];
	}
}
void updata(int x,int fa,int k){
	cnt[c[x]]+=k;
	if(x>0&&cnt[c[x]]>mx)	mx=cnt[c[x]],sum=c[x];
	else if(x>0&&cnt[c[x]]==mx)	sum+=c[x];
	for(int i=head[x];i;i=nex[i]){
		if(to[i]!=fa&&to[i]!=skip)	updata(to[i],x,k);
	}
}
void solve(int x,int fa,int k){
	for(int i=head[x];i;i=nex[i]){
		if(to[i]!=fa&&to[i]!=son[x])	solve(to[i],x,0);
	}
	if(son[x])	solve(son[x],x,1),skip=son[x];
	updata(x,fa,1);	res[x]=sum; skip=0;
	if(!k)	updata(x,fa,-1),mx=sum=0;
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++)	cin>>c[i];
	for(int i=1;i<n;i++){
		int a,b;	cin>>a>>b;	add(a,b);	add(b,a);
	}
	dfs(1,0);	solve(1,0,0);
	for(int i=1;i<=n;i++)	cout<<res[i]<<" ";puts("");
	return 0;
}