题目链接:http://codeforces.com/problemset/problem/699/D
题目大意:
给你一个建图的序列。
a[i]表示i的父节点是a[i]。
问你最少改变多少个数字,使得这个图变成一棵树。
思路:如果有a[i]=i。那么把i当做默认的根。对于后面的建树序列如果有环,就把环拆开。连向根。
如果没有a[i]=i,就把第一个环的节点当做根。后面操作一样。判断环用并查集就可以实现。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int f[200005];
int a[200005];
int b[200005];
int fd(int x){
if(f[x]==-1){
return x;
}
else{
return f[x]=fd(f[x]);
}
}
int main()
{
int n, k=-1;
memset(f, -1, sizeof(f));
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
if(a[i]==i){
k=i;
}
}
for(int i=1; i<=n; i++){
int fx=fd(i);
int fy=fd(a[i]);
if(fx==fy){
if(k==-1){
k=i;
}
b[i]=k;
}
else{
f[fx]=fy;
b[i]=a[i];
}
}
int ans=0;
for(int i=1; i<=n; i++){
if(a[i]!=b[i]){
ans++;
}
}
printf("%d\n", ans);
for(int i=1; i<=n; i++){
printf("%d ", b[i]);
}
printf("\n");
return 0;
}