P2921 [USACO08DEC]Trick or Treat on the Farm G
阿新 • • 發佈:2021-11-19
分析
這題蠻簡單的,就不多說什麼了。
記錄的主要原因是,有個比較有意思的小用法。
如果圖是一個基環樹森林,這時,我們要求的是,對於其中每個點,從該點出發最多能過多少個不重複的點。可以跑一個tarjan,接下來,就在跑出來的拓撲圖上,跑一個最長路就得到答案了
Ac_code
#include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10,M = 2*N; int h[N],hs[N],e[M],ne[M],idx; int dfn[N],low[N],timestamp; int id[N],Size[N],cnt,f[N],d[N]; bool st[N]; stack<int> s; int n; void add(int h[],int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void tarjan(int u) { dfn[u]=low[u]=++timestamp; st[u]=1; s.push(u); for(int i=h[u];~i;i=ne[i]) { int j = e[i]; if(!dfn[j]) { tarjan(j); low[u]=min(low[u],low[j]); } else if(st[j]) low[u]=min(low[u],low[j]); } if(dfn[u]==low[u]) { int y; ++cnt; do { y = s.top(); s.pop(); st[y]=0; id[y]=cnt; Size[cnt]++; }while(y!=u); } } int main() { cin>>n; memset(h,-1,sizeof h); memset(hs,-1,sizeof hs); for(int i=1;i<=n;i++) { int x; cin>>x; add(h,i,x); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++) for(int j=h[i];~j;j=ne[j]) { int k = e[j]; if(id[i]!=id[k]){ add(hs,id[k],id[i]); d[id[i]]++; } } for(int i=1;i<=cnt;i++) if(!d[i]) f[i]=Size[i]; for(int i=1;i<=cnt;i++) for(int j=hs[i];~j;j=ne[j]) { int k = e[j]; f[k]=max(f[k],f[i]+Size[k]); } for(int i=1;i<=n;i++) cout<<f[id[i]]<<endl; return 0; }