朴素并查集
并查集(又加找父亲 hh)
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,并就是按一定顺序将属于同一组的元素所在的集合合并。
并查集的基本操作:
1.初始化,使每个节点的祖宗节点为自己。
2.将两个集合合并成一个集合。
3.查找两个元素是否在一个集合。
最关键的就是find函数:
int find(int x) { if(f[x]!=x) f[x]=find(f[x]); return f[x]; }
find函数是用来寻找每个节点的祖宗节点是哪个 以当前的节点的集合开始寻找,如果自身不是祖宗节点,则询问父亲节点,直到寻找到祖宗节点并且回溯将每个节点全部连接到祖宗节点,即使祖宗节点成为其父亲节点。
一共有n个数,编号是1~n,最开始每个数各自在一个集合中。
现在要进行m个操作,操作共有两种:
- “M a b”,将编号为a和b的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
- “Q a b”,询问编号为a和b的两个数是否在同一个集合中;
输入格式
第一行输入整数n和m。
接下来m行,每行包含一个操作指令,指令为“M a b”或“Q a b”中的一种。
输出格式
对于每个询问指令”Q a b”,都要输出一个结果,如果a和b在同一集合内,则输出“Yes”,否则输出“No”。
每个结果占一行。
上代码:
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int a,b; 6 int f[100010]; 7 int find(int x) 8 { 9 if(f[x]!=x) f[x]=find(f[x]); 10 return f[x]; 11 } 12 int main() 13 { 14 int n,m; 15 cin>>n>>m; 16 for(int i=1;i<=n;i++) f[i]=i;//初始化,使每个节点的祖宗节点是自己 17 char str[2]; 18 while(m--) 19 { 20 scanf("%s%d%d",str,&a,&b); 21 //使a的父亲节点变成b的祖宗节点,即使两个集合合并成一个集合 22 if(str[0]=='M') f[find(a)]=find(b); 23 else 24 { 25 if(find(a)==find(b)) cout<<"Yes"<<endl; 26 //如果a的祖宗节点等于b的祖宗节点,那么说明a,b在同一个集合 27 else cout<<"No"<<endl; 28 } 29 } 30 }