[CF600E]Lomsat gelral

Description:

一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和。

Hint:

\(n \le 10^5\)

Solution:

线段树合并裸题?

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mxn=5e5+5;
int n,m,s,cnt,a[mxn],rt[mxn<<4],ls[mxn<<4],rs[mxn<<4],tot[mxn<<4];
ll sum[mxn<<4],ans[mxn];
int hd[mxn];

inline int read() {
	char c=getchar(); int x=0,f=1;
	while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
	return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}

struct ed {
	int to,nxt;
}t[mxn<<1];

inline void add(int u,int v) {
	t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}

int merge(int u,int v,int l,int r) {
	if(!u) return v;
	if(!v) return u;
	if(l==r) {
		tot[u]+=tot[v];
		return u;
	}
	int mid=(l+r)>>1;
	ls[u]=merge(ls[u],ls[v],l,mid);
	rs[u]=merge(rs[u],rs[v],mid+1,r);
	tot[u]=max(tot[ls[u]],tot[rs[u]]); ll res=0;
	if(tot[u]==tot[rs[u]]) res+=sum[rs[u]];
	if(tot[u]==tot[ls[u]]) res+=sum[ls[u]];
	sum[u]=res;
	return u;
}

void update(int l,int r,int pos,int val,int &p) {
	if(!p) p=++s;
	if(l==r) {++tot[p]; sum[p]=l; return ;}
	int mid=(l+r)>>1;
	if(pos<=mid) update(l,mid,pos,val,ls[p]);
	else update(mid+1,r,pos,val,rs[p]);
    tot[p]=max(tot[ls[p]],tot[rs[p]]); ll res=0;
    if(tot[p]==tot[rs[p]]) res+=sum[rs[p]];
    if(tot[p]==tot[ls[p]]) res+=sum[ls[p]];
	sum[p]=res;
}

void dfs(int u,int fa) {
	for(int i=hd[u];i;i=t[i].nxt) {
		int v=t[i].to;
		if(v==fa) continue ;
		dfs(v,u); rt[u]=merge(rt[u],rt[v],1,n);
	}
	update(1,n,a[u],1,rt[u]);
	ans[u]=sum[rt[u]];
}

int main()
{
	n=read(); int u,v;
	for(int i=1;i<=n;++i) a[i]=read();
	for(int i=1;i<n;++i) {
		u=read(); v=read();
		add(u,v); add(v,u);
	}
	dfs(1,0);
	for(int i=1;i<=n;++i) printf("%I64d\n",ans[i]);
    return 0;
}
posted @ 2019-03-30 13:22  cloud_9  阅读(105)  评论(0)    收藏  举报