[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;
}

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