1. 程式人生 > >p2921 Trick or Treat on the Farm

p2921 Trick or Treat on the Farm

type return ble getch ron org nbsp 就會 ostream

傳送門

題目

每年萬聖節,威斯康星的奶牛們都要打扮一番,出門在農場的N個牛棚裏轉 悠,來采集糖果.她們每走到一個未曾經過的牛棚,就會采集這個棚裏的1顆糖果。農場不大,所以約翰要想盡法子讓奶牛們得到快樂.他給每一個牛棚設置了一個“後繼牛 棚”.牛棚i的後繼牛棚是next_i 他告訴奶牛們,她們到了一個牛棚之後,只要再往後繼牛棚走去, 就可以搜集到很多糖果.事實上這是一種有點欺騙意味的手段,來節約他的糖果.第i只奶牛從牛棚i開始她的旅程.請你計算,每一只奶牛可以采集到多少糖果.

分析

首先我們先進行Tarjan縮點,將每點權值賦為環中點數,意為走入這個環可獲得的糖果數。因為只有一條出邊,所以之後我們便進行dfs,從每一個點出發所獲糖果數即為它自身權值+由它到達的點出發所能獲得的糖果數。

代碼
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<stack>


using namespace std;
int vis[110000],size[110000],nxt[110000],ist[110000],dfn[110000],low[110000];
int sum,cnt,belong[110000],nxt2[110000],all[110000];
stack<int>a;
inline void read(int &x){
int f=1;x=0;
char s=getchar();
while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();}
while(s>=‘0‘&&s<=‘9‘){x=x*10+(s-‘0‘);s=getchar();}

x*=f;
}
inline void tarjan(int x){
dfn[x]=low[x]=++cnt;
a.push(x);
ist[x]=1;
if(!dfn[nxt[x]]){
tarjan(nxt[x]);
low[x]=min(low[x],low[nxt[x]]);
}else if(ist[nxt[x]]){
low[x]=min(low[x],dfn[nxt[x]]);
}
if(dfn[x]==low[x]){
sum++;
while(1){
int u=a.top();
a.pop();
ist[u]=0;
belong[u]=sum;
all[sum]++;
if(u==x)break;
}
}
}
inline void go(int x){
if(size[x])return;
size[x]=all[x];
vis[x]=1;
if(!nxt2[x])return;
go(nxt2[x]);
size[x]+=size[nxt2[x]];
}
int main(){
int n,m,i,j,k;
read(n);
for(i=1;i<=n;i++)read(nxt[i]);
for(i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
for(i=1;i<=n;i++)
if(belong[i]!=belong[nxt[i]])nxt2[belong[i]]=belong[nxt[i]];
for(i=1;i<=sum;i++)
if(!vis[i])
go(i);
for(i=1;i<=n;i++)printf("%d\n",size[belong[i]]);
return 0;
}

p2921 Trick or Treat on the Farm