什么叫扩展域并查集
1 和 2是敌人,那么就把1好12链接起来:表示1和2是敌人
2和11链接起来也是这个道理
然后2 和3使敌人同理。
最后12连接了1 和 3,表名1 和 3 是 2 的敌人,1和3 就是朋友
1.P1892 [BalticOI 2003] 团伙 - 洛谷
#include<iostream>
using namespace std;
const int N = 1010;
int f[N * 2];
int n, m;
int find(int x)
{
if (f[x] == x)return x;
return f[x] = find(f[x]);
}
void un(int x, int y)
{
f[find(y)] = find(x);
}
int main()
{
cin >> n >> m;//n个人,m个关系
for (int i = 1; i <= n * 2; i++)f[i] = i;//并查集和扩域并查集都要初始化
while (m--)
{
//关系,人,人
char opt; int p, q; cin >> opt >> p >> q;
if (opt == 'E')//敌人
{
//把后一个人的敌人域的父亲指定为前一个人的父亲,当该敌人域再次和前面一个数进行un时,就会把上一次指定的父亲的父亲指定为当前数,实现敌人的敌人朋友化,如果不懂可以自己画一遍
un(p, q + n);
un(q, p + n);
}
else if (opt == 'F')//朋友
{
un(p, q);
//如果是朋友的话,就把它两个连接起来
}
}
int ret = 0;
for (int i = 1; i <= n; i++)
{
if (f[i] == i)ret++;
}
cout << ret << endl;
}
2.记录详情 - 洛谷 | 计算机科学教育新生态
//3种关系->扩展域并查集
#include<iostream>
using namespace std;
const int N = 5e4 + 10;
int f[N * 3];
int n;//序号范围
int m;//几种说法
//并查集实现
int find(int x)
{
return (f[x] == x) ? x : f[x] = find(f[x]);
}
void un(int x, int y)
{
f[find(y)] = find(x);
}
int main()
{
cin >> n >> m;
int ret = 0;
//进行初始化,并查集初始化
for (int i = 1; i <= n * 3; i++)f[i] = i;
while (m--)
{
int op, x, y;
cin >> op >> x >> y;
//超过范围了
if (x > n || y > n)
{
ret++;
continue;
}
//当op = 1
if (op == 1)//两者是同类
{
//两者不是同类的情况:x->y || y -> x
if (find(x) == find(y + 2 * n) || find(x) == find(y + n))
{
ret++;
continue;
}
//两者是同类,进行维护
un(x, y);
un(x + n, y + n);
un(x + 2 * n, y + 2 * n);
}
else if (op == 2)//x->y
{
//两者不是x->y 是y->x||x == y
if (find(x) == find(y) || find(x) == find(y + n))
{
ret++;
continue;
}
//维护信息
un(x, y + 2 * n);
un(x + n, y);
un(x + 2 * n, y + n);
}
}
cout << ret << endl;
return 0;
}
一定要记得实现并查集的初始化
思想:根据关系,可以划分多个f[n*num],num:表示关系的种类
该题中一共有,同类,捕食,被捕食,三种关系,
扩展域并查集的核心就是找到谁和谁合并在一起。