题目描述

每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在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缩点。
 #include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
using namespace std;
const int N=;
int n,tim,dcnt,next[N],nxt[N],dfn[N],low[N],belong[N],sz[N],ans[N];
bool instk[N],vis[N];
stack<int>stk;
void tarjan(int u)
{
dfn[u]=low[u]=++tim;
instk[u]=;
stk.push(u);
if(next[u])
{
if(dfn[next[u]]==)
{
tarjan(next[u]);
low[u]=min(low[u],low[next[u]]);
}
else if(instk[next[u]])
low[u]=min(low[u],dfn[next[u]]);
}
if(low[u]==dfn[u])
{
++dcnt;
while()
{
int t=stk.top();
stk.pop();
instk[t]=;
belong[t]=dcnt;
sz[dcnt]++;
if(t==u)
break;
}
}
}
void dfs(int u)
{
if(nxt[u])
{
if(!vis[nxt[u]])
{
dfs(nxt[u]);
vis[nxt[u]]=;
}
ans[u]=ans[nxt[u]]+sz[u];
}
else
{
ans[u]=sz[u];
vis[u]=;
}
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d",&next[i]);
if(next[i]==i)
next[i]=;
}
for(int i=;i<=n;i++)
if(!dfn[i])
tarjan(i);
for(int i=;i<=n;i++)
if(next[i]&&belong[i]!=belong[next[i]])
nxt[belong[i]]=belong[next[i]];
for(int i=;i<=dcnt;i++)
if(!vis[i])
{
dfs(i);
vis[i]=;
}
for(int i=;i<=n;i++)
printf("%d\n",ans[belong[i]]);
return ;
}
04-26 16:34
查看更多