题目链接:E. Lomsat gelral
最开始做这道题的时候,采用了dsu on tree的做法,其实这道题也可以用线段树合并来做。
就是用线段树动态维护区间的众数,然后更新答案即可。
但是要注意merge的时候,我们需要传入区间l,r,因为我们到端点的时候,值是一样的,所以直接更新,和pushup不一样。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10,M=N*20;
int mx[M],lc[M],rc[M],res[M],n,c[N],cnt,ans[N],rt[N];
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;}
inline void push_up(int p){
if(mx[lc[p]]>mx[rc[p]]){
mx[p]=mx[lc[p]]; res[p]=res[lc[p]];
}else if(mx[lc[p]]<mx[rc[p]]){
mx[p]=mx[rc[p]]; res[p]=res[rc[p]];
}else{
mx[p]=mx[rc[p]]; res[p]=res[lc[p]]+res[rc[p]];
}
}
void change(int &p,int l,int r,int x){
if(!p) p=++cnt;
if(l==r){mx[p]++; res[p]=x; return;}
int mid=l+r>>1;
if(x<=mid) change(lc[p],l,mid,x);
else change(rc[p],mid+1,r,x);
push_up(p);
}
int merge(int x,int y,int l,int r){
if(!x||!y) return x+y;
if(l==r){mx[x]+=mx[y]; res[x]=l; return x;}
int mid=l+r>>1;
lc[x]=merge(lc[x],lc[y],l,mid);
rc[x]=merge(rc[x],rc[y],mid+1,r);
push_up(x);
return x;
}
void dfs(int x,int fa){
for(int i=head[x];i;i=nex[i]){
if(to[i]==fa) continue;
dfs(to[i],x); merge(rt[x],rt[to[i]],1,n);
}
ans[x]=res[rt[x]];
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++) scanf("%lld",&c[i]),change(rt[i],1,n,c[i]);
for(int i=1,a,b;i<n;i++) scanf("%lld %lld",&a,&b),add(a,b),add(b,a);
dfs(1,0);
for(int i=1;i<=n;i++) printf("%lld ",ans[i]);puts("");
return 0;
}