CF600E Lomsat gelral【题解】线段树合并
Luogu题目:https://www.luogu.com.cn/problem/CF600E
值域线段树加合并。
基本上就是裸的。
代码如下:
#include<bits/stdc++.h> #define int long long using namespace std; const int maxn=1e5+10; int c[maxn],n,cnt; struct node{ int nxt,to; #define nxt(x) e[x].nxt #define to(x) e[x].to }e[maxn<<1]; int head[maxn],tot,rt[maxn],ans[maxn]; inline void add(int from,int to){ to(++tot)=to; nxt(tot)=head[from];head[from]=tot; } struct tree{ int lc,rc,tg,dt; }t[maxn*50]; inline void pushup(int p){ t[p].dt=max(t[t[p].lc].dt,t[t[p].rc].dt); if(t[t[p].lc].dt==t[t[p].rc].dt) t[p].tg=t[t[p].lc].tg+t[t[p].rc].tg; else t[p].tg= t[t[p].lc].dt > t[t[p].rc].dt ? t[t[p].lc].tg : t[t[p].rc].tg; } inline int merge(int p,int q,int l,int r){ if(!p) return q; if(!q) return p; if(l==r){ t[p].dt+=t[q].dt; t[p].tg=l; return p; } int mid=(l+r)>>1; t[p].lc=merge(t[p].lc,t[q].lc,l,mid); t[p].rc=merge(t[p].rc,t[q].rc,mid+1,r); pushup(p); return p; } void change(int &p,int l,int r,int wh){ if(!p) p=++cnt; if(l==r){ t[p].dt+=1;t[p].tg=wh;return; } int mid=(l+r)>>1; if(wh<=mid) change(t[p].lc,l,mid,wh); else change(t[p].rc,mid+1,r,wh); pushup(p); } int dfs(int now,int fa){ for(int i=head[now];i;i=nxt(i)){ int to=to(i); if(to==fa) continue; dfs(to,now); rt[now]=merge(rt[now],rt[to],1,maxn); } change(rt[now],1,maxn,c[now]); ans[now]=t[rt[now]].tg; } signed main() { scanf("%lld",&n); for(int i=1;i<=n;i++) scanf("%lld",&c[i]),rt[i]=++cnt; for(int i=1;i<n;i++){ int x,y;scanf("%lld%lld",&x,&y); add(x,y);add(y,x); } dfs(1,0); for(int i=1;i<=n;i++) printf("%lld ",ans[i]); return 0; }