需要将并查集与矢量法则相结合。par数组用以记录父节点,rank用以记录与父节点的关系。如题意,有两种关系,设定0是属于同一个帮派,1表示不属于同一个帮派。
运用并查集的时候判断x,y时考虑几种情况:
1.x与y父节点不相同:此时为不清楚两者关系。
2.x与y父节点相同,rank的值也相同:两者属于同一帮派。
3.x与y父节点相同,rank的值不相同:两者不属于同一帮派。
要得到这个关系,需要在并查集的find函数内对各个点的rank和par的值进行不断的更新。
对于rank,需要使用矢量加法,如
$\overrightarrow{AB}+\overrightarrow {BC}=\overrightarrow {AC}$
结合题目就是例:x的父节点px,如果x与父节点的关系是rank[x],px与父节点的关系是rank[px],那么x与par[px]的关系就是
$(rank[x] + rank[px])\%2$
其他的推理类似。
在find的路径压缩时,注意把rank关系进行更新即可,在union时涉及到x,y与它们的父节点px,py的rank值更新,其实原理相同。
1 #include <cstdio> 2 #include <iostream> 3 #include <fstream> 4 5 using namespace std; 6 7 const int MAXN = 1e5+4; 8 int par[MAXN]; 9 int Rank[MAXN]; 10 11 void init() 12 { 13 for(int i = 0; i < MAXN; i++) 14 { 15 par[i] = i; 16 Rank[i] = 0; 17 } 18 } 19 20 int find(int x) 21 { 22 if(par[x] == x) 23 return x; 24 int px = par[x]; 25 par[x] = find(par[x]); 26 Rank[x] = (Rank[px]+Rank[x])%2; 27 return par[x]; 28 } 29 30 void Union(int x, int y) 31 { 32 int px = find(x); 33 int py = find(y); 34 if(px == py) 35 return; 36 par[px] = py; 37 Rank[px] = (Rank[x]+1+Rank[y])%2; 38 } 39 40 int main() 41 { 42 //freopen("input.txt", "r", stdin); 43 //freopen("out.txt", "w", stdout); 44 int T, M, N, x, y; 45 char op; 46 47 while(scanf("%d", &T)!=EOF) 48 { 49 50 while(T--) 51 { 52 init(); 53 scanf("%d %d", &N, &M); 54 for(int i = 0; i < M; i++) 55 { 56 getchar(); 57 scanf("%c %d %d", &op, &x, &y); 58 if(op == ‘A‘) 59 { 60 int px = find(x); 61 int py = find(y); 62 if(px != py) 63 { 64 puts("Not sure yet."); 65 } 66 else 67 { 68 if(Rank[x] == Rank[y]) 69 puts("In the same gang."); 70 else 71 puts("In different gangs."); 72 } 73 } 74 else 75 { 76 Union(x, y); 77 } 78 } 79 } 80 } 81 return 0; 82 }
POJ_1703 Find them, Catch them 【并查集】
原文:https://www.cnblogs.com/dybala21/p/10134417.html