洛谷 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: 复制
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 }
原文地址:https://www.cnblogs.com/fantasquex/p/9342708.html