【CF600E】Lomsat gelral

题目

题目链接:https://codeforces.com/problemset/problem/600/E
有一棵 \(n\) 个结点的以 \(1\) 号结点为根的有根树
每个结点都有一个颜色,颜色是以编号表示的, \(i\) 号结点的颜色编号为 \(c_i\)
如果一种颜色在以 \(x\) 为根的子树内出现次数最多,称其在以 \(x\) 为根的子树中占主导地位。显然,同一子树中可能有多种颜色占主导地位。
你的任务是对于每一个 \(i\in[1,n]\),求出以 \(i\) 为根的子树中,占主导地位的颜色的编号和。
\(n\le 10^5,c_i\le n\)

思路

一眼线段树合并,但是被安排用 dsu on tree 做 /kk
\(cnt[x]\) 表示颜色 \(x\) 出现的次数。那么我们对于一个点 \(x\),先求出其轻儿子的答案并将 \(cnt\) 清空,然后求重儿子的答案并不清空。接下来再便利轻子树的每一个节点把贡献加上即可。
显然复杂度瓶颈在于每一个点最多做多少次贡献。一个点被计算次数取决于从它到根的轻边条数。再树剖中我们都知道,重链是 \(O(\log n)\) 级别的,每两个重链之间夹着恰好一个轻边,所以每一个点贡献次数是 \(O(\log n)\) 的。
时间复杂度 \(O(n\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=100010;
int n,tot,head[N],cnt[N],col[N],size[N],son[N];
ll ans[N],maxn,sum;

struct edge
{
	int next,to;
}e[N*2];

void add(int from,int to)
{
	e[++tot].to=to;
	e[tot].next=head[from];
	head[from]=tot;
}

void dfs1(int x,int fa)
{
	size[x]=1;
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=fa)
		{
			dfs1(v,x);
			size[x]+=size[v];
			if (size[v]>size[son[x]]) son[x]=v;
		}
	}
}

void check(int x)
{
	if (cnt[col[x]]>maxn)
		maxn=cnt[col[x]],sum=col[x];
	else if (cnt[col[x]]==maxn)
		sum+=col[x];
}

void dfs3(int x,int fa,int v)
{
	cnt[col[x]]+=v;
	check(x);
	for (int i=head[x];~i;i=e[i].next)
		if (e[i].to!=fa) dfs3(e[i].to,x,v);
}

void dfs2(int x,int fa,bool clr)
{
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=fa && v!=son[x]) dfs2(v,x,1);
	}
	sum=maxn=0;
	if (son[x]) dfs2(son[x],x,0);
	cnt[col[x]]++;
	check(x);
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=fa && v!=son[x]) dfs3(v,x,1);
	}
	ans[x]=sum;
	if (clr)
	{
		cnt[col[x]]--;
		for (int i=head[x];~i;i=e[i].next)
		{
			int v=e[i].to;
			if (v!=fa) dfs3(v,x,-1);
		}
		sum=maxn=0;
	}
}

int main()
{
	memset(head,-1,sizeof(head));
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d",&col[i]);
	for (int i=1,x,y;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y); add(y,x);
	}
	dfs1(1,0); dfs2(1,0,0);
	for (int i=1;i<=n;i++)
		printf("%lld ",ans[i]);
	return 0;
}
posted @ 2020-10-02 22:54  stoorz  阅读(119)  评论(0编辑  收藏  举报