传送门
题意: 给出每个编号下一个要到达的编号, 问最后每个标号可以到达的编号数量(具体可以看样例)
思路: 很明显有环的情况需要考虑, 所以实际上这是一副链环的有向的非联通图, 有自环的情况. 所以我们有先把链的情况删掉, 然后统计出每个环的大小, 然后再次累加到那些链的上面就行了. 就按照这个实现即可. 具体细节还要自己思考下…
AC Code
const int maxn = 1e5+5;
int ans[maxn], in[maxn], a[maxn];
int vis[maxn];
void bfs(int st) {
queue<int>q; q.push(st);
while(!q.empty()) {
int u = q.front(); q.pop(); vis[u] = 1;
if (--in[a[u]] == 0) q.push(a[u]);
}
}
int cnt;
void dfs1(int u) {
++ cnt; vis[u] = 2;
ans[u] = cnt;
if (vis[a[u]]) return ;
dfs1(a[u]);
ans[u] = cnt;
}
int dfs2(int u) {
ans[u] = 1; vis[u] = 2;
if (vis[a[u]] == 2) return ans[u] += ans[a[u]];
ans[u] += dfs2(a[u]);
return ans[u];
}
void solve() {
int n; scanf("%d", &n);
for (int i = 1 ; i <= n ; i ++) {
scanf("%d", a+i);
++ in[a[i]];
}
for (int i = 1 ; i <= n ; i ++) {
if (!in[i] && !vis[i]) bfs(i); // 删链
}
for (int i = 1 ; i <= n ; i ++) {
if (!vis[i]) cnt = 0, dfs1(i); // 统计环的大小
}
for (int i = 1 ; i <= n ; i ++) {
if (!ans[i]) dfs2(i); // 累加到链上面
}
for (int i = 1 ; i <= n ; i ++) {
printf("%d\n", ans[i]);
}
}