CodeForces 600E Lomsat gelral (樹上啟發式合併模板)

是羊駝鴨發表於2020-11-09

題目連結:點選這裡

題目大意:
給定一棵以 1 1 1 為根的樹,每個節點都有一個顏色編號。求以每個節點為根的子樹中,顏色出現次數最多的編號之和。(次數最多的可能有多個顏色)
題目分析:
樹啟模板,更新的時候,記錄顏色出現的次數,次數超過或者等於最大值時進行更新即可

具體細節見程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int read()
{
	int res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 1e5+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
vector<int>v[maxn];
int col[maxn],siz[maxn],son[maxn];
ll ans[maxn],cnt[maxn],sum,maxx;
void update(int u,int fa,int val,int heavy)
{
	cnt[col[u]] += val;
	if(cnt[col[u]] > maxx)
	{
		sum = col[u];
		maxx = cnt[col[u]];
	}
	else if(cnt[col[u]] == maxx)
		sum += col[u];
	for(auto it:v[u])
	{
		if(it == fa || it == heavy) continue;
		update(it,u,val,heavy);
	}
}
void dfs1(int u,int fa)
{
	siz[u] = 1;
	for(auto it:v[u])
	{
		if(it == fa) continue;
		dfs1(it,u);
		siz[u] += siz[it];
		if(siz[it] > siz[son[u]]) son[u] = it;
	}
}
void dfs2(int u,int fa,int keep)
{
	for(auto it:v[u])
	{
		if(it == fa || it==son[u]) continue;
		dfs2(it,u,0);
	}
	if(son[u]) dfs2(son[u],u,1);
	update(u,fa,1,son[u]);
	ans[u] = sum;
	if(!keep)
	{
		update(u,fa,-1,-1);
		sum = maxx = 0;
	}
}
int main()
{
	int n = read();
	for(int i = 1;i <= n;++i)
		col[i] = read();
	for(int i = 1;i < n;i++)
	{
		int u = read(),v = read();
		::v[u].push_back(v);
		::v[v].push_back(u);
	}
	dfs1(1,0);
	dfs2(1,0,1);
	for(int i = 1;i <= n;i++)
		printf("%lld%c",ans[i],i==n?'\n':' ');
	return 0;
}


相關文章