题目链接

题目大意

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

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

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

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

题解

此题也可以用tarjan缩点
由题意可得每个牛到了一个牛棚后下一个只能去后继牛棚

那么我们可以用tarjan先预处理出来,然后再用记忆化搜索统计答案

一定要用记忆化搜索,否则会超时6个点

代码

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include &lt; cstdio &gt;
#include &lt; cstring &gt;
#include &lt; queue &gt;
#include &lt; algorithm &gt;
using namespace std;
const int maxn=200005;
int n,x,k=0,head[maxn],dfn[maxn],low[maxn],color_num=0,dfs_num=0;
bool visit[maxn];int ans[maxn];
int stack[maxn],top=0,val[maxn],head_new[maxn],color[maxn];
struct node
{
int to,next;
} edge[maxn<<1],edge_new[maxn<<1];
void add(int u,int v)
{
edge[++k].to=v;
edge[k].next=head[u];
head[u]=k;
}
void tarjan(int x)
{
dfn[x]=low[x]=++dfs_num;
visit[x]=true;stack[++top]=x;
for(int i=head[x];i;i=edge[i].next)
{
if(!dfn[edge[i].to])
{
tarjan(edge[i].to);
low[x]=min(low[x],low[edge[i].to]);
}
else if(visit[edge[i].to]) low[x]=min(low[x],dfn[edge[i].to]);
}
if(low[x]==dfn[x])
{
visit[x]=false;color_num++;
while(stack[top+1]!=x)
{
val[color_num]++;
visit[stack[top]]=false;
color[stack[top]]=color_num;
top--;
}
}
}

void add_new(int u,int v)
{
edge_new[++k].to=v;
edge_new[k].next=head_new[u];
head_new[u]=k;
}
void dfs(int x)
{
if(ans[x]) return;
ans[x]+=val[x];
for(int i=head_new[x];i;i=edge_new[i].next)
{
dfs(edge_new[i].to);
ans[x]+=ans[edge_new[i].to];
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
add(i,x);
}
k=0;
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++)
{
for(int j=head[i];j;j=edge[j].next)
{
if(color[i]!=color[edge[j].to])
{
add_new(color[i],color[edge[j].to]);
}
}
}
for(int i=1;i<=n;i++) dfs(color[i]);
for(int i=1;i<=n;i++) printf("%d\n",ans[color[i]]);
return 0;
}