题目链接: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;
}