Codeforces Round #363 (Div. 1) B. Fix a Tree 拆环+合并树

来源:互联网 发布:删除淘宝评价怎么删 编辑:程序博客网 时间:2024/06/05 08:37

传送门

思路:
这里的树如果没有形成环的话,用并查集就可以搞定了,可是有环的话并查集会无限递归,怎么办呢?
解环,这里用的是一个vis数组,每次从某个节点不停向上找,找到已经访问过的就停止(这里既可以判环也可以判是否连通),用index来表示每一次访问,如果之间已经访问过,但这次同样在这里终止循环,那么说明这是一个共同的树根,无须处理,如果这是第一次访问到这个根或者环,那么我们统统把这个根或者环的终点(因为采用了循环,所以会有几个终点)指向我们标好的s树根,并且次数加+1.
GG

#include <cstdio>#include<iostream>using namespace std;const int maxn = 200200;int f[maxn], vis[maxn], n, s, cnt, idx;int Find(int x){    vis[x] = ++ idx;    while (!vis[ f[x] ])    {        x = f[x];        vis[x] = idx;    }    if (vis[ f[x] ] == idx)    {        if (s == 0)//s==0表明全是环,这时我们要从这些环里再确定一个根,            s = x;        if (f[x] != s)        {            f[x] = s;            cnt ++;        }    }}int main(){    scanf("%d", &n);    for (int i = 1; i <= n; i ++)        scanf("%d" , f + i);    for (int i = 1; i <= n; i ++)        if (i == f[i])            s = i;    for (int i = 1; i <= n; i ++)        if (!vis[i])            Find(i);    printf("%d\n", cnt);    for (int i = 1; i <= n; i ++)        printf("%d ", f[i]);    return 0;}
0 0
原创粉丝点击