CodeForces-600E Lomsat gelral DSU on Tree 模板题

CodeForces-600E Lomsat gelral DSU on Tree 模板题

题意

  • 有一颗(n)个结点,以1为根的有根树
  • 每个结点有一种颜色,颜色以编号表示,(i)号结点的颜色编号为(c_i)
  • 如果一种颜色以(x)为根的子树内出现最多,称其为(x)为根的子树中占主导地位。显然同一个子树中可能有多种颜色占主导地位。
  • 求出(1-n)的子树中,占主导地位的颜色的编号和

[1leq n leq 10^5,c_i leq n ]

分析

典型的启发式合并题(DSU on Tree)

核心思想:利用重链剖分的性质优化子树贡献的计算

来解决一类不带修改的子树查询问题

  • 预处理重儿子
  • dfs所有轻儿子,并清空贡献
  • dfs重儿子,不清空贡献
  • 暴力合并除了重儿子以外的贡献

代码

int fa[maxn],son[maxn],dep[maxn],siz[maxn],top[maxn];
vector<int> e[maxn];
ll a[maxn],cnt[maxn],ans[maxn];
ll sum;
int mx,Son;

void dfs1(int u){
	siz[u] = 1;
	for(auto v:e[u]){
		if(v == fa[u]) continue;
		dep[v] = dep[u] + 1;
		fa[v] = u;
		dfs1(v);
		siz[u] += siz[v];
		if(siz[v] > siz[son[u]]) 
			son[u] = v;
	}
}

void add(int x,int val){
	cnt[a[x]] += val;
	if(cnt[a[x]] > mx) mx = cnt[a[x]],sum = a[x];
	else if(cnt[a[x]] == mx) sum += a[x];
	for(auto v:e[x]){
		if(v == fa[x] || v == Son) continue;
		add(v,val);
	}
}

void dfs(int x,int op){
	for(auto v:e[x]){
		if(v == fa[x]) continue;
		if(v != son[x]) dfs(v,0);
	}
	if(son[x]) dfs(son[x],1),Son = son[x];
	add(x,1);
	Son = 0;
	ans[x] = sum;
	if(!op) add(x,-1),sum = 0,mx = 0;
}

int main(){
	int n = readint();
	for(int i = 1;i <= n;i++)
		a[i] = readint();
	for(int i = 1;i < n;i++){
		int u = readint();
		int v = readint();
		e[u].pb(v);
		e[v].pb(u);
	}
	dfs1(1);
	dfs(1,0);
	for(int i = 1;i <= n;i++) 
		cout << ans[i] << ' ';
}
原文地址:https://www.cnblogs.com/hznumqf/p/14076359.html