Codeforces Round #363 (Div. 1) B. Fix a Tree 拆环+合并树
2016-07-20 18:36
288 查看
传送门
思路:
这里的树如果没有形成环的话,用并查集就可以搞定了,可是有环的话并查集会无限递归,怎么办呢?
解环,这里用的是一个vis数组,每次从某个节点不停向上找,找到已经访问过的就停止(这里既可以判环也可以判是否连通),用index来表示每一次访问,如果之间已经访问过,但这次同样在这里终止循环,那么说明这是一个共同的树根,无须处理,如果这是第一次访问到这个根或者环,那么我们统统把这个根或者环的终点(因为采用了循环,所以会有几个终点)指向我们标好的s树根,并且次数加+1.
GG
思路:
这里的树如果没有形成环的话,用并查集就可以搞定了,可是有环的话并查集会无限递归,怎么办呢?
解环,这里用的是一个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 Round #197 (Div. 2)
- Codeforces Round #198 (Div. 1)
- Codeforces 405E Codeforces Round #238 (Div. 2)E
- Codeforces 407C Codeforces Round #239 (Div. 1)C
- CodeForces 449A - Jzzhu and Chocolate
- CodeForces 449 B. Jzzhu and Cities
- codeforces 618C. Constellation
- Codeforces Round #349 (Div. 2) - C
- Codeforces Round #361 (Div. 2)
- 7.13Codeforces Round #360 (Div. 2)
- Codeforces Round #265 (Div. 2)
- Codeforces #310 div2 C. Case of Matryoshkas
- 状态压缩DP codeforces 244 Problem C. The Brand New Function 和 codeforces 165 E. Compatible Numbers
- codeforces 16 Problem E fish
- Codeforces Round332 部分题解
- CodeForces 603A_Alternative Thinking (DP)
- CodeForces 602B_Approximating a Constant Range_DP
- Codeforces round #247 for Div. 2
- Codeforces Round #246 (Div. 2)
- Codeforces Round #356 (Div. 2)