[CF 600E] Lomsat gelral

Description

一棵 \(n\) 个节点的树,点权 \(c_i≤ n\),根为\(1\),对于每个节点求出对应子树中出现次数最多的点权的和。

Solution

Code

#include <cstdio>

const int N = 100005;
struct Edge {
    int v, nxt;
} e[N<<1];
int head[N], tot, siz[N], son[N], num[N], a[N], vis[N], mx; long long ans[N], sum;

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}
void adde(int u, int v) {
    e[++tot].nxt = head[u], head[u] = tot, e[tot].v = v;
}
void dfs1(int u, int f) {
    siz[u] = 1;
    for (int i = head[u]; i; i = e[i].nxt) if (e[i].v != f) {
        dfs1(e[i].v, u), siz[u] += siz[e[i].v];
        if (siz[e[i].v] > siz[son[u]]) son[u] = e[i].v;
    }
}
void update(int u, int f, int k) {
    num[a[u]] += k;
    if (k > 0 && num[a[u]] >= mx) {
        if (num[a[u]] > mx) sum = 0, mx = num[a[u]];
        sum += a[u];
    }
    for (int i = head[u]; i; i = e[i].nxt)
        if (e[i].v != f && !vis[e[i].v]) update(e[i].v, u, k);
}
void dfs2(int u, int f, int k) {
    for (int i = head[u]; i; i = e[i].nxt)
        if (e[i].v != f && e[i].v != son[u]) dfs2(e[i].v, u, 1);
    if (son[u]) dfs2(son[u], u, 0), vis[son[u]] = 1;
    update(u, f, 1), ans[u] = sum, vis[son[u]] = 0;
    if (k) update(u, f, -1), mx = sum = 0;
}

int main() {
    int n = read();
    for (int i = 1; i <= n; ++i) a[i] = read();
    for (int i = 1, u, v; i < n; ++i)
        u = read(), v = read(), adde(u, v), adde(v, u);
    dfs1(1, 0), dfs2(1, 0, 0);
    for (int i = 1; i <= n; ++i) printf("%I64d ", ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fly-in-milkyway/p/10081044.html