支配樹 | 模板

題目

【模板】支配樹

實現思路

  • DFS 一次得到 DfnTid 數組;
  • Dfn 大的點開始枚舉點 uu
    • 枚舉 uu 的反向鄰接點 vv,則 vv 所在的並查集的最小 SDom 可以更新 uu(因爲 uu 的 DFS 樹上的父親還沒更新進帶權並查集,所以這時候所有的 vv 都可以在符合定理的條件下更新 uu),注意不要管不在 DFS 樹上的點;
    • SDom 樹上將 SDom[u]uu 連邊;
    • uu 更新進帶權並查集(將自己在並查集上連向自己 DFS 樹上的父親);
    • 此時 uu 所在的子樹的 SDom 已經處理好了,於是找到 uu 的 DFS 樹的父親 rr,枚舉 rrSDom 樹的兒子 vv,用求 IDom 的定理得到 vvIDom 對應的點(不能直接賦成那個點的 IDom,因爲那個點可能還沒更新)。
  • Dfn 小的點開始枚舉點 uu,並把 IDom[u] 由點變爲值,即 IDom[u] = IDom[IDom[u]]

代碼

#include <bits/stdc++.h>

const int MAXN = 200000;
const int MAXM = 300000;

int N, M;
std::vector<int> G[MAXN + 5], H[MAXN + 5];
std::vector<int> STree[MAXN + 5], ITree[MAXN + 5];

int DfnCnt;
int Fat[MAXN + 5];
int Dfn[MAXN + 5], Tid[MAXN + 5];
int SDom[MAXN + 5],IDom[MAXN + 5];

struct Union_Find {
    int Fat[MAXN + 5], Min[MAXN + 5];

    void Init(int n) {
        for (int i = 1; i <= n; i++)
            Fat[i] = Min[i] = i;
    }

    int Find(int u) {
        if (Fat[u] == u)
            return u;
        int anc = Find(Fat[u]);
        if (Dfn[SDom[Min[u]]] > Dfn[SDom[Min[Fat[u]]]])
            Min[u] = Min[Fat[u]];
        return Fat[u] = anc;
    }
}T;

void Dfs(int u) {
    Tid[Dfn[u] = ++DfnCnt] = u;
    for (int i = 0; i < int(G[u].size()); i++) {
        int v = G[u][i];
        if (!Dfn[v])
            Fat[v] = u, Dfs(v);
    }
}

void Lengauer_Tarjan() {
    for (int i = DfnCnt; i >= 2; i--) {
        int u = Tid[i];
        for (int j = 0; j < int(H[u].size()); j++) {
            int v = H[u][j];
            if (Dfn[v]) {
                T.Find(v);
                if (Dfn[SDom[u]] > Dfn[SDom[T.Min[v]]])
                    SDom[u] = SDom[T.Min[v]];
            }
        }
        STree[SDom[u]].push_back(u);
        T.Fat[u] = Fat[u];
        int r = Fat[u];
        for (int j = 0; j < int(STree[r].size()); j++) {
            int v = STree[r][j];
            T.Find(v);
            if (SDom[T.Min[v]] == r)
                IDom[v] = r;
            else
                IDom[v] = T.Min[v];
        }
    for (int i = 2; i <= DfnCnt; i++) {
        int u = Tid[i];
        if (IDom[u] != SDom[u])
            IDom[u] = IDom[IDom[u]];
    }
}

int Size[MAXN + 5];

void Count(int u) {
    Size[u] = 1;
    for (int i = 0; i < int(ITree[u].size()); i++) {
        int v = ITree[u][i];
        Count(v);
        Size[u] += Size[v];
    }
}

int main() {
    scanf("%d%d", &N, &M);
    for (int i = 1; i <= M; i++) {
        int u, v; scanf("%d%d", &u, &v);
        G[u].push_back(v);
        H[v].push_back(u);
    }
    for (int i = 1; i <= N; i++)
        SDom[i] = i;
    T.Init(N);
    Dfs(1);
    Lengauer_Tarjan();
    for (int i = 2; i <= N; i++)
        if (IDom[i])
            ITree[IDom[i]].push_back(i);
    Count(1);
    for (int i = 1; i <= N; i++)
        printf("%d ", Size[i]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章