CF600E Lomsat gelral

题意翻译

一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和。

题目描述

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<=105 ) — the number of vertices in the tree.

The second line contains nn integers c_{i}ci ( 1<=c_{i}<=n1<=ci<=n ), c_{i}ci — the colour of the ii -th vertex.

Each of the next n-1n1 lines contains two integers x_{j},y_{j}xj,yj ( 1<=x_{j},y_{j}<=n1<=xj,yj<=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.

 

输入输出样例

输入样例#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

我终于会树上启发式惹..。 

树上启发式 简单来说就是先搞轻儿子 在搞重儿子 搞轻儿子的时候将他的贡献除去 保留重儿子的贡献 最后再把轻儿子的贡献加回来作为一个整体传上去

这样子才能保证时间复杂度

那么对于这个东西就可以一个桶表示每个颜色节点的数量即可 再加上跟dalao学习的时间戳优化 不用每次都去清空

边走边更新 每次更新的时候时间戳$++$ 再开一个$t$表示上一次修改这个颜色的时间 如果时间不同 那么他们就不在一颗子树当中 就进行清空即可

代码

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

typedef long long ll;
const int N = 1e5 + 5;
int idc,masiz,num[N],t[N],head[N],nex[2 * N],tov[2 * N];
int n,c[N],tot,size[N],son[N];
ll sum, ans[N];

void clear( ) {
    
    idc ++; sum = 0, masiz = 0;
}

void calc(int col) {
    
    if(t[col] != idc) {num[col] = 0, t[col] = idc;}
    num[col] ++;
    if(num[col] > masiz) {
        masiz = num[col]; sum = 1ll * col;
    }
    else if(num[col] == masiz) sum += 1ll * col;
}

void add(int u, int v) {
    
    tot ++;
    nex[tot] = head[u];
    tov[tot] = v;
    head[u] = tot;
}

void Init( ) {
    
    scanf("%d",& n);
    for(int i = 1;i <= n;i ++) scanf("%d",& c[i]);
    for(int i = 1;i < n;i ++) {
        int u, v;
        scanf("%d%d",& u, & v);
        add(u, v); add(v, u);
    }
}

void dfs1(int u, int fa) {
    
    size[u] = 1; 
    for(int i = head[u];i;i = nex[i]) {
        int v = tov[i];
        if(v == fa) continue;
        dfs1(v, u);
        size[u] += size[v];
        if(size[v] > size[son[u]]) son[u] = v;
    }
}

void dfs3(int u, int fa) {
    
    calc(c[u]); 
    for(int i = head[u];i;i = nex[i]) {
        int v = tov[i];
        if(v == fa) continue;
        dfs3(v, u);
    }
}

void dfs2(int u, int fa) {
    
    if(! son[u]) {
        ans[u] = c[u];
        calc(c[u]); return ;
     }
    for(int i = head[u];i;i = nex[i]) {
        int v = tov[i];
        if(v == fa || v == son[u]) continue;
        dfs2(v, u); clear( );
    }
    dfs2(son[u], u);
    for(int i = head[u];i;i = nex[i]) {
        int v = tov[i];
        if(v == fa || v == son[u]) continue;
        dfs3(v, u); 
    }
    calc(c[u]);
    ans[u] = sum;
}

void Solve( ) {
    
    dfs1(1, 1); dfs2(1, 1);
    for(int i = 1;i <= n;i ++) printf("%lld ",ans[i]);
}

int main( ) {
    
    Init( );
    Solve( );
}
posted @ 2018-10-07 20:28  阿澈说他也想好好学习  阅读(136)  评论(0编辑  收藏  举报