[ZJOI2012]灾难
题面:Luogu
题解:DAG支配树
一般图的支配树?咕咕咕(其实是因为我太菜了,不会)
考虑你有一个DAG,如果某一个点到根节点的所有节点全都挂了,则这个节点必定也会挂掉
(类比一下生物的食物链,生产者挂了会一直传导到高级消费者)
于是我们可以建出这样一棵树,其中某个点的父亲是它所有前置节点的lca上(这个lca是新树上的)
由于这是一个DAG,所以直接上toposort,倍增lca的过程在中间处理
答案就是子树的大小(不算自己)
注意一下一开始给的图要反着建(因为我们要的是消费者\(\to\)生产者,而不是反过来)
#include<bits/stdc++.h>
using namespace std;
inline void read(int& x)
{
x = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define maxn 100005
struct Graph
{
struct Edge { int fr, to; }eg[maxn << 1];
int head[maxn], edgenum, fa[maxn][20], dep[maxn];
inline void add(int fr, int to)
{
eg[++edgenum] = { head[fr],to };
head[fr] = edgenum;
}
int lca(int x, int y)
{
if (dep[x] < dep[y]) swap(x, y);
int dis = dep[x] - dep[y];
for (int i = 0; i <= 16; ++i)
if ((1 << i) & dis) x = fa[x][i];
if (x == y) return x;
for (int i = 16; i >= 0; --i)
if (fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
}G, g;
queue<int> q;
int deg[maxn], n, dad[maxn];
void toposort()
{
#define to G.eg[i].to
memset(dad, -1, sizeof(dad));
for (int i = 1; i <= n; ++i)
if (!deg[i]) q.push(i), dad[i] = 0;
while (!q.empty())
{
int tp = q.front(); q.pop();
g.add(dad[tp], tp); G.dep[tp] = G.dep[dad[tp]] + 1;
G.fa[tp][0] = dad[tp];
for (int i = 1; i <= 16; ++i)
G.fa[tp][i] = G.fa[G.fa[tp][i - 1]][i - 1];
for (int i = G.head[tp]; i; i = G.eg[i].fr)
{
if (dad[to] == -1) dad[to] = tp;
else dad[to] = G.lca(dad[to], tp);
if (!--deg[to]) q.push(to);
}
}
#undef to
}
int siz[maxn];
void dfs(int rt)
{
siz[rt] = 1;
for (int i = g.head[rt]; i; i = g.eg[i].fr)
dfs(g.eg[i].to), siz[rt] += siz[g.eg[i].to];
}
int main()
{
read(n);
for (int i = 1, tp; i <= n; ++i)
while (read(tp), tp) G.add(tp, i), ++deg[i];
toposort();
dfs(0);
for (int i = 1; i <= n; ++i) printf("%d\n", siz[i] - 1);
return 0;
}
一切伟大的行动和思想,都有一个微不足道的开始。
There is a negligible beginning in all great action and thought.
There is a negligible beginning in all great action and thought.