洛谷 P2921 在农场万圣节
https://www.luogu.org/problemnew/show/P2921
开始感觉这题30行代码就可以搞定,还是太菜啦,还是乖乖地写了tarjan。
对图进行缩点,那么这个强联通分量中的点多余一个,那么这个环中的每个点的最长路径就是这个环(因为每个点只有一条连出去的有向边)。
对于不在环中的点,每个点搜索,当搜到一个环时,直接返回这个环中点的个数,搜不到环返回1.
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; int n,m,a[100006],ans[100006],sum[100006]; bool vis[100006]; int low[100006],dfn[100006],Index; bool in[100006]; int stack[100006],top; int belong[100006],cnt; void tarjan(int u) { low[u]=dfn[u]=++Index; in[u]=1;stack[++top]=u; if(a[u]) { int v=a[u]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(in[v]&&low[u]>dfn[v])low[u]=dfn[v]; } if(low[u]==dfn[u]) { int p; ++cnt; do { p=stack[top--]; belong[p]=cnt; in[p]=0; }while(p!=u); } } int dfs(int x) { if(ans[x])return ans[x]; ans[x]=1; if(a[x])ans[x]+=dfs(a[x]); return ans[x]; } int main() { int x; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i]==i)ans[i]=1; } for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); for(int i=1;i<=n;i++)sum[belong[i]]++; for(int i=1;i<=n;i++) if(sum[belong[i]]>1)ans[i]=sum[belong[i]]; for(int i=1;i<=n;i++) if(!ans[i])dfs(i); for(int i=1;i<=n;i++)printf("%d\n",ans[i]); }
除特别注明外,本站所有文章均为Manjusaka丶梦寒原创,转载请注明来自出处