123789456ye

已AFO

[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;
}
posted @ 2020-04-12 20:18  123789456ye  阅读(97)  评论(0编辑  收藏  举报