https://www.luogu.com.cn/problem/P2921
题目描述
每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在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只奶牛要前往的隔间数。
输入输出样例
输入 #1
输出 #1
样例解释
有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个隔间。
翻译提供者:吃葡萄吐糖
先用 tarjan 找出所有的强连通分量 ( 包括强连通分量的大小 ),然后再跑一边 dfs
搜索的时候,如果 u, v 不在一个圈内,则 ans [ u ] = 1 + ans[ v ],需 dfs( v ) 先求出 ans[ v ] ; 否则两者相等,直接返回结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| const int MAX=100000+10; int n,next[MAX],ans[MAX]; int Low[MAX],DFN[MAX],Stack[MAX],Belong[MAX]; int ind,top; int scc; bool InStack[MAX]; int num[MAX]; void tarjan(int u,int fa){ Low[u]=DFN[u]=++ind; Stack[top++]=u; InStack[u]=true; int v=next[u]; if(!DFN[v]){ tarjan(v,u); Low[u]=min(Low[u],Low[v]); }else if(InStack[v]){ Low[u]=min(Low[u],DFN[v]); } if(Low[u]==DFN[u]){ scc++; do{ v=Stack[--top]; InStack[v]=false; Belong[v]=scc; num[scc]++; }while(v!=u); } } void dfs(int u){ if(ans[u]) return; int v=next[u]; if(Belong[v]!=Belong[u]){ dfs(v); ans[u] = 1 + ans[v]; }else { ans[u] = num[Belong[u]]; dfs(v) ; } } void solve(int n){ memset(DFN,0,sizeof(DFN)); memset(InStack,false,sizeof(InStack)); memset(num,0,sizeof(num)); ind=scc=top=0; for(int i=1;i<=n;i++) if(!DFN[i]) tarjan(i,-1); } int main(){ freopen("in","r",stdin); sf(n); fi(i,1,n+1){ sf(next[i]); } solve(n); fi(i,1,n+1) if(!ans[i]) dfs(i); fi(i,1,n+1){ pf(ans[i]); pfc("\n"); } return 0; }
|