题意:
给出 \(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();
}
}