题目描述
每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在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
本来以为是水题,被洛谷坑了2333。
如果暴力模拟可以拿40分,之后想到记忆化搜索。
记忆化搜索对于树是非常方便的,但无法处理环,那就先tarjan缩点。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<stack> 5 using namespace std; 6 const int N=100005; 7 int n,tim,dcnt,next[N],nxt[N],dfn[N],low[N],belong[N],sz[N],ans[N]; 8 bool instk[N],vis[N]; 9 stack<int>stk; 10 void tarjan(int u) 11 { 12 dfn[u]=low[u]=++tim; 13 instk[u]=1; 14 stk.push(u); 15 if(next[u]) 16 { 17 if(dfn[next[u]]==0) 18 { 19 tarjan(next[u]); 20 low[u]=min(low[u],low[next[u]]); 21 } 22 else if(instk[next[u]]) 23 low[u]=min(low[u],dfn[next[u]]); 24 } 25 if(low[u]==dfn[u]) 26 { 27 ++dcnt; 28 while(1) 29 { 30 int t=stk.top(); 31 stk.pop(); 32 instk[t]=0; 33 belong[t]=dcnt; 34 sz[dcnt]++; 35 if(t==u) 36 break; 37 } 38 } 39 } 40 void dfs(int u) 41 { 42 if(nxt[u]) 43 { 44 if(!vis[nxt[u]]) 45 { 46 dfs(nxt[u]); 47 vis[nxt[u]]=1; 48 } 49 ans[u]=ans[nxt[u]]+sz[u]; 50 } 51 else 52 { 53 ans[u]=sz[u]; 54 vis[u]=1; 55 } 56 } 57 int main() 58 { 59 scanf("%d",&n); 60 for(int i=1;i<=n;i++) 61 { 62 scanf("%d",&next[i]); 63 if(next[i]==i) 64 next[i]=0; 65 } 66 for(int i=1;i<=n;i++) 67 if(!dfn[i]) 68 tarjan(i); 69 for(int i=1;i<=n;i++) 70 if(next[i]&&belong[i]!=belong[next[i]]) 71 nxt[belong[i]]=belong[next[i]]; 72 for(int i=1;i<=dcnt;i++) 73 if(!vis[i]) 74 { 75 dfs(i); 76 vis[i]=1; 77 } 78 for(int i=1;i<=n;i++) 79 printf("%d ",ans[belong[i]]); 80 return 0; 81 }