您的位置:首页 > 其它

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

2016-07-20 18:36 288 查看
传送门

思路:

这里的树如果没有形成环的话,用并查集就可以搞定了,可是有环的话并查集会无限递归,怎么办呢?

解环,这里用的是一个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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces