并查集,顾名思义有两个操作:合并和查询。
并就是把两个集合合并到一起。
查就是查询两个节点是否属于同一个集合。
每个节点有一个父节点。一个集合内存在一个唯一的根,判断根的条件就是节点的父节点是不是该节点本身。
合并操作就是把一个集合的根接到另一个集合的根上。
而查询操作就是找两个对象是否有同一个根。
查询过程中可以顺便进行路径压缩以优化后续查询:即让查找路径上所有节点的父节点直接等于根节点。
#include <iostream>
#include <algorithm>
#include <cstring>
#define MAX 200005
using namespace std;
int root[MAX];
char names[MAX][50];
unsigned int BKDRHash(char *str)
{
unsigned int seed = 131;
unsigned int hash = 0;
while (*str)
{
hash = hash * seed + (*str++);
}
return (hash & 0x7FFFFFFF) % MAX;
}
int get_index(char *str) {
int res = BKDRHash(str);
while (strlen(names[res]) != 0 && strcmp(str, names[res])) {
res++;
res %= MAX;
}
if (strlen(names[res]) == 0) {
strcpy(names[res], str);
}
return res;
}
int get_root(int a) {
if (root[a] == -1) root[a] = a;
if (a != root[a]) {
root[a] = get_root(root[a]);
}
return root[a];
}
int main() {
int n;
int op;
char s1[50], s2[50];
int a, b;
memset(root, -1, sizeof(root));
cin >> n;
while (n--) {
cin >> op >> s1 >> s2;
a = get_index(s1);
b = get_index(s2);
if (op == 0) {
int fa = get_root(a), fb = get_root(b);
root[fa] = fb;
} else {
int fa = get_root(a), fb = get_root(b);
if (fa == fb) {
cout << "yes" << endl;
}
else {
cout << "no" << endl;
}
}
}
return 0;
}