树上启发式合并
作者:互联网
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 100010;
int n, c[N], head[N], ver[N << 1], nex[N << 1], tot, cnt[N], num[N], siz[N], son[N], L[N], R[N], dfn, pos[N], maxn;
long long sum[N], ans[N];
inline void add (int x, int y) {
ver[++ tot] = y;
nex[tot] = head[x];
head[x] = tot;
}
void dfs1 (int x, int fa) {
L[x] = ++ dfn;
pos[dfn] = x;
siz[x] = 1;
for (int i = head[x]; i; i = nex[i]) {
int y = ver[i];
if (y == fa) continue;
dfs1(y, x);
siz[x] += siz[y];
if (!son[x] || siz[y] > siz[son[x]]) son[x] = y;
}
R[x] = dfn;
}
inline void addans (int x) {
sum[cnt[c[x]]] -= c[x];
num[cnt[c[x]]] --;
cnt[c[x]] ++;
num[cnt[c[x]]] ++;
maxn = max(maxn, cnt[c[x]]);
sum[cnt[c[x]]] += c[x];
}
inline void delans (int x) {
sum[cnt[c[x]]] -= c[x];
num[cnt[c[x]]] --;
if (!num[cnt[c[x]]] && maxn == cnt[c[x]]) maxn --;
cnt[c[x]] --;
num[cnt[c[x]]] ++;
sum[cnt[c[x]]] += c[x];
}
void dfs2 (int x, int fa, int flag) {
for (int i = head[x]; i; i = nex[i]) {
int y = ver[i];
if (y == fa || y == son[x]) continue;
dfs2(y, x, 0);
}
if (son[x]) dfs2(son[x], x, 1);
for (int i = head[x]; i; i = nex[i]) {
int y = ver[i];
if (y == fa || y == son[x]) continue;
for (int j = L[y]; j <= R[y]; j ++)
addans(pos[j]);
}
addans(x);
ans[x] = sum[maxn];
if (flag) return;
for (int i = L[x]; i <= R[x]; i ++)
delans(pos[i]);
}
int main () {
scanf("%d", &n);
for (int i = 1; i <= n; i ++) scanf("%d", &c[i]);
for (int i = 1; i < n; i ++) {
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
dfs1(1, 0);
dfs2(1, 0, 1);
for (int i = 1; i <= n; i ++) printf("%lld ", ans[i]);
return 0;
}
标签:cnt,int,sum,合并,son,num,maxn,启发式,树上 来源: https://www.cnblogs.com/duoluoluo/p/16505131.html