并查集是一个树形的数据结构, 可以用来处理集合的问题, 也可以用来维护动态连通性,或者元素之间关系的传递(关系必须具有传递性才能有并查集来维护,因为并查集有压缩路径)。
用并查集来维护元素之间关系的传递, 那么元素与元素之间就有一个权值(带权并查集),那么当路径压缩时,我们需要根据关系的传递性来维护
当父元素变动时,关系的变动。
给定一些元素之间的关系, 问我们有多少是错误的。 当碰到一个错误时,并不会用它来更新并查集(错误的怎么用来更新?),只会把ans++
我们用0表示与父亲是同类, 用1表示吃父亲 , 用2表示被父亲吃。(这表示的是我与父亲的关系,即箭头是由我指向父亲), 那怎么得到父亲与我的关系呢?
只要将箭头的方向改变, 就得到了父亲与我的关系, (3-rank[x]) % 3 就是了
只要明白了箭头方向的改变,关系也可以用公式推导出来
那么下边就好办了, 如果判断是否发生错误呢?
如图,红色的线表示题目给我们的关系, 现在他们在一个集合里面,可以通过运算获得蓝线1,然后再通过计算获得蓝线2, 只要将蓝线2和红线对比,就知道
题目所给的关系是否正确。
同理,集合的合并也是一样的
通过红线1,依次算出蓝线1,2,3. 那么就可以进行集合的合并了。
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <algorithm> 5 #include <iostream> 6 #include <queue> 7 #include <stack> 8 #include <vector> 9 #include <map> 10 #include <set> 11 #include <string> 12 #include <math.h> 13 using namespace std; 14 #pragma warning(disable:4996) 15 #pragma comment(linker, "/STACK:1024000000,1024000000") 16 typedef long long LL; 17 const int INF = 1<<30; 18 /* 19 路径压缩的时候要保留结点与结点之间的关系, 所以要维护的一个信息是,结点之间的关系 20 0同类 , 1被父亲吃, 2吃父亲 21 */ 22 const int N = 50000 + 10; 23 int fa[N]; 24 int id[N];//id[u] 表示与父亲之间的边的权值,, 权值为0,1,2三种 25 int find(int x) 26 { 27 if (x == fa[x]) 28 return x; 29 //路径压缩的时候,由于父亲的改变, 需要改变权值 30 int tmp = fa[x]; 31 fa[x] = find(fa[x]); 32 id[x] = (id[x] + id[tmp]) % 3; 33 return fa[x]; 34 } 35 int main() 36 { 37 int n, m, ans; 38 int d, a, b; 39 int fx, fy; 40 //while (scanf("%d%d", &n, &m) != EOF) 41 { 42 scanf("%d%d", &n, &m); 43 ans = 0; 44 for (int i = 1; i <= n; ++i) 45 { 46 fa[i] = i; 47 id[i] = 0; 48 } 49 while (m--) 50 { 51 scanf("%d%d%d", &d, &a, &b); 52 if (d == 1) 53 { 54 if (a > n || b > n) 55 ans++; 56 else 57 { 58 fx = find(a); 59 fy = find(b); 60 if (fx != fy) 61 { 62 fa[fy] = fx; 63 id[fy] = ((3 - id[b])%3 + (d - 1) + id[a]) % 3; 64 } 65 else 66 { 67 if ((3-id[a]+id[b])%3 != 0) 68 ans++; 69 70 } 71 } 72 } 73 else 74 { 75 if (a > n || b > n) 76 ans++; 77 else 78 if (a == b) 79 ans++; 80 else 81 { 82 fx = find(a); 83 fy = find(b); 84 if (fx != fy) 85 { 86 fa[fy] = fx; 87 id[fy] = ((3 - id[b])%3 + (d - 1) + id[a]) % 3; 88 } 89 else 90 { 91 if ((3 - id[a] + id[b])%3 != 1) 92 ans++; 93 } 94 } 95 } 96 } 97 printf("%d\n", ans); 98 } 99 return 0; 100 }