[zjoi2012]灾难——拓扑排序+灭绝树

题目大意:

草原中有一张食物网,如果将一种动物弄死,将会有一些动物没有食物而死亡,那么称死亡动物的种类数为这种动物的灾难值。
求每一种动物的灾难值。
\(n\leq 65534\),输入数据\(\leq\) 10M。

思路:

题目可以转化为将DAG删除一个结点后有多少个结点变得不可达
不难发现,整张食物网其实是构成了一个树形结构,即直接导致某种动物死亡的动物有且只有一种。某一个结点的死亡必定会导致它的子树内的所有的动物都死亡。
于是我们尝试将这颗“灭绝树”给建出来,一种动物v要死亡,那么直接连向它的所有结点\(u_1,u_2,u_3\dots\)都必须要死亡。那么我们只要找到第一个可以使{u}全部死亡的结点,它就是v的父亲。
{u}必须在v之前处理出来,并且加入灭绝树中,于是直接按照拓扑序建树。之后的找父亲就是一个求lca的过程,只需要每次更新新结点的st表即可。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define debug(x) cout<<#x<<"="<<x<<endl
typedef long long ll;

using namespace std;

void File(){
	freopen("bzoj2815.in","r",stdin);
	freopen("bzoj2815.out","w",stdout);
}

template<typename T>void read(T &_){
	T __=0,mul=1; char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')mul=-1;
		ch=getchar();
	}
	while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
	_=__*mul;
}

const int maxn=65534+10;
const int maxm=2e6+10;
int n,rt,deg[maxn],st[maxn][21],dep[maxn],Log[maxn],sz[maxn];
int beg[maxn],to[maxm<<1],las[maxm<<1],cnte=1;
vector<int>T[maxn],from[maxn]; 

void add(int u,int v){
	las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v;
}

void init(){
	read(n);
	rt=n+1;
	Log[1]=0;
	REP(i,2,n)Log[i]=Log[i/2]+1;
	int v;
	REP(i,1,n){
		read(v);
		while(v)add(v,i),++deg[i],read(v);
	}
	REP(i,1,n)if(!deg[i])add(rt,i),++deg[i];
}

void update(int u){
	REP(i,1,18){
		int f=st[u][i-1];
		if(!f || !st[f][i-1])break;
		st[u][i]=st[f][i-1];
	}
}

int query(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	while(dep[x]!=dep[y]){
		int d=Log[dep[x]-dep[y]];
		x=st[x][d];
	}
	if(x==y)return x;
	for(int d=18;d>=0;--d)
		if(st[x][d] && st[y][d] && st[x][d]!=st[y][d])
			x=st[x][d],y=st[y][d];
	return st[x][0];
}

void Topsort(){
	queue<int>qu;
	qu.push(rt);
	while(!qu.empty()){
		int u=qu.front(); qu.pop();
		if(u!=rt){
			int t=from[u][0];
			REP(i,1,from[u].size()-1)
				t=query(t,from[u][i]);
			st[u][0]=t; update(u);
			dep[u]=dep[st[u][0]]+1;
		}
		for(int i=beg[u];i;i=las[i]){
			int v=to[i];
			--deg[v]; from[v].push_back(u);
			if(!deg[v])qu.push(v);
		}
	}
}

void dfs(int u){
	++sz[u];
	REP(i,0,T[u].size()-1){
		dfs(T[u][i]);
		sz[u]+=sz[T[u][i]];
	}
}

int main(){
	File();
	init();
	Topsort();
	REP(i,1,n)T[st[i][0]].push_back(i);
	dfs(rt);
	REP(i,1,n)printf("%d\n",sz[i]-1);
	return 0;
}

posted @ 2018-10-27 14:42  ylsoi  阅读(166)  评论(0编辑  收藏  举报