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();
    }
}

猜你喜欢

转载自www.cnblogs.com/nenT/p/11761258.html