主要思路
这道题就是 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;
}