支配(灭绝)树学习笔记 暨 P2597 [ZJOI2012]灾难 题解

支配树:满足树上任何一点的所有祖先都是他的支配点的树.

支配点:在图中指定一个起点s,若删去一个点t,s到w就没有路径,则t为w的支配点.

  • 一棵树本身就是支配树

  • 对于DAG:

    • 在原图上拓扑排序.
    • 按照拓扑序建支配树,方法是求出所有原图上有边指向该节点的点(即反图上该节点指向的点)的支配树上lca,将该节点设为lca的子结点,顺便更新深度,fa数组等信息.
    • dfs求出每个点的子树size.
    • 结果即为每个点子树(不含该点)的size.
  • 对于一般图:

    • 去问tarjan.
  • #include <iostream>
    #include <cstdio>
    #include <queue>
    using namespace std;
    const int N = 100005;
    int n, x;
    int rin[N], head[3][N * 2], cnt[3], index[N], dep[N], fa[N][21], siz[N];
    queue<int> q;
    struct edge
    {
        int to, next;
    } e[3][N * 2];
    void add(int u, int v, int type)
    {
        e[type][++cnt[type]].to = v;
        e[type][cnt[type]].next = head[type][u];
        head[type][u] = cnt[type];
    }
    void topo()
    {
        for (int i = 1; i <= n; i++)
            if (!rin[i])
                q.push(i);
        int tot = 0;
        while (!q.empty())
        {
            int x = q.front();
            q.pop();
            index[++tot] = x;
            for (int i = head[0][x]; i; i = e[0][i].next)
            {
                int v = e[0][i].to;
                rin[v]--;
                if (!rin[v])
                    q.push(v);
            }
        }
    }
    int lca(int a, int b)
    {
        if (dep[a] > dep[b])
            swap(a, b);
        for (int i = 20; i >= 0; i--)
            if (dep[fa[b][i]] >= dep[a]) 
                b = fa[b][i];
        if (a == b)
            return a;
        for (int i = 20; i >= 0; i--)
            if (fa[a][i] != fa[b][i])
                a = fa[a][i], b = fa[b][i];
        return fa[a][0];
    }
    void dfs(int k)
    {
        for (int i = head[2][k]; i; i = e[2][i].next)
        {
            int v = e[2][i].to;
            dfs(v);
            siz[k] += siz[v];
        }
        siz[k]++;
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            while (1)
            {
                cin >> x;
                if (x == 0)
                    break;
                rin[i]++;
                add(x, i, 0);
                add(i, x, 1);
            }
        }
        topo();
        for (int i = 1; i <= n; i++)
        {
            int ans = e[1][head[1][index[i]]].to;
            for (int j = head[1][index[i]]; j; j = e[1][j].next)
                ans = lca(ans, e[1][j].to);
            add(ans, index[i], 2);
            dep[index[i]] = dep[ans] + 1;
            fa[index[i]][0] = ans;
            for (int j = 1; j <= 20; j++)
                fa[index[i]][j] = fa[fa[index[i]][j - 1]][j - 1];
        }
        dfs(0);
        for (int i = 1; i <= n; i++)
            cout << siz[i] - 1<<endl;
    }
    
上一篇:noip多校模拟31


下一篇:CF1515F Phoenix and Earthquake