今天一定彻底弄懂 带权并查集
好吧这题我还是不懂,,,烦躁
现在基本上知道了吧,不过不清楚公式是怎样推出来的,如果要我再写一遍的话,估计会写很多个判断
1 #include <iostream> 2 #include <cstdio> 3 #include <fstream> 4 #include <algorithm> 5 #include <cmath> 6 #include <deque> 7 #include <vector> 8 #include <queue> 9 #include <string> 10 #include <cstring> 11 //#include <unordered_map> 12 #include <map> 13 #include <stack> 14 #include <set> 15 #define LL long long 16 #define INF 0x3f3f3f3f 17 #define OPEN_FILE 18 #define MAXN 50005 19 using namespace std; 20 int n, k; 21 int father[MAXN]; 22 int ranK[MAXN]; 23 //rank[x]表示x 与 father[x] 的关系,0 是同类,1 是 x 吃 father[x], 2 是 father[x] 吃 x 24 int find(int x){ 25 if (x == father[x]) return x; 26 int y = father[x]; 27 father[x] = find(father[x]); 28 ranK[x] = (ranK[x] + ranK[y]) % 3; 29 //rank[x]=1,rank[y]=1,表示x吃路径压缩前的的father[x] 30 //压缩前的father[x]吃压缩后的father[x],那么就是压缩后的father[x]吃x 31 //所以rank[x]更新为2 32 //rank[x] = 1, rank[y] = 1 ====> rank[x] = 2 33 //rank[x] = 1, rank[y] = 2 ====> rank[x] = 0 34 //rank[x] = 2, rank[y] = 1 ====> rank[x] = 0 35 //rank[x] = 0, rank[y] = 1 ====> rank[x] = 1 36 //rank[x] = 1, rank[y] = 0 ====> rank[x] = 1 37 //rank[x] = 2, rank[x] = 2 ====> rank[x] = 1 38 return father[x]; 39 } 40 void union_set(int x, int y, int z){ 41 int a = father[x], b = father[y]; 42 father[a] = b; 43 ranK[a] = (z + ranK[y] - ranK[x] + 3) % 3; 44 //这里仅仅是更新了father[x]的rank值, 并没有更新其他的子节点 45 //因为每次查询时都调用了find函数,在路径压缩的回溯过程中就会将其他节点的rank值更新 46 //如果公式看不过来的话,那就有下面这几种情况 47 //rank[x] = 1, rank[y] = 1, z = 1 ====> rank[a] = 1 48 //rank[x] = 0, rank[y] = 1, z = 1 ====> rank[a] = 2 49 //因为情况比较多,就不一一列举了,但是很好奇这个公式是怎样想出来的 50 //看到别人的博客中提到向量? 51 } 52 int main() 53 { 54 #ifdef OPEN_FILE 55 freopen("in.txt", "r", stdin); 56 //freopen("out.txt", "w", stdout); 57 #endif // OPEN_FILE 58 scanf("%d%d", &n, &k); 59 for (int i = 1; i <= n; i++){ 60 father[i] = i; 61 } 62 memset(ranK, 0, sizeof(ranK)); 63 int x, y, z; 64 int cnt = 0; 65 for (int i = 1; i <= k; i++){ 66 scanf("%d%d%d", &z, &x, &y); 67 if (x > n || y > n){ 68 cnt++; 69 continue; 70 } 71 if (x == y && z == 2){ 72 cnt++; 73 continue; 74 } 75 if (x == y) continue; 76 int a = find(x), b = find(y); 77 if (a == b && ranK[x] != (z - 1 + ranK[y]) % 3){ 78 //如果father[x]!=father[y],那这两个还不属于同一个集合,谈不上假话了 79 //属于同一个集合,就有下面几种情况可以保证是真话 80 //z - 1 = 1, rank[y] = 2, rank[x] = 0 给的条件是x吃y,而y被他们的祖先吃,那只有x和father[y]是同类才可能是真话了 81 //z - 1 = 1, rank[y] = 0, rank[x] = 1 82 //z - 1 = 1, rank[y] = 1, rank[x] = 2 83 //z - 1 = 0, rank[y] = 0, rank[x] = 0 84 //z - 1 = 0, rank[y] = 1, rank[x] = 1 85 //z - 1 = 0, rank[y] = 2, rank[x] = 2 86 cnt++; 87 } 88 if (a != b){ 89 //还不属于同一个集合的话就肯定是真话,那就把他们的关系加到集合中来 90 union_set(x, y, z - 1); 91 } 92 } 93 printf("%d ", cnt); 94 }