利用并查集判断环和树
第一次两个节点判断是,如果不在一个树上就合并,如果出现两个点在一个树上就说明出现了环
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 200000 + 10;
int a[maxn], p[maxn];
int tofind(int x){
if(x == p[x]) return x;
return p[x] = tofind(p[x]);
}
void join(int x, int y){
int px = tofind(x);
int py = tofind(y);
p[px] = py;
}
int main(){
int n;
scanf("%d", &n);
int root = -1;
for(int i = 1; i <= n; i++) p[i] = i;
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
if(i == a[i])
root = i;
}
int pv, pu;
int ans = 0;
for(int i = 1; i <= n; i++){
if(a[i] != root){
pu = tofind(i);
pv = tofind(a[i]);
if(pu == pv){
ans++;
if(root == -1) root = i;
a[pu] = root;
}
else{
join(i, a[i]);
}
}
}
printf("%d\n", ans);
for(int i = 1; i <= n; i++){
if(i == 1) printf("%d", a[i]);
else printf(" %d", a[i]);
}
printf("\n");
return 0;
}