【ZJOI2012】灾难(拓扑+重新建树+lca)

版权声明:虽然我很菜,不过转载请标明出处。 https://blog.csdn.net/Patrickpwq/article/details/86622040

(我怎么又双叒叕发烧了...)

不难想到 对于一个生产者 它死了 所有它的子树就都死了

换句话说 对于一个消费者 它死 当且仅当它的所有食物都死了 什么时候所有食物都死了呢?——最顶端的生产者死了。否则,那消费者一定能至少找到一种食物

假如我们能够建出这样的一颗树就是极好的 不妨先来考虑建树的过程 对于新加入的点now 首先我们确定now是否为生产者 否则 将now放在食物们lca的儿子的地方即可

那肯定不能直接1~n枚举 这样找出来的LCA是错的 由于没有环 考虑拓扑先确定层次

#include<bits/stdc++.h>
const int N=65535;
using namespace std;
int n;
int first[N],tot;
struct Edge
{
	int to,next;
}edge[2*N];
inline void addedge(int x,int y)
{
	tot++;
	edge[tot].to=y; edge[tot].next=first[x]; first[x]=tot;
}
int in[N],topo[N],num;
void Topo_sort()
{
	queue <int> q;
	for(int i=1;i<=n;i++)	if(!in[i])	q.push(i);
	while(!q.empty())
	{
		int now=q.front();
		q.pop();
		topo[++num]=now;
		for(int u=first[now];u;u=edge[u].next)
		{
			int vis=edge[u].to;
			in[vis]--;
			if(!in[vis]) q.push(vis);
		}
	}
}
vector <int> e[N];
int father[N],depth[N],up[N][20];
inline int getlca(int x,int y)
{
	if(depth[x]<depth[y])	swap(x,y);
	for(int i=19;i>=0;i--) if(depth[up[x][i]]>=depth[y]) x=up[x][i];
	if(x==y)	return x;
	for(int i=19;i>=0;i--) if(up[x][i]!=up[y][i]) x=up[x][i],y=up[y][i];
	return up[x][0];
}
inline void update(int now)
{
	for(int i=1;i<=19;i++)	up[now][i]=up[up[now][i-1]][i-1];
}
void build()
{
	depth[n+1]=1;
	for(int i=num;i>=1;i--)
	{
		int now=topo[i];
		if(first[now]==0)	//生产者 
		{
			e[now].push_back(n+1); e[n+1].push_back(now);
			up[now][0]=n+1;
			depth[now]=2;
			continue;		
		}
		int lca=edge[first[now]].to;
		for(int u=edge[first[now]].next;u;u=edge[u].next)
		{
			int vis=edge[u].to;
			lca=getlca(lca,vis);
		}
		up[now][0]=lca;
		e[now].push_back(lca); e[lca].push_back(now);
		depth[now]=depth[lca]+1;
		update(now);
	}
}
int sum[N];
void dfs(int now,int fa)
{
	sum[now]=1;
	for(int i=0;i<e[now].size();i++)
	{
		int vis=e[now][i];
		if(vis==fa)	continue;
		dfs(vis,now);
		sum[now]+=sum[vis];
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cin>>n;
	for(int i=1,x;i<=n;i++)
	{
		cin>>x;
		while(x)
		{
			addedge(i,x);	//每个点连向它的食物 方便build 
			in[x]++;
			cin>>x;
		}
	}
	Topo_sort();
	build();
	dfs(n+1,0);
	for(int i=1;i<=n;i++)	cout<<sum[i]-1<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Patrickpwq/article/details/86622040