樹上啟發式合併-附有例題CF600E

9102700發表於2024-06-28

樹上啟發式合併(dsu on tree)

但這個 dsu 應該和並查集沒啥關係

總體思想就是利用重鏈剖分的性質,將小堆(輕兒子)往大堆(重兒子)合併,這樣子可以達到 log 的複雜度
以下是幾個重要函式

  1. void dfs1(int u, int father){} 得到一系列重要陣列,其中包括 son[]
  2. void dfs2(int u, int op){} 計算 u 子樹的答案
  3. add_ans(int u, int xson){} 將 u 子樹除了 xson 子樹的所有加入答案,是合併輕子樹的操作
  4. del_ans(int u){} 將 u 子樹的答案刪除,清空 cnt 陣列,用於第一遍 dfs2 後輕子樹的刪除操作
    第一次敲的時候 add_ans 函式敲成了 add 函式......
int n, m;
ll col[N];

int head[N], cnt;
struct Edge{
    int from, to, nxt;
}e[N << 1];
void add(int u, int v){
    e[++cnt].from = u;
    e[cnt].to = v;
    e[cnt].nxt = head[u];
    head[u] = cnt;
}

int deep[N], fa[N], siz[N], son[N];

void dfs1(int u, int father){
    fa[u] = father;
    deep[u] = deep[father] + 1;
    siz[u] = 1;
    for(int i = head[u]; i != 0; i = e[i].nxt){
        int v = e[i].to;
        if(v == father) continue;
        dfs1(v, u);
        siz[u] += siz[v];
        if(!son[u] || siz[son[u]] < siz[v]) son[u] = v;
    }
}

ll tmpans, ans_cnt, num[N], ans[N];
void add_ans(int u, int xson){
    num[col[u]]++;
    if(num[col[u]] == ans_cnt){
        tmpans += col[u];
    }else if(num[col[u]] > ans_cnt){
        ans_cnt = num[col[u]];
        tmpans = col[u];
    }
    for(int i = head[u]; i != 0; i = e[i].nxt){
        int v = e[i].to;
        if(v == xson || v == fa[u]) continue;
        add_ans(v, xson);
    }
}
void del_ans(int u){
    num[col[u]]--;
    for(int i = head[u]; i != 0; i = e[i].nxt){
        int v = e[i].to;
        if(v == fa[u]) continue;
        del_ans(v);
    }
}

void dfs2(int u, int op){
    for(int i = head[u]; i != 0; i = e[i].nxt){
        int v = e[i].to;
        if(v == fa[u] || v == son[u]) continue;
        dfs2(v, 0);
    }
    if(son[u] != 0){
        dfs2(son[u], 1);
    }
    add_ans(u, son[u]);
    ans[u] = tmpans;
    if(op == 0){
        tmpans = ans_cnt = 0;
        del_ans(u);
    }
}

Lomsat gelral

題面翻譯

  • 有一棵 \(n\) 個結點的以 \(1\) 號結點為根的有根樹
  • 每個結點都有一個顏色,顏色是以編號表示的, \(i\) 號結點的顏色編號為 \(c_i\)
  • 如果一種顏色在以 \(x\) 為根的子樹內出現次數最多,稱其在以 \(x\) 為根的子樹中佔主導地位。顯然,同一子樹中可能有多種顏色占主導地位。
  • 你的任務是對於每一個 \(i\in[1,n]\),求出以 \(i\) 為根的子樹中,占主導地位的顏色的編號和。
  • \(n\le 10^5,c_i\le n\)

題目描述

You are given a rooted tree with root in vertex $ 1 $ . Each vertex is coloured in some colour.

Let's call colour $ c $ dominating in the subtree of vertex $ v $ if there are no other colours that appear in the subtree of vertex $ v $ more times than colour $ c $ . So it's possible that two or more colours will be dominating in the subtree of some vertex.

The subtree of vertex $ v $ is the vertex $ v $ and all other vertices that contains vertex $ v $ in each path to the root.

For each vertex $ v $ find the sum of all dominating colours in the subtree of vertex $ v $ .

輸入格式

The first line contains integer $ n $ ( $ 1<=n<=10^{5} $ ) — the number of vertices in the tree.

The second line contains $ n $ integers $ c_{i} $ ( $ 1<=c_{i}<=n $ ), $ c_{i} $ — the colour of the $ i $ -th vertex.

Each of the next $ n-1 $ lines contains two integers $ x_{j},y_{j} $ ( $ 1<=x_{j},y_{j}<=n $ ) — the edge of the tree. The first vertex is the root of the tree.

輸出格式

Print $ n $ integers — the sums of dominating colours for each vertex.

樣例 #1

樣例輸入 #1

4
1 2 3 4
1 2
2 3
2 4

樣例輸出 #1

10 9 3 4

樣例 #2

樣例輸入 #2

15
1 2 3 1 2 3 3 1 1 3 2 2 1 2 3
1 2
1 3
1 4
1 14
1 15
2 5
2 6
2 7
3 8
3 9
3 10
4 11
4 12
4 13

樣例輸出 #2

6 5 4 3 2 3 3 1 1 3 2 2 1 2 3

相關文章