「CF 600E」 Lomsat gelral

题目链接

戳我

\(Describe\)

给出一棵树,每个节点有一个颜色,求每个节点的子树中颜色数目最多的颜色的和。

\(Solution\)

这道题为什么好多人都写的是启发式合并,表示我不会啊.

这道题不是可以用线段树合并吗?将每个子节点看做一个线段树,维护两个值一个颜色的数目最大值,一个是最大颜色的和,然后不断从儿子向父亲合并即可.

\(Code\)

#include<bits/stdc++.h>
#define int long long 
#define rg register
using namespace std;
int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9')  f= (c=='-')?-1:1,c=getchar();
    while(c>='0'&&c<='9')  x=x*10+c-48,c=getchar();
    return f*x;
}
struct node {
	int to,next;
}a[2000011];
struct node1{
	int ch[2],sum,rt,maxx;
}t[2000011];
int head[200011],cnt,x,y,n,c[200011];
void add(int x,int y){
	a[++cnt].to=y;
	a[cnt].next=head[x];
	head[x]=cnt;
}
int b[200011],tot;
void add(int &rt,int l,int r,int c){
	rt=++tot;
	t[rt].maxx=1,t[rt].sum=c;
	if(l==r)
		return ;
	int mid=(l+r)>>1;
	if(c<=mid)
		add(t[rt].ch[0],l,mid,c);
	else add(t[rt].ch[1],mid+1,r,c);
}
void pushup(int x){
	int fx=t[x].ch[0],fy=t[x].ch[1];
	if(t[fx].maxx==t[fy].maxx)
		t[x].sum=t[fx].sum+t[fy].sum,t[x].maxx=t[fx].maxx;
	else if(t[fx].maxx>t[fy].maxx)
		t[x].sum=t[fx].sum,t[x].maxx=t[fx].maxx;
	else t[x].sum=t[fy].sum,t[x].maxx=t[fy].maxx;
}
int join(int x,int y,int l,int r){
	if(!x||!y)
		return x+y;
	int mid=(l+r)>>1;
	if(l==r){
		t[x].maxx+=t[y].maxx;
		return x;
	}
	t[x].ch[0]=join(t[x].ch[0],t[y].ch[0],l,mid);
	t[x].ch[1]=join(t[x].ch[1],t[y].ch[1],mid+1,r);
	pushup(x);
	return x;
}
void dfs(int x,int fa){
	add(t[x].rt,1,n,b[x]);
	for(int i=head[x];i;i=a[i].next){
		int v=a[i].to;
		if(v==fa)
			continue;
		dfs(v,x);
		t[x].rt=join(t[x].rt,t[v].rt,1,n);
	}
	c[x]=t[t[x].rt].sum;
}
 main(){
	n=read();
	for(int i=1;i<=n;i++)
		b[i]=read();
	for(int i=1;i<n;i++)
		x=read(),y=read(),add(x,y),add(y,x);
	dfs(1,0);
	for(int i=1;i<=n;i++)
		printf("%I64d ",c[i]);
}
posted @ 2019-01-24 11:23  撤云  阅读(176)  评论(1编辑  收藏  举报
……