洛谷 P2921 在农场万圣节

https://www.luogu.org/problemnew/show/P2921

 

开始感觉这题30行代码就可以搞定,还是太菜啦,还是乖乖地写了tarjan。

对图进行缩点,那么这个强联通分量中的点多余一个,那么这个环中的每个点的最长路径就是这个环(因为每个点只有一条连出去的有向边)。

对于不在环中的点,每个点搜索,当搜到一个环时,直接返回这个环中点的个数,搜不到环返回1.

 

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int n,m,a[100006],ans[100006],sum[100006];
bool vis[100006];
int low[100006],dfn[100006],Index;
bool in[100006];
int stack[100006],top;
int belong[100006],cnt;
void tarjan(int u)
{
    low[u]=dfn[u]=++Index;
    in[u]=1;stack[++top]=u;
    if(a[u])
    {
        int v=a[u];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(in[v]&&low[u]>dfn[v])low[u]=dfn[v];
    }
    if(low[u]==dfn[u])
    {
        int p;
        ++cnt;
        do
        {
            p=stack[top--];
            belong[p]=cnt;
            in[p]=0;
        }while(p!=u);
    }
}
int dfs(int x)
{
    if(ans[x])return ans[x];
    ans[x]=1;
    if(a[x])ans[x]+=dfs(a[x]);
    return ans[x];
}
int main()
{
    int x;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(a[i]==i)ans[i]=1;
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])tarjan(i);
    for(int i=1;i<=n;i++)sum[belong[i]]++;
    for(int i=1;i<=n;i++)
        if(sum[belong[i]]>1)ans[i]=sum[belong[i]];
    for(int i=1;i<=n;i++)
        if(!ans[i])dfs(i);
    for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
}

 

posted @ 2018-09-19 16:07  Manjusaka丶梦寒  阅读(197)  评论(0编辑  收藏  举报