1. 程式人生 > >dsu on tree 啟發式合併演算法

dsu on tree 啟發式合併演算法

我們先引入這樣一個問題:

有一棵樹,樹上有很多結點,每個結點有一個顏色c,我們現在想知道樹上每個結點的子樹**(subtree)**,有多少個結點出現顏色c。子樹的定義:該結點和其所有的孩子構成的樹。
在這裡插入圖片描述
如上圖:

  • 結點1子樹:3個結點出現黃色,2個結點出現紅色
  • 結點2子樹:2個結點出現黃色,1個結點出現紅色
  • 結點3子樹:1個結點出現紅色
  • 結點4子樹:1個結點出現黃色
  • 結點5子樹:1個結點出現紅色
    我們現在丟擲一個問題;
    樹上每個結點的子樹**(subtree)**,有多少個結點出現顏色黃色

暴力做法

不難想到,我們可以dfs遍歷整個樹,然後對結點再一次dfs(subtree),計算多少個點出現黃色,程式碼如下:

int cnt[maxn];
void add(int v, int p, int x){//v結點,p父節點
    cnt[ col[v] ] += x;
    for(auto u: g[v])
        if(u != p)
            add(u, v, x)
}
void dfs(int v, int p){
    add(v, p, 1);
    //現在cnt陣列記錄
    add(v, p, -1);
    for(auto u : g[v])
        if(u != p)
            dfs(u, v);
}