其他分享
首页 > 其他分享> > 树上启发式合并

树上启发式合并

作者:互联网

模板

#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