题解:根据定义,若不存在生产者到x的路径,那么x就会灭绝,一个物种的灾难值:将这个点抠掉,有多少个点无法从生产者到达。对输入反向建图,构建支配树,物种的灾难值就是该点在支配树上的子节点个数(不包括自己)。
由于图是DAG,可以按拓扑序构建支配树:按拓扑序遍历所有点,对于当前处理的点x,[1,x - 1]已经构成了支配树,求出所有能到达它的点在支配树上的lca,lca 就是 x的支配点。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
const int mx = 17;
int n;
vector<int> g[maxn],rg[maxn],h[maxn],tmp;
int ru[maxn],f[maxn][mx + 1],dep[maxn],son[maxn];
void init() {
memset(ru,0,sizeof ru);
memset(f,0,sizeof f);
memset(dep,0,sizeof dep);
}
void tpsort() {
queue<int> q;
for(int i = 1; i <= n; i++)
if(!ru[i]) q.push(i);
while(!q.empty()) {
int top = q.front();
q.pop();
tmp.push_back(top);
for(int i = 0; i < g[top].size(); i++) {
int v = g[top][i];
ru[v]--;
if(!ru[v]) q.push(v);
}
}
}
int lca(int u,int v) {
if(dep[u] < dep[v]) swap(u,v);
for(int i = mx; i >= 0; i--)
if(dep[f[u][i]] >= dep[v]) u = f[u][i];
if(u == v) return u;
for(int i = mx; i >= 0; i--)
if(f[u][i] != f[v][i]) {
u = f[u][i];
v = f[v][i];
}
return f[u][0];
}
void dfs(int u,int fa) {
son[u] = 1;
for(auto it : h[u]) {
if(it == fa) continue;
dfs(it,u);
son[u] += son[it];
}
}
int main() {
init();
scanf("%d",&n);
int x;
for(int i = 1; i <= n; i++) {
while(scanf("%d",&x) && x) {
g[x].push_back(i);
ru[i]++;
rg[i].push_back(x);
}
}
tpsort();
for(auto it : tmp) {
if(rg[it].size() == 0) {
h[0].push_back(it);
dep[it] = 1;
continue;
}
int p = rg[it][0];
for(int j = 1; j < rg[it].size(); j++)
p = lca(p,rg[it][j]);
h[p].push_back(it);
f[it][0] = p;dep[it] = dep[p] + 1;
for(int i = 1; i <= mx; i++) f[it][i] = f[f[it][i - 1]][i - 1];
}
dfs(0,0);
for(int i = 1; i <= n; i++) {
printf("%d\n",son[i] - 1);
}
return 0;
}