【CF600E】Lomsat gelral

题目

题目描述
You are given a rooted tree with root in vertex 11 . Each vertex is coloured in some colour.

Let’s call colour cc dominating in the subtree of vertex vv if there are no other colours that appear in the subtree of vertex vv more times than colour cc . So it’s possible that two or more colours will be dominating in the subtree of some vertex.

The subtree of vertex vv is the vertex vv and all other vertices that contains vertex vv in each path to the root.

For each vertex vv find the sum of all dominating colours in the subtree of vertex vv .

输入格式
The first line contains integer nn ( 1<=n<=10^{5}1<=n<=10
5
) — the number of vertices in the tree.

The second line contains nn integers c_{i}c
i

( 1<=c_{i}<=n1<=c
i

<=n ), c_{i}c
i

— the colour of the ii -th vertex.

Each of the next n-1n−1 lines contains two integers x_{j},y_{j}x
j

,y
j

( 1<=x_{j},y_{j}<=n1<=x
j

,y
j

<=n ) — the edge of the tree. The first vertex is the root of the tree.

输出格式
Print nn integers — the sums of dominating colours for each vertex.

题意翻译
有一棵 nn 个结点的以 11 号结点为根的有根树。
每个结点都有一个颜色,颜色是以编号表示的, ii 号结点的颜色编号为 c_ic
i


如果一种颜色在以 xx 为根的子树内出现次数最多,称其在以 xx 为根的子树中占主导地位。显然,同一子树中可能有多种颜色占主导地位。
你的任务是对于每一个 i\in[1,n]i∈[1,n],求出以 ii 为根的子树中,占主导地位的颜色的编号和。
n\le 10^5,c_i\le nn≤10
5
,c
i

≤n
输入输出样例
输入 #1复制
4
1 2 3 4
1 2
2 3
2 4
输出 #1复制
10 9 3 4
输入 #2复制
15
1 2 3 1 2 3 3 1 1 3 2 2 1 2 3
1 2
1 3
1 4
1 14
1 15
2 5
2 6
2 7
3 8
3 9
3 10
4 11
4 12
4 13
输出 #2复制
6 5 4 3 2 3 3 1 1 3 2 2 1 2 3

思路

显然dsu on tree板子题,但今天我是来学线段树合并的

对于每一个点开一棵动态开点权值线段树,然后维护最大值。

转移时线段树合并即可

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
struct Seg
{
	int l,r,sum,val,ans;
}tr[5000077];
const int N=1e5+77;
int rt[N],cl[N],cnt,n,anss[N];
vector<int> g[N];
int push_up(int u)
{
	if(tr[tr[u].l].sum>tr[tr[u].r].sum)
	{
		tr[u].sum=tr[tr[u].l].sum;
		tr[u].val=tr[tr[u].l].val;
		tr[u].ans=tr[tr[u].l].ans;
	}
	if(tr[tr[u].r].sum>tr[tr[u].l].sum)
	{
		tr[u].sum=tr[tr[u].r].sum;
		tr[u].val=tr[tr[u].r].val;
		tr[u].ans=tr[tr[u].r].ans;
	}
	if(tr[tr[u].l].sum==tr[tr[u].r].sum)
	{
		tr[u].sum=tr[tr[u].l].sum;
		tr[u].val=tr[tr[u].l].val;
		tr[u].ans=tr[tr[u].l].ans+tr[tr[u].r].ans;
	}
}
int update(int &u,int l,int r,int pos,int v)
{
	if(!u) u=++cnt;
	if(l==r)
	{
		tr[u].val=l;
		tr[u].sum+=v;
		tr[u].ans=l;
		return 0;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) update(tr[u].l,l,mid,pos,v);
	else update(tr[u].r,mid+1,r,pos,v);
	push_up(u);
}
int merge(int a,int b,int l,int r)
{
	if(!a) return b;
	if(!b) return a;
	if(l==r)
	{
		tr[a].val=l;
		tr[a].sum+=tr[b].sum;
		tr[a].ans=l;
		return a;
	}
	int mid=(l+r)>>1;
	tr[a].l=merge(tr[a].l,tr[b].l,l,mid);
	tr[a].r=merge(tr[a].r,tr[b].r,mid+1,r);
	push_up(a);
	return a;
}
int dfs(int u,int f)
{
	for(int i=0; i<g[u].size(); i++)
	{
		if(g[u][i]==f) continue;
		dfs(g[u][i],u);
		merge(rt[u],rt[g[u][i]],1,100000);
	}
	update(rt[u],1,100000,cl[u],1);
	anss[u]=tr[rt[u]].ans;
}
signed main()
{
	scanf("%lld",&n);
	for(int i=1; i<=n; i++)
	{
		scanf("%lld",&cl[i]);
		rt[i]=i;
		cnt++;
	}
	int from,to;
	for(int i=1; i<n; i++)
	{
		scanf("%lld%lld",&from,&to);
		g[from].push_back(to);
		g[to].push_back(from);
	}
	dfs(1,0);
	for(int i=1; i<=n; i++)
	{
		printf("%lld ",anss[i]);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值