縮點【洛谷P2921】 [USACO08DEC]在農場萬聖節Trick or Treat on the Farm
阿新 • • 發佈:2018-10-31
【洛谷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號隔間開始收集糖果。如果一隻奶牛回到某一個她已經去過的隔間,她就會停止收集糖果。
在被迫停止收集糖果之前,計算一下每頭奶牛要前往的隔間數(包含起點)。
有向圖縮點,之後對於入度為零的點進行記憶化搜尋。
很明顯不記憶化搜尋的話一定很慘,我居然還交了一遍。。。
code:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int wx=200017; inline int read(){ int sum=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();} return sum*f; } int st[wx],vis[wx],f[wx]; int num,Num,n,top,tot,col; int head[wx],h[wx],in[wx]; int dfn[wx],low[wx],belong[wx],size[wx]; struct e{ int nxt,to; }edge[wx*2]; void add(int from,int to){ edge[++num].nxt=head[from]; edge[num].to=to; head[from]=num; } struct node{ int nxt,to; }e[wx*2]; void Add(int from,int to){ e[++Num].nxt=h[from]; e[Num].to=to; h[from]=Num; } void Tarjan(int u){ dfn[u]=low[u]=++tot; st[++top]=u; for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(!dfn[v]){ Tarjan(v); low[u]=min(low[u],low[v]); } else if(!belong[v]){ low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]){ belong[u]=++col; size[col]++; while(st[top]!=u){ belong[st[top]]=col; size[col]++; top--; } top--; } } int dfs(int u,int fa){ if(f[u])return f[u]; f[u]=size[u]; for(int i=h[u];i;i=e[i].nxt){ int v=e[i].to; if(v==fa)continue; f[u]+=dfs(v,u); } return f[u]; } int main(){ n=read(); for(int i=1;i<=n;i++){ int x; x=read(); add(i,x); } for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i); for(int u=1;u<=n;u++){ for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(belong[u]!=belong[v]){ in[belong[v]]++; Add(belong[u],belong[v]); } } } for(int i=1;i<=col;i++){ if(!in[i])dfs(i,0); } for(int i=1;i<=n;i++){ printf("%d\n",f[belong[i]]); } return 0; }