[ZJOI 2012] 災難(支配樹) | 錯題本

題目

[ZJOI 2012] 災難

分析

將圖中所有邊取反,發現要求的就是每個點支配的點數。然而發現一個問題:這個不是一個單源點的有向圖。我們只需建一個源點,將其向所有入度爲零的點連邊,建出支配樹即可。


當然,這個圖是 DAG,事實上拓撲排序就 + LCA 能找到支配點。但我還是用的 LT

錯因

  • 沒想到怎麼處理多源點的 DAG 的問題;
  • 板子打錯了兩個地方。

代碼

#include <bits/stdc++.h>

const int MAXN = 65534;

int N;
int In[MAXN + 5];
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[Fat[u]]]] < Dfn[SDom[Min[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[T.Min[v]]] < Dfn[SDom[u]])
                    SDom[u] = SDom[T.Min[v]];
            }
        }
        STree[SDom[u]].push_back(u);
        int r = T.Fat[u] = 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];
        }
        STree[r].clear();
    }
    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", &N);
    for (int i = 1; i <= N; i++) {
        while (1) {
            int v; scanf("%d", &v);
            if (!v) break;
            In[i]++;
            G[v].push_back(i);
            H[i].push_back(v);
        }
    }
    for (int i = 1; i <= N; i++)
        if (!In[i]) {
            G[N + 1].push_back(i);
            H[i].push_back(N + 1);
        }
    Dfs(N + 1);
    for (int i = 1; i <= N + 1; i++)
        SDom[i] = i;
    T.Init(N + 1);
    Lengauer_Tarjan();
    for (int i = 1; i <= N + 1; i++)
        if (IDom[i])
            ITree[IDom[i]].push_back(i);
    Count(N + 1);
    for (int i = 1; i <= N; i++)
        printf("%d\n", Size[i] - 1);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章