P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm

题目描述

每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在N(1<=N<=100,000)个牛棚隔间中留下的糖果,以此来庆祝美国秋天的万圣节。

由于牛棚不太大,FJ通过指定奶牛必须遵循的穿越路线来确保奶牛的乐趣。为了实现这个让奶牛在牛棚里来回穿梭的方案,FJ在第i号隔间上张贴了一个“下一个隔间”Next_i(1<=Next_i<=N),告诉奶牛要去的下一个隔间;这样,为了收集它们的糖果,奶牛就会在牛棚里来回穿梭了。

FJ命令奶牛i应该从i号隔间开始收集糖果。如果一只奶牛回到某一个她已经去过的隔间,她就会停止收集糖果。

在被迫停止收集糖果之前,计算一下每头奶牛要前往的隔间数(包含起点)。

输入格式

第1行 整数n。

第2行到n+1行 每行包含一个整数 next_i 。

输出格式

n行,第i行包含一个整数,表示第i只奶牛要前往的隔间数。

样例解释

有4个隔间

隔间1要求牛到隔间1

隔间2要求牛到隔间3

隔间3要求牛到隔间2

隔间4要求牛到隔间3

牛1,从1号隔间出发,总共访问1个隔间;

牛2,从2号隔间出发,然后到三号隔间,然后到2号隔间,终止,总共访问2个隔间;

牛3,从3号隔间出发,然后到2号隔间,然后到3号隔间,终止,总共访问2个隔间;

牛4,从4号隔间出发,然后到3号隔间,然后到2号隔间,然后到3号隔间,终止,总共访问3个隔间。

输入输出样例

输入样例#1
4 
1 
3 
2 
3 
输出样例#1
1 
2 
2 
3 
题解
强连通+搜索,

 

#include<cstdio>
#include <algorithm>
#include <stack>
#include <cstring>
using namespace std;

const int MAXN=1e5+10;
const int inf=0x3f3f3f3f;
struct node{
    int to;
    int next;
}edge[MAXN*4];
int head[MAXN];
bool instack[MAXN];
int cnt;
int dfn[MAXN],low[MAXN];
void add(int x,int y)
{
    edge[++cnt].to =y;
    edge[cnt].next=head[x];
    head[x]=cnt;
}
int Time,num;
stack<int >st;
int color[MAXN];
int x[MAXN];
int ans[MAXN],sum[MAXN];
void tarjan(int u)
{
    dfn[u]=low[u]= ++Time;
    st.push(u);
    instack[u]=true;
    for (int i = head[u]; i !=-1 ; i=edge[i].next) {
        int v=edge[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(instack[v]) low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
    {
        int x;
        num++;
        while(1) {
            x=st.top();
            st.pop();
            color[x]=num;
            instack[x]=false;
            if(x==u) break;
        }

    }
}
int search(int root,int to,int setp  )
{
    if(ans[to]!=0) {ans[root]=ans[to]+setp;}
    else search(root,x[to],setp+1);
}
int main()
{
    int n;
    scanf("%d",&n);
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(instack,false, sizeof(instack));
    memset(sum, 0,sizeof(sum));
    for (int i = 1; i <=n; ++i) {
        scanf("%d",&x[i]);
        add(i,x[i]);
        if(i==x[i])
            ans[i]=1;
    }
    for (int i = 1; i <=n ; ++i) {
        if(!dfn[i]) tarjan(i);
    }
    for (int i = 1; i <=n ; ++i) {
        sum[color[i]]++;
    }
    for (int i = 1; i <=n ; ++i) {
        if(sum[color[i]]>1) ans[i]=sum[color[i]];
    }
    for (int i = 1; i <=n ; ++i) {
        if(ans[i]==0) search(i,x[i],1);
    }
    for (int i = 1; i <=n ; ++i) {
        printf("%d\n",ans[i]);
    }
    return 0;
}

  

posted @ 2018-07-20 08:30  岩扉  阅读(262)  评论(0编辑  收藏  举报