并查集是什么?
P3367 【模板】并查集 题解
初学者必码的一道题。
并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。
关于并查集和路径压缩:
有a,b,c三个人
假设a和b打架了,a做了b的小弟。则令f[a]=b;
后来a打赢了c 黑社会
那么c就是a的小弟了。所以,令f[c]=a;
但是,c不知道b,这不符合要求。
所以,我们必须让c的大哥变成最大的老大。
定义函数find
int find(int k){
if(f[k]==k)return k;
return find(f[k]);
}
f[c]=find(a);
这时,我们可以使途中经过的人的大哥也变成老大。
//路径压缩
int find(int k){
if(f[k]==k)return k;
return f[k]=find(f[k]);
}
f[c]=find(a);
简直是太巧妙了!
而判定两个人的老大是否相等,只需用
if(find(a)==find(b))
就好了。
(在其中,一个人不能有两个老大。当已经有老大的人臣服时,老大也将成为胜利的人的小弟)
不说了,上代码:
#include<bits/stdc++.h>
using namespace std;
int i,j,k,n,m,s,ans,f[10010],p1,p2,p3;
//f[i]表示i的集合名
int find(int k){
//路径压缩
if(f[k]==k)return k;
return f[k]=find(f[k]);
}
int main()
{
cin>>n>>m;
for(i=1;i<=n;i++)
f[i]=i;//初始化i的老大为自己
for(i=1;i<=m;i++){
cin>>p1>>p2>>p3;
if(p1==1)
f[find(p2)]=find(p3);
//p3打赢了p2
else
if(find(p2)==find(p3))
//是否是一伙的
printf("Y\n");
else
printf("N\n");
}
return 0;
}