先tarjan缩点,然后记忆化搜索。。每个点就一个出度,重建图后一个强连通若是大于1则不可能有出度。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define pa pair<int,int>
#define N 100010
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,to[N],to1[N],dfn[N],low[N],dfnum=0,bel[N],sz[N],scc=0,ans[N];
bool inq[N];
stack<int>q;
void tarjan(int x){
dfn[x]=low[x]=++dfnum;q.push(x);inq[x]=1;
if(!dfn[to[x]]) tarjan(to[x]),low[x]=min(low[x],low[to[x]]);
else if(inq[to[x]]) low[x]=min(low[x],dfn[to[x]]);
if(low[x]==dfn[x]){
++scc;while(1){
int y=q.top();q.pop();inq[y]=0;
bel[y]=scc;sz[scc]++;if(x==y) break;
}
}
}
void rebuild(){
for(int i=1;i<=n;++i)
if(bel[i]!=bel[to[i]])
to1[bel[i]]=bel[to[i]];
}
int solve(int x){
if(ans[x]) return ans[x];
ans[x]=sz[x];
if(sz[x]==1&&to1[x]) ans[x]+=solve(to1[x]);
return ans[x];
}
int main(){
// freopen("a.in","r",stdin);
n=read();for(int i=1;i<=n;++i) to[i]=read();
for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
rebuild();
for(int i=1;i<=n;++i)
printf("%d\n",solve(bel[i]));
return 0;
}