發現答案一定在直徑上,然後以直徑端點爲根求出每個點的長兒子,然後一下即可求出每個點的答案。
#include<bits/stdc++.h>
#define maxn 200005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;
char cb[1<<16],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<16,stdin),cs==ct)?0:*cs++)
void read(int &res){
char ch;
for(;!isdigit(ch=getc()););
for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}
int n,m,cl[maxn],c[maxn],ans[maxn];
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int S,T,dis[maxn];
void dfs0(int u,int ff,int d,int &s){
dis[u] = d;
if(d > dis[s]) s = u;
for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff)
dfs0(v,u,d+1,s);
}
int son[maxn] , len[maxn],dep[maxn];
void dfs1(int u,int ff){
son[u] = len[u] = 0;
dep[u] = dep[ff] + 1;
for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff)
dfs1(v,u) , (len[v] > len[son[u]]) && (son[u] = v);
len[u] = len[son[u]] + 1;
}
int sta[maxn],tp,tr,sm;
void dfs2(int u,int ff){
for(;tr < tp && dep[u] - dep[sta[tr+1]] > len[u] - 1;)
sm += (c[cl[sta[++tr]]]++ == 0);
ans[u] = max(ans[u] , sm);
if(son[u]){
int sl = 0;
for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff && v!=son[u])
sl = max(sl , len[v]);
for(;tp && dep[u] - dep[sta[tp]] <= sl;tp--)
if(tr == tp)
sm -= (--c[cl[sta[tr--]]] == 0);
sta[++tp] = u;
dfs2(son[u],u);
for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff && v!=son[u]){
for(;tp && dep[u] - dep[sta[tp]] <= len[u] - 1;tp--)
if(tr == tp)
sm -= (--c[cl[sta[tr--]]] == 0);
if(sta[tp] != u) sta[++tp] = u;
dfs2(v,u);
}
}
}
void Solve(int s){
tp = tr = sm = 0;
memset(c,0,sizeof c);
dfs1(s,0);
dfs2(s,0);
}
int main(){
read(n),read(m);
rep(i,1,n-1){
int u,v;read(u),read(v);
Node(u,v),Node(v,u);
}
rep(i,1,n) read(cl[i]);
memset(dis,-1,sizeof dis);
dfs0(1,0,0,S);
memset(dis,-1,sizeof dis);
dfs0(S,0,0,T);
Solve(S);
Solve(T);
rep(i,1,n) printf("%d\n",ans[i]);
}