【CF698B】fix a tree

CF698B

给出 n 个结点的父亲,问至少修改多少个结点的父亲,能使整张图变成
一棵树(根的父亲为自己),要求输出任一方案。
其中 1 ≤ n ≤ 200000

我是想做图论的 然后他可以用并查集来做ye? 用并查集来判断各种状态

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#include<stack>
#include<algorithm>
using namespace std;
#define ll long long
#define rg register
const int N=200000+5,pw=11,inf=0x3f3f3f3f,P=19650827;
int n,m,ans=0,root=-1,a[N],f[N];
template <class t>void rd(t &x)
{
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void Union(int x,int y) {f[find(y)]=find(x);}

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("nocows.out","w",stdout);
    rd(n);
    for(int i=1;i<=n;++i){
        rd(a[i]);
        f[i]=i;
        if(a[i]==i) root=i;
    }
    for(int i=1;i<=n;++i){
        if(a[i]==root&&a[i]==i) continue;
        if(a[i]==i&&a[i]!=root){
            a[i]=root,++ans;
            Union(a[i],root);
        }
        else if(a[i]!=i&&find(a[i])!=find(i)) Union(a[i],i);
        else if(a[i]!=i&&find(a[i])==find(i)){
            if(!(root+1)) root=i;
            a[i]=root,++ans;
            Union(root,i);
        }
    }
    printf("%d
",ans);
    for(int i=1;i<=n;++i) printf("%d ",a[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/lxyyyy/p/11004280.html