题目大意:
给你一个树,每个节点上有有一个部落,以及部落的人数,要你求出每个节点的子树里面人数最多的部落是哪一个(人数相同部落编号最小的)。
思路:
树上启发式合并,每次先做轻节点,后做重节点,然后开一个桶维护,轻节点的桶做完以后清理,重节点的桶不用清理,直接传给父亲。
程序:
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 400005
struct data{int to,next;}e[N*2];
struct data1{int a,b;}ans[N];
struct ms{int a,b;}ms[N];
int last[N],size[N],a[N],b[N],t[N];
int n,m,cnt,u,v;
void add(int x,int y){
e[++cnt].to=y; e[cnt].next=last[x]; last[x]=cnt;
e[++cnt].to=x; e[cnt].next=last[y]; last[y]=cnt;
}
void dfs(int x,int fa){
size[x]=1;
for (int i=last[x];i;i=e[i].next)
if (e[i].to!=fa){
dfs(e[i].to,x);
size[x]+=size[e[i].to];
if (size[e[i].to]>ms[x].a) ms[x].a=size[e[i].to],ms[x].b=e[i].to;
}
}
void jia(int x,int fa,int la){
t[b[x]]+=a[x];
if (t[b[x]]==ans[la].a) ans[la].b=std::min(b[x],ans[la].b);
if (t[b[x]]>ans[la].a) ans[la].a=t[b[x]],ans[la].b=b[x];
for (int i=last[x];i;i=e[i].next)
if (fa!=e[i].to) jia(e[i].to,x,la);
}
void clean(int x,int fa){
t[b[x]]-=a[x];
for (int i=last[x];i;i=e[i].next)
if (fa!=e[i].to) clean(e[i].to,x);
}
void solve(int x,int fa){
for (int i=last[x];i;i=e[i].next)
if (e[i].to!=fa&&e[i].to!=ms[x].b) solve(e[i].to,x);
for (int i=last[x];i;i=e[i].next)
if (e[i].to!=fa&&e[i].to==ms[x].b) solve(e[i].to,x);
ans[x].a=ans[ms[x].b].a;
ans[x].b=ans[ms[x].b].b;
for (int i=last[x];i;i=e[i].next)
if (e[i].to!=fa&&e[i].to!=ms[x].b) jia(e[i].to,x,x);
t[b[x]]+=a[x];
if (t[b[x]]==ans[x].a) ans[x].b=std::min(b[x],ans[x].b);
if (t[b[x]]>ans[x].a) ans[x].a=t[b[x]],ans[x].b=b[x];
if (ms[fa].b!=x) clean(x,fa);
}
int main(){
freopen("endless.in","r",stdin);
freopen("endless.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
}
for (int i=1;i<=n;i++) scanf("%d%d",&b[i],&a[i]);
dfs(1,0);
solve(1,0);
for (int i=1;i<=n;i++) printf("%d %d\n",ans[i].b,ans[i].a);
}