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;
}