树上启发式合并(详解)

核心思想

借用了一个节点到根的路径上轻边个数不会超过logn条。

故重节点保留,轻节点删去,多重统计。

实际复杂度(nlogn)

例题

Lomsat gelral - 洛谷

AC 代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
int col[100010],ans[100010];
vector<int> g[100010];
int son[100010];
int sz[100010];
int sum,mx;
int Son;
int cnt[100010];
void dfs1(int u,int fa){
	sz[u] = 1;
	for(int v:g[u]){
		if(v == fa)continue;
		dfs1(v,u);
		sz[u]+=sz[v];
		if(sz[son[u]]<sz[v]){
			son[u] = v;
		}
	}
}
void add(int u,int fa,int val){
	cnt[col[u]]+=val;
	int tp = col[u];
	if(cnt[tp] > mx){
		mx = cnt[tp];
		sum = tp;
	}
	else if(cnt[tp] == mx){
		sum+=tp;
	}
	for(int v:g[u]){
		if(v == fa||v == Son)continue;
		add(v,u,val);
	}
}
void dfs2(int u,int fa,int opt){
	for(int v:g[u]){
		if(v == fa||v == son[u])continue;
		dfs2(v,u,0);
	}
	if(son[u]){
		dfs2(son[u],u,1),Son = son[u];
	}
	add(u,fa,1);Son = 0;
	ans[u] = sum;
	if(!opt){
		add(u,fa,-1),sum = mx = 0;
	}
}
signed main(){
	cin>>n;
	for(int i = 1;i <= n;i++)cin>>col[i];
	for(int i = 1;i < n;i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs1(1,0);
	dfs2(1,1,0);
	for(int i = 1;i <= n;i++){
		cout<<ans[i]<<" ";
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值