并查集
并查集是个好东东,你们一定要学会!
序列合并需(),并查集只需(
)。
序列查询需(),并查集只需(
)。
做题想要速度快,用它!用它!用它!!!
并查集合并
刚才说了并查集的好处,接下来我们来讲一讲并查集如何把合并序列的时间复杂度从()化为(
)的。
并查集的核心主要就是他有一个‘祖宗节点’,来人了就判断和他的祖宗是不是一样的,不一样就强迫他认你的祖先为祖宗(大家不要学啊!)。
主要该如何实现呢?别急,接下来我来说亿说。
首先输入一组序列,选序列中任意一个点为祖宗(本人建议第一个点,以后方便),把序列中其他的数的祖先都设置为祖宗。
然后,再输入一个序列,步骤跟上一个一模一样。
注意,每个人的祖宗开始都是自己。
想合并这两个序列的话:
1.判断祖宗是否相同,相同你还咋强迫人家认祖宗?(认着认着突然来句:我和你是亲戚呀!尴尬~)
2.如果祖宗不同,就强迫b的祖宗认a的祖宗为祖宗(也就是把b序列里的数的祖宗都设置为a序列的祖宗,不孝顺的子孙)
然后......就没有然后了。
就这?!!
啊对,就这!
是不是很简单?
他们两个祖宗都一样了,自然就是一个序列的了。
有细心的同学可能会问了,那把b序列中的数的祖宗都设置为a序列的祖宗,时间复杂度不还是()吗?
问得好!!!
我也不知道......
啊开个笑,我怎么会不知道呢?
把b序列的祖宗(只有祖宗一个人)设置为a序列的祖宗就行了。查询b序列的时候只需要查询它的祖宗就行了。
可以这样理解。b序列的人都是大臣,平民,宰相......他们每天都是听皇上的,有事也是找皇上,他们不管皇上是谁,有事就去找皇上就对了!a序列的祖宗过来把b序列的皇帝给踹了他们照样找皇帝,只不过找的是a序列的祖宗了。
能理解了吧?
这就是并查集合并,接下来我来说亿说并查集查询。
并查集查询
其实我们刚才也说了如何查询n是哪一个序列的,就是去找皇帝嘛!
比如说:
要查询平民a是哪一个皇帝手下的,就让平民a去找地主b,让地主b去找城主c,再让城主c去找大臣d,大臣d去找宰相e,宰相e再去找皇帝f,找到皇帝f了,就可以判断平民a是哪个皇帝手下的啦!
简单来说,并查集查询就是这样一个过程。
从要查询的那一个数开始,一直查询的它的祖宗。
又有同学会问了(你们怎么那么多问题嘞?):
那一直判断,时间复杂度不也是()的吗?
问的依旧太好了,我依旧不知道。
啊我依旧开个玩笑,我依旧怎么可能会不知道呢?
咳咳,切回正题。
我们可以定义一个数组:f,每次查询到祖宗的时候,使f[(当前这个数)]=祖宗,使沿途的数的f也等于祖宗,这样我们只是第一次用到了(),其他时候我们都是(
)。
这就是并查集的主要思想,接下来,上题目!!!
题目背景
若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。
题目描述
规定: 和
是亲戚,
和
是亲戚,那么
和
也是亲戚。如果
,
是亲戚,那么
的亲戚都是
的亲戚,
的亲戚也都是
的亲戚。
输入格式
第一行:三个整数 (
),分别表示有
个人,
个亲戚关系,询问
对亲戚关系。
以下 行:每行两个数
,
,
,表示
和
具有亲戚关系。
接下来 行:每行两个数
,询问
和
是否具有亲戚关系。
输出格式
行,每行一个
或
。表示第 个询问的答案为“具有”或“不具有”亲戚关系。
好了,首先分析一下题,这是给你两个人的关系,让你判断两人是否是一家人。
当有两个人是亲戚时,我们可以把两人的家族已知人员合并成一个家族,用到我们的并查集合并。
判断的时候,就查祖先是否是一样的,用到我们的并查集查询。
接下来,上代码!!!
#include <bits/stdc++.h>
using namespace std;
int n,m,q,f[20010];
//n,m,q是题目所需变量,f是当前这个数的祖宗
int find(int x){
//查询祖宗
if(f[x]==x) return x;
//如果当前这个数的祖宗是这个数的话,说明这个数就是祖宗,返回它
return f[x]=find(f[x]);
//否则返回当前查询的这个数(递归),顺便使当前这个数的祖宗等于真的祖宗
}
int main(){
scanf("%d%d%d",&n,&m,&q);
//输入
for(int i=1;i<=n;i++) f[i]=i;
//每个人开始的祖宗都是自己(逞威风)
while(m--){
//循环m次,获得信息
int x,y;
//定义两个变量,代表两个人
scanf("%d%d",&x,&y);
//输入两个人的信息
f[find(x)]=find(y);
//使当前x的祖宗等于 y的祖宗(大孝子)
}
while(q--){
//循环q次,询问信息
int x,y;
//定义两个变量,代表两个人
scanf("%d%d",&x,&y);
//输入两个人的信息
x=find(x),y=find(y);
//x等于x的祖宗,y等于y的祖宗
if(f[x]==f[y]) printf("Yes\n");
//如果祖宗一样,就是一家人
else printf("No\n");
//否则风马牛不相及
}
return 0;
//结束程序
}
好了,这就是今天的内容,你们学废了吗?
.