luogu#P2921 USACO08DEC在农场万圣节

题意:

给出 \(N\) 个点,每个点指向一个其它点的,求从每个点开始,第二次访问一个节点时走的步数

解析:

Tarjan

#include<cstdio>
#include<stack>
#define N 100005
using namespace std;
struct Edge{int next,to;}edge[N];
int n,n_e,head[N],f[N];
int dfn[N],low[N],tot,clr[N],col,p[N],out[N];
stack<int> s;
bool vis[N];

int dfs(int x);
void tarjan(int u);
inline void addedge(int from,int to);
void init();
int main()
{
	init();
	
	for(int i=1;i<=n;i++)
		if(!dfn[i])
			tarjan(i);

	for(int i=1;i<=n;i++)
		if(clr[i]!=clr[edge[i].to])
			out[clr[i]]=clr[edge[i].to];
	for(int i=1;i<=n;i++)
		printf("%d\n",dfs(clr[i]));
	return 0;
}
int dfs(int x)
{
	if(!x)
		return 0;
	if(f[x])
		return f[x];
	return f[x]=dfs(out[x])+p[x];
}
void init()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int v;
		scanf("%d",&v);
		addedge(i,v);
	}
}
inline void addedge(int from,int to)
{
	edge[++n_e].next=head[from];
	edge[n_e].to=to;
	head[from]=n_e;
}
void tarjan(int u)
{
	tot++; dfn[u]=tot; low[u]=tot;
	s.push(u); vis[u]=1;
	for(int i=head[u];i;i=edge[i].next)	
	{
		int v=edge[i].to;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[v],low[u]);
		}
		else if(vis[v])
			low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
	{
		col++; clr[u]=col; p[col]++; vis[u]=0;
		while(s.top()!=u)
		{
			p[col]++;
			vis[s.top()]=0;
			clr[s.top()]=col;
			s.pop();
		}
		s.pop();
	}
}
posted @ 2019-10-29 20:17  nenT  阅读(110)  评论(0)    收藏  举报