缩点+记忆化
【代码】
#include <cstdio>
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#define N 1000005
#define M 1000005
#define INF 1000000000
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pa;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,ind,scc;
int b[N],num[N];
int dfn[N],low[N],Belong[N],ans[N];
bool Instack[N];
vector<int>g[N];
stack<int>st;
void Input_Init()
{
n=read();
for(int i=1;i<=n;i++)
b[i]=read();
}
void Tarjan(int x)
{
dfn[x]=low[x]=++ind;
st.push(x);Instack[x]=1;
int v=b[x];
if(!dfn[v])
{
Tarjan(v);
low[x]=min(low[x],low[v]);
}
else if(Instack[v]) low[x]=min(low[x],dfn[v]);
if(dfn[x]==low[x])
{
int now=-1;scc++;
while(now!=x)
{
now=st.top();st.pop();
Belong[now]=scc;
Instack[now]=0;
num[scc]++;
}
}
}
void Get_Scc(){
for(int i=1;i<=n;i++)
if(!dfn[i]) Tarjan(i);
}
void Build_Graph()
{
for(int i=1;i<=n;i++)
if(Belong[i]!=Belong[b[i]])
g[Belong[i]].push_back(Belong[b[i]]);
}
int dfs(int x)
{
if(ans[x]) return ans[x];
ans[x]=num[x];
if(g[x].size()) ans[x]+=dfs(g[x][0]);
return ans[x];
}
int main()
{
Input_Init();
Get_Scc();
Build_Graph();
for(int i=1;i<=n;i++)
printf("%d\n",dfs(Belong[i]));
return 0;
}