树上启发式合并(dsu on tree),也叫静态树链分治模板题,预处理dfn可以节省一个dfs,改写成for循环,常数更小。
#include<bits/stdc++.h> using namespace std; const int MAXN=100005; int n; int g[MAXN],tot,col[MAXN],dfn,u,v; int sz[MAXN],deep[MAXN],fa[MAXN],son[MAXN],L[MAXN],R[MAXN],index[MAXN],skp; long long sum,ans[MAXN]; int cnt[MAXN],nowmax; struct edges { int to,next; }e[2*MAXN]; void add_edge(int from,int to) { e[++tot].to=to; e[tot].next=g[from]; g[from]=tot; return; } void dfs(int x,int dep,int father) { sz[x]=1; deep[x]=dep; fa[x]=father; son[x]=0; L[x]=++dfn; index[dfn]=x; for(int i=g[x];i;i=e[i].next) { if(e[i].to!=father) { dfs(e[i].to,dep+1,x); sz[x]+=sz[e[i].to]; if(!son[x]||sz[son[x]]<sz[e[i].to])son[x]=e[i].to; } } R[x]=dfn; return; } void get_data(int x,int op) { for(int i=L[x];i<=R[x];++i) { if(index[i]==skp) { i=R[index[i]]; continue; } cnt[col[index[i]]]+=op; if(nowmax<cnt[col[index[i]]]) { nowmax=cnt[col[index[i]]]; sum=col[index[i]]; } else if(nowmax==cnt[col[index[i]]]) { sum+=col[index[i]]; } } } void dsu(int x,int fa,bool del) { for(int i=g[x];i;i=e[i].next) { if(e[i].to==fa||e[i].to==son[x])continue; dsu(e[i].to,x,true); } ///skip the heavy son if(son[x]) { dsu(son[x],x,false); skp=son[x]; } ///get data from light son and itself get_data(x,1); ans[x]=sum; ///if delete clear all if(del) { skp=0; get_data(x,-1); sum=0; nowmax=0; } return; } int main() { scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&col[i]); } for(int i=1;i<n;++i) { scanf("%d %d",&u,&v); add_edge(u,v); add_edge(v,u); } dfs(1,1,-1); dsu(1,-1,0); for(int i=1;i<=n;++i) { printf("%lld%c",ans[i],i==n?'\n':' '); } return 0; }