P2921 [USACO08DEC]Trick or Treat on the Farm G
作者:互联网
分析
这题蛮简单的,就不多说什么了。
记录的主要原因是,有个比较有意思的小用法。
如果图是一个基环树森林,这时,我们要求的是,对于其中每个点,从该点出发最多能过多少个不重复的点。可以跑一个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;
}
标签:cnt,idx,int,st,Trick,Farm,dfn,low,P2921 来源: https://www.cnblogs.com/aitejiu/p/15578368.html