并查集
将若干对象划分为不相交的集合,在每个集合中选择某个元素代表所在集合
可以用编号最小的元素标记,也可以开辟一个数组a[],a[i]代表元素i所在的集合
并查集常见的运算有merge find 数组操作find是O(1)时间,merge是O(n)时间
树状结构,fa[i]代表i的父节点,判断元素是否位于同一集合,查找他们是否有共同的祖先,合并就是讲两个根节点合并
如果可以舍弃层级关系,只是反映集合关系,可以将一个集合的所有节点都直接指向祖先
#include<vector>
#include<cstdio>
#include<iostream>
using namespace std;
const int INF = 1000;
int fa[INF];
int find(int x)//找到x的祖先
{
while (fa[x] != x) {
x = fa[x];
}
return x;
}
int Find(int x)//找到x的祖先并且原来路径上的点都指向共同的祖先(非递归路径压缩)
{
int r = x;
while (fa[r] != r)r = fa[r];
while (fa[x] != x) {
int f = fa[x];
fa[x] = r;
x = f;
}
return r;
}
void merge(int x, int y)//把两个点(集合)合并
{
int fx = Find(x), fy = Find(y);
if (fx == fy)return;
fa[fy] = fx;
}
int main()
{
int n;//n是结点的数目
cin >> n;
for (int i = 1; i <= n; i++)fa[i] = i;
int edge;//边的数目
cin >> edge;
int fir, sec;
for (int i = 0; i < edge; i++) {
cin >> fir >> sec;
merge(fir, sec);
}
int ques;
cin >> ques;
for (int i = 0; i < ques; i++) {
int a, b;
cin >> a >> b;
int f_a = Find(a), f_b = Find(b);
if (f_a == f_b)printf("Yes\n");//询问两个点是否有共同的祖先
else printf("No\n");
}
}

浙公网安备 33010602011771号