题目链接
题目大意
每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在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 < cstdio > #include < cstring > #include < queue > #include < algorithm > 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; }
|