P2597:「ZJOI2012」灾难 – 题解

主要思路

这道题就是 DAG 求支配树裸题,过程是这样的:先做一遍拓扑排序,然后对于第\(i\)个点\(u\)而言,前\(i – 1\)个点已经完成,所以其支配树上的父亲就是入边起点的 LCA。稍稍处理一下即可。然后再在支配树上进行 DFS 求出每个子树的大小即可。

代码

// P2597.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 75534;

int head[MAX_N], current, n, m, deg[MAX_N], order[MAX_N], fa[20][MAX_N], dep[MAX_N], siz[MAX_N], root;
bool vis[MAX_N];

struct edge
{
    int to, nxt;
} edges[MAX_N << 1];

vector<int> G[MAX_N], revG[MAX_N];

void addpath(int src, int dst)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    head[src] = current++;
}

void toposort()
{
    int tot = 0;
    queue<int> q;
    for (int i = 1; i <= n; i++)
        if (deg[i] == 0)
            q.push(i);
    while (!q.empty())
    {
        int u = q.front();
        q.pop(), order[++tot] = u;
        for (int i = 0, siz = G[u].size(); i < siz; i++)
            if (--deg[G[u][i]] == 0)
                q.push(G[u][i]);
    }
}

int getLCA(int x, int y)
{
    if (dep[x] < dep[y])
        swap(x, y);
    for (int i = 19; i >= 0; i--)
        if (dep[fa[i][x]] >= dep[y])
            x = fa[i][x];
    if (x == y)
        return x;
    for (int i = 19; i >= 0; i--)
        if (fa[i][x] != fa[i][y])
            x = fa[i][x], y = fa[i][y];
    return fa[0][x];
}

void dfs(int u)
{
    siz[u] = 1;
    for (int i = head[u]; i != -1; i = edges[i].nxt)
        if (edges[i].to != fa[0][u])
            dfs(edges[i].to), siz[u] += siz[edges[i].to];
}

int main()
{
    memset(head, -1, sizeof(head)), scanf("%d", &n);
    for (int i = 1, val; i <= n; i++)
        while (scanf("%d", &val) && val != 0)
            G[val].push_back(i), deg[i]++, revG[i].push_back(val);
    toposort(), deg[0] = 1;
    for (int i = 1; i <= n; i++)
    {
        int u = order[i], lca = revG[u].empty() ? 0 : revG[u][0];
        for (int idx = 0, siz = revG[u].size(); idx < siz; idx++)
            lca = getLCA(lca, revG[u][idx]);
        fa[0][u] = lca, dep[u] = dep[lca] + 1, vis[u] = true;
        for (int i = 1; i <= 19; i++)
            fa[i][u] = fa[i - 1][fa[i - 1][u]];
        addpath(lca, u);
    }
    dfs(0);
    for (int i = 1; i <= n; i++)
        printf("%d\n", siz[i] - 1);
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *