线段树合并 CF 600E Lomsat gelral

这题和[Vani有约会]雨天的尾巴 有些神似的地方 算是线段树合并的模板题把   每个结点维护一颗线段树 线段树维护颜色出现个数 以及编号和  pushup要写好 想清楚 最后dfs合并起来就行了

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
typedef long long ll;
#define ls T[rt].l
#define rs T[rt].r
ll ans[N];
int h[N],to[N<<1],nex[N<<1],cur,rt[N],tot;
struct tree{
	int ct,l,r;
	ll sum;
}T[N*50];
void add_edge(int x,int y){
	to[++cur]=y;nex[cur]=h[x];h[x]=cur;
}
void pushup(int rt){
	if(T[ls].ct==T[rs].ct){
		T[rt].sum=T[ls].sum+T[rs].sum;
		T[rt].ct=T[ls].ct;
	}else{
		if(T[ls].ct>T[rs].ct) T[rt].sum=T[ls].sum,T[rt].ct=T[ls].ct;
		else T[rt].sum=T[rs].sum,T[rt].ct=T[rs].ct;
	}
}
void update(int &rt,int l,int r,int pos,int val){
	if(!rt) rt=++tot;
	if(l==r){
		T[rt].ct+=val;T[rt].sum=l;
		return;
	}
	int mid = l+r>>1;
	if(pos<=mid) update(ls,l,mid,pos,val);
	else update(rs,mid+1,r,pos,val);
	pushup(rt);
}
int merge(int x,int y,int l,int r){
	if(!x||!y) return x+y;
	if(l==r){
		T[x].ct+=T[y].ct;
		T[x].sum=l;
		return x;
	}
	int mid = l+r>>1;
	T[x].l=merge(T[x].l,T[y].l,l,mid);
	T[x].r=merge(T[x].r,T[y].r,mid+1,r);
	pushup(x);
	return x;
}
void dfs(int u,int f){
	for(int i = h[u]; i; i = nex[i]){
		if(to[i]!=f){
			dfs(to[i],u);
			rt[u]=merge(rt[u],rt[to[i]],1,1e5);
		}
	}
	ans[u]=T[rt[u]].sum;
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i = 1; i <= n; i++){
		int c;
		scanf("%d",&c);
		update(rt[i],1,1e5,c,1);		
	}
	for(int i = 2; i <= n; i++){
		int x,y;
		scanf("%d%d",&x,&y);
		add_edge(x,y);
		add_edge(y,x);
	}
	dfs(1,0);
	for(int i = 1; i <= n; i++) 
	printf("%lld ",ans[i]);
	puts("");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43824564/article/details/106321165
今日推荐