CF600E Lomsat gelral(dsu on tree)

Lomsat gelral

题目描述

一个NN个节点的有根树(点11为根),节点从11到NN编号,每个节点有一个颜色C_iCi

对于一个以xx为根的子树,我们认为颜色cc在这个子树中出现的次数是最多的,则认为cc支配了这个子树。

如果有多个颜色的次数相同并且都为最大,则他们都支配了这个子树。

对每个节点xx,输出所有支配他的子树的颜色的编号之和。

输入格式

第一行一个整数n,

接下来一行n个整数Ci,

接下来n-1行,每行两个整数x,y,表示x和y有一条边。

输出格式

输出一行n个数,第i个数为节点i的答案。


dsu on tree的入门题

十分套路的模板

(代码格式化真吼看)

#include <cstdio>
#include <vector>
using namespace std;
void read(int &x) {
    char c = getchar();
    x = 0;
    while (c < '0' || c > '9') c = getchar();
    while ('0' <= c && c <= '9') x = x * 10 + c - 48, c = getchar();
}
#define N 1000005
int n, siz[N], big[N], cr[N], c[N], mx;
long long ans[N], sum;
bool vis[N];
vector<int> g[N];
void dfs1(int x, int fa) {
    siz[x] = 1;
    for (auto i : g[x])
        if (i != fa) {
            dfs1(i, x);
            siz[x] += siz[i];
            if (siz[i] > siz[big[x]])
                big[x] = i;
        }
}
void draw(int x, int fa, int k) {
    c[cr[x]] += k;
    if (k > 0 && c[cr[x]] >= mx) {
        if (c[cr[x]] > mx)
            sum = 0;
        mx = c[cr[x]];
        sum += cr[x];
    }
    for (auto i : g[x])
        if (i != fa && !vis[i])
            draw(i, x, k);
}
void dfs2(int x, int fa, bool is) {
    for (auto i : g[x])
        if (i != fa && i != big[x])
            dfs2(i, x, 0);
    if (big[x])
        dfs2(big[x], x, 1), vis[big[x]] = 1;
    draw(x, fa, 1);
    ans[x] = sum;
    if (big[x])
        vis[big[x]] = 0;
    if (!is)
        draw(x, fa, -1), sum = mx = 0;
}
int main() {
    read(n);
    for (int i = 1; i <= n; ++i) read(cr[i]);
    for (int i = 1, p, q; i < n; ++i) {
        read(p);
        read(q);
        g[p].push_back(q);
        g[q].push_back(p);
    }
    dfs1(1, 0);
    dfs2(1, 0, 1);
    for (int i = 1; i <= n; ++i) printf("%lld ", ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/kafuuchino/p/10946109.html