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