CodeForces - 600E Lomsat gelral (树上启发式合并)

这篇博客介绍了如何解决CodeForces上的600E问题——Lomsat gelral。这是一个关于树的题目,要求在每个节点的子树中找出支配颜色(出现次数最多)的总和。博主提供了使用树上启发式合并的算法思路,该算法能在O(nlogn)的时间复杂度内完成任务,并给出了代码实现。
摘要由CSDN通过智能技术生成

Lomsat gelral

 

You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour.

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

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

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

Input

The first line contains integer n (1 ≤ n ≤ 105) — the number of vertices in the tree.

The second line contains n integers ci (1 ≤ ci ≤ n), ci — the colour of the i-th vertex.

Each of the next n - 1 lines contains two integers xj, yj (1 ≤ xj, yj ≤ n) — the edge of the tree. The first vertex is the root of the tree.

Output

Print n integers — the sums of dominating colours for each vertex.

Examples

Input

4
1 2 3 4
1 2
2 3
2 4

Output

10 9 3 4

Input

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

Output

6 5 4 3 2 3 3 1 1 3 2 2 1 2 3

 

题目链接:http://codeforces.com/problemset/problem/600/E

题目大意:有一棵n个节点的树,1为根节点,每个节点被染了一个颜色,问 i 节点的子树上 颜色最多的颜色 的和。

思路: 树上启发式合并能在O(nlogn) 的复杂度里快速统计子树的信息。主要思路就是:先遍历轻儿子记录轻儿子的答案,把记录信息的数组清空,最后遍历重儿子,保留重儿子的信息,传递上去。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define ll long long
const int N=100005;
int n,first[N],tot,fa[N],dep[N],siz[N],son[N];
int vis[N],num[N],top;
ll c[N],sum[N],ans[N];
struct node
{
    int v,nex;
}e[N<<1]; 
void init()
{
    tot=top=0;
    memset(first,-1,sizeof(first));
}
void adde(int u,int v)
{
    e[tot].v=v;
    e[tot].nex=first[u];
    first[u]=tot++;
}
void dfs1(int u,int pre,int depth) //标记dep,fa,siz,son
{
    dep[u]=depth;
    fa[u]=pre;
    siz[u]=1;
    for(int i=first[u];~i;i=e[i].nex)
    {
        int v=e[i].v;
        if(v==pre) continue;
        dfs1(v,u,depth+1);
        if(siz[son[u]]<siz[v]) son[u]=v;
        siz[u]+=siz[v];
    }
}
void update(int u,int pre,int t)
{
    sum[num[c[u]]]-=c[u]; 
    num[c[u]]+=t;
    sum[num[c[u]]]+=c[u];
    if(sum[top+1]) top++;
    if(!sum[top]) top--;
    for(int i=first[u];~i;i=e[i].nex)
    {
        int v=e[i].v;
        if(v==pre||vis[v]) continue;
        update(v,u,t);  //合并没被保留下来的子节点
    }
}
void dfs2(int u,int pre,int so)
{
    for(int i=first[u];~i;i=e[i].nex)
    {
        int v=e[i].v;
        if(v==pre||v==son[u]) continue; //如果是父节点或者是重儿子
        dfs2(v,u,0);
    }
    if(son[u]) //最后遍历重儿子
    {
        dfs2(son[u],u,1);
        vis[son[u]]=1;  //标记保留下来的节点
    }
    update(u,pre,1);
    vis[son[u]]=0;
    ans[u]=sum[top]; //记录答案
    if(so==0) update(u,pre,-1); //如果不是重节点清除数组
}
int main()
{
    scanf("%d",&n);
    init();
    for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
    int u,v;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        adde(u,v);
        adde(v,u);
    }
    dfs1(1,0,1);
    dfs2(1,0,1);
    for(int i=1;i<=n;i++)
        printf("%lld ",ans[i]);
    printf("\n");
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]中提到了一种树形动态规划的方法来解决CodeForces - 982C问题。在这个问题中,subtree指的是子连通块,而不是子树。为了使cnt_white - cnt_black尽可能大,可以使用两次树形动态规划来求解。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。如果ans\[u\]为正,则减去dp\[v\]就是树链所代表的子树的权值。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] 问题: CodeForces - 982C 树形DP是什么问题?如何解决? 回答: CodeForces - 982C是一个树形动态规划问题。在这个问题中,需要求解子连通块的最大权值和,使得cnt_white - cnt_black尽可能大。解决这个问题的方法是使用两次树形动态规划。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] #### 引用[.reference_title] - *1* *2* [CodeForces - 1324F Maximum White Subtree(树形dp)](https://blog.csdn.net/qq_45458915/article/details/104831678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值