定义:
并查集是一种用来管理元素分组情况的数据结构。
作用:
查询元素a和元素b是否属于同一组
合并元素a和元素b所在的组
优化方法:
1.路径压缩
2.添加高度属性
拓展延伸:
分组并查集
带权并查集
代码如下:
- //带有路径压缩的并查集
- //一句话并查集(常用)
- int dsu(int x){
- return x==par[x]?x:(par[x]=dsu(par[x]));
- }
- //带有路径压缩和高度的并查集
- //ranks[i]代表以i为根的树的最大高度,若不存在则为0
- int rank[maxn];
- int par[maxn];
- void init(int n){
- for(int i=0;i<n;i++){
- par[i]=i;
- rank[i]=0;
- }
- }
- int dsu(int x){
- if(par[x]==x){
- return x;
- }else{
- return par[x]=dsu(par[x]);
- }
- }
- void union(int x,int y){
- int fx=dsu(x);
- int fy=dsu(y);
- if(fx==fy){
- return;
- }
- if(rank[fx]<rank[fy]){
- par[fx]=fy;
- }else if(rank[fx]>rank[fy]){
- par[fy]=fx;
- }else{
- par[fy]=fx;
- rank[fx]++;
- }
- }
- bool same(int x,int y){
- return dsu(x)==dsu(y);
- }
- poj1182 食物链
- //带权并查集解法
- /*
- 模仿矢量计算来处理权值
- 当我们知道x与祖先x1的关系,y与祖先y1的关系,x与y的关系时,求x1与y1的关系时,使用矢量
- 计算:
- x1->x ->y ->y1
- */
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- const int maxn=50010;
- int par[maxn],ran[maxn];
- int dsu(int x){
- if(x==par[x]){
- return x;
- }else{
- int fx=dsu(par[x]);
- //一开始将par[x]写成了fx,一直wa
- //如果是fx,那么每一次都到最终的根节点,求解ran数组显然不正确
- ran[x]=(ran[x]+ran[par[x]]+3)%3;
- par[x]=fx;
- return par[x];
- }
- }
- int main()
- {
- int n,m;
- int ty,x,y,ans=0;
- scanf("%d%d",&n,&m);
- for(int i=0;i<=n;i++){
- par[i]=i;
- ran[i]=0;
- }
- while(m--){
- scanf("%d%d%d",&ty,&x,&y);
- if(x==y&&ty==2){
- ans++;
- }
- else if(x>n||y>n){
- ans++;
- }
- else{
- int fx=dsu(x);
- int fy=dsu(y);
- if(fx==fy)
- {
- if((ran[x]-ran[y]+3)%3!=ty-1){
- ans++;
- //这里如果不相等,说明这句话是错误的,continue
- //一开始因为没写continue,一直wa
- continue;
- }
- }
- par[fx]=fy;
- ran[fx]=(-ran[x]+ty-1+ran[y]+3)%3;
- }
- }
- printf("%d\n",ans);
- return 0;
- }
- //分组并查集解法
- /*
- 个人理解带权并查集就是多个并查集,
- 然后一个set所代表的的关系不仅一种,
- 所以对每个元素要用多重表示,在这个题目里
- 就是+i*n来区分每个元素和另一些元素的不同关系
- */
- #include<iostream>
- #include<string>
- #include<algorithm>
- #include<cstdio>
- #include<cstring>
- #include<cmath>
-
- using namespace std;
-
- const int maxn = 200000+10;
- int par[maxn];
-
- int dsu(int x){
- return x==par[x]?x:(par[x]=dsu(par[x]));
- }
- bool same(int x,int y){
- return dsu(x)==dsu(y);
- }
- int main(){
- int n,m;
- scanf("%d%d",&n,&m);
- for(int i=0;i<=3*n;i++){
- par[i]=i;
- }
- int cnt=0;
- int x,y,ty;
- while(m--){
- scanf("%d%d%d",&ty,&x,&y);
- if(x<=0||x>n||y<=0||y>n){
- cnt++;
- continue;
- }
- if(ty==1){
- if(same(x,y+n)||same(y,x+n)){
- cnt++;
- }else{
- for(int i=0;i<3;i++){
- int fx=dsu(x+i*n);
- int fy=dsu(y+i*n);
- par[fx]=fy;
- }
- }
- }else{
- if(x==y||same(x,y)||same(y,x+n)){
- cnt++;
- }else{
- for(int i=0;i<3;i++){
- int fx=dsu(x+i*n);
- int fy=dsu(y+(i+1)%3*n);
- par[fx]=fy;
- }
- }
- }
- }
- printf("%d\n",cnt);
- return 0;
- }