Luogu 2597 [ZJOI2012 灾难]

传送门

题目大意

一个食物网有$N$个点,代表$N$种生物,如果生物$x$可以吃生物$y$,那么从$y$向$x$连一个有向边。这个图没有环。

图中有一些点没有连出边,这些点代表的生物都是生产者,可以通过光合作用来生存; 而有连出边的点代表的都是消费者,它们必须通过吃其他生物来生存。

如果某个消费者的所有食物都灭绝了,它会跟着灭绝。

我们定义一个生物在食物网中的“灾难值”为,如果它突然灭绝,那么会跟着一起灭绝的生物的种数。

举个例子:在一个草场上,生物之间的关系是:

img

  • 如果羊都死了,那么狼会因为没有食物而灭绝,而小强可以通过吃牛、牛可以通过吃草来生存下去。所以,羊的灾难值是$1$。

  • 但是,如果草突然灭绝,那么整个草原上的$5$种生物都无法幸免,所以,草的灾难值是$4$。

给定一个食物网,你要求出每个生物的灾难值。


解析

把所有的边反向,按时拓扑序处理某个点,这样就可以保证处理一个点的时候,这个点能吃的点都会被吃掉。
现在我们假设处理一个点之前,其他的点统统都是一棵树的形态。

那么这个点吃的所有,等价于吃吃的所有的lca。

这个随便维护。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#define  REP(i, s, e) for (int i = s; i <= e; i++)
#define DREP(i, s, e) for (int i = s; i >= e; i--)
#define DEBUG fprintf(stderr, "Passing [%s] in Line %d\n", __FUNCTION__, __LINE__)

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 70000 + 10, maxm = maxn;

int bg[maxn], ne[maxn], to[maxn], e;
void add(int x, int y)
{
e++;
to[e] = y;
ne[e] = bg[x];
bg[x] = e;
}

int n, k, depth[maxn], grand[maxn][20], LOG;
int tcnt;
vector <int> G[maxn], eat[maxn];
int in[maxn], q[maxn], head, tail;

int lca(int x, int y)
{
if (depth[x] < depth[y]) swap(x, y);
DREP(i, LOG, 0)
if (depth[grand[x][i]] >= depth[y]) x = grand[x][i];
if (x == y) return x;
DREP(i, LOG, 0)
if (grand[x][i] ^ grand[y][i]) x = grand[x][i], y = grand[y][i];
return grand[x][0];
}
int ans[maxn];
void dfs(int x)
{
ans[x] = 1;
for (int i = bg[x]; i ;i = ne[i])
{
dfs(to[i]);
ans[x] += ans[to[i]];
}
}

int main()
{
#ifndef ONLINE_JUDGE
freopen("2597.in", "r", stdin);
freopen("2597.out", "w", stdout);
#endif
cin >> n;LOG = log2(n);
REP(i, 1, n) while (scanf("%d", &k), k) G[k].push_back(i), in[i]++, eat[i].push_back(k);
REP(i, 1, n)
if (!in[i]) depth[q[++tail] = i] = 1;
while (head <= tail)
{
int x = q[head++];
int siz = (int)G[x].size()-1;
REP(i, 0, siz)
if (!(--in[G[x][i]])) q[++tail] = G[x][i];
if (!eat[x].empty())
{
siz = (int)eat[x].size() - 1;
int l = eat[x][0];
REP(i, 1, siz) l = lca(l, eat[x][i]);
grand[x][0] = l;
depth[x] = depth[l] + 1;
REP(j, 1, LOG) grand[x][j] = grand[grand[x][j-1]][j-1];
add(l, x);
}
}
REP(i, 1, n) if(!ans[i])dfs(i);
REP(i, 1, n) printf("%d\n", ans[i] - 1);
return 0;
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×