并查集

将若干对象划分为不相交的集合,在每个集合中选择某个元素代表所在集合
可以用编号最小的元素标记,也可以开辟一个数组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");
	}
}
posted @ 2021-09-15 16:49  empty_thought  阅读(33)  评论(0)    收藏  举报