树上启发式合并 E. Lomsat gelral Educational Codeforces Round 2

E. Lomsat gelral
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

题意就不说了

思路:
树上启发式合并主要是用来处理子树的值的某些特征,用一个容器去维护就行,上模板

#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int maxn = 1e5+6;
int siz[maxn];
int son[maxn];
int skip[maxn];
int n;
int va[maxn];
int head[maxn];
int tot;
LL ans[maxn];
LL cnt[maxn];
struct node
{
    int u,v;
    int net;
}E[maxn*2];
void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}
void build(int u,int v)
{
    E[tot].u = u;
    E[tot].v = v;
    E[tot].net = head[u];
    head[u] =  tot++;
}
void dfs0(int u,int fa)
{
    siz[u] = 1;
    for(int i = head[u];~i;i = E[i].net){
        int v = E[i].v;
        if(v==fa){
            continue;
        }
        dfs0(v,u);
        siz[u]+=siz[v];
        if(siz[son[u]]<siz[v]){
            son[u] = v;
        }
    }
}
LL mx = 0;
LL sum = 0;
void getans(int u,int fa,int vv)
{
    cnt[va[u]]+=vv;
    if(vv>0&&cnt[va[u]]>mx){
        mx = cnt[va[u]];
        sum = va[u];
    }
    else if(vv>0&&cnt[va[u]]==mx){
        mx = cnt[va[u]];
        sum += va[u];
    }
    for(int i = head[u];~i;i = E[i].net){
        if(E[i].v==fa||skip[E[i].v]) continue;
        getans(E[i].v,u,vv);
    }
}
void dfs(int u,int fa,int op)
{
  //  cout<<u<<endl;
    for(int i = head[u];~i;i = E[i].net){
        int v = E[i].v;
        if(v==fa||v==son[u]) continue;
        dfs(v,u,0);
    }
    if(son[u]){
        dfs(son[u],u,1);
        skip[son[u]] = 1;
    }
    getans(u,fa,1);
    ans[u] = sum;
    if(son[u]){
        skip[son[u]] = 0;
    }
    if(op==0){
        getans(u,fa,-1);
        sum = mx = 0;
    }
}
int main()
{
    init();
    scanf("%d",&n);
    for(int i = 1;i<=n;i++){
        scanf("%d",&va[i]);
    }
    for(int i = 0;i<n-1;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        build(u,v);
        build(v,u);
    }
    dfs0(1,0);
    dfs(1,0,1);
    for(int i = 1;i<=n;i++){
        printf("%lld%c",ans[i],i==n?'\n':' ');
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值