并查集模板

题目介绍:洛谷 P3367 并查集模板

两个数组 s[N] ,height[N] :

    s[N] 用来存储哪些结点连通 ( 1 -> 2 == s[2] = s[1],先后顺序很重要

    *height[N]用来表示树的高度,用来路径压缩

        1*比如说 1 和 2 连通,2 和 3 连通,4 和 5连通 

        就会有:height [ 1 ] = 1 , height [ 2 ] = 0 , height [ 3 ] = 0    ;    height [ 4 ] = 1 , height [ 5 ] = 0;

        s [ 1 ] = 1 , s [ 2 ] = s [ 1 ]  = 1 , s [ 3 ] = s [ 2 ] = 1     ;    s [ 4 ] = 4 , s [ 5 ] = 4;

        *如果再加一个 1 和 4 连通 (因为 1 和 4 的高度一样,所以把后面的树接到前面的树上

         就会有height [ 1 ] = 2 , height [ 2 ] = 0 , height [ 3 ] = 0    ;    height [ 4 ] = 1 , height [ 5 ] = 0;

         s [ 1 ] = 1 , s [ 2 ] = s [ 1 ]  = 1 , s [ 3 ] = s [ 2 ] = 1     ;    s [ 4 ] = s [ 1 ] = 1 , s [ 5 ] = 4;

        2*比如说 1 和 2 连通,3 和 4 连通,2 和 3 连通,5 和 6 连通

        就会有height [ 1 ] = 2 , height [ 2 ] = 0 , height [ 3 ] = 1 , height [ 4 ] = 0 , height [ 5 ] = 1 , height [ 6 ] = 0 ;

         s [ 1 ] = 1 , s [ 2 ] = s [ 1 ]  = 1 , s [ 4 ] = s [ 3 ] = 3 , s [ 3 ] = s [ 2 ] = 1 , s [ 6 ] = s [ 5 ] = 5 ;

        *如果再加一个 1 和 5 连通 (因为 height [ 1 ] > height [ 5 ] , 所以5 和 1 连通是一样的 ,都是矮树接到高树上

        就会有height [ 1 ] = 2 , height [ 2 ] = 0 , height [ 3 ] = 1 , height [ 4 ] = 0 , height [ 5 ] = 1 , height [ 6 ] = 0 ;

         s [ 1 ] = 1 , s [ 2 ] = s [ 1 ]  = 1 , s [ 4 ] = s [ 3 ] = 3 , s [ 3 ] = s [ 2 ] = 1 , s [ 6 ] = s [ 5 ] = 5  , s [ 5 ] = s [ 1 ] = 1 ;

inte_set( )函数 对两个数组初始化

        *在最初时,所以的结点都互不相关,所以s[i]都等于本身 ;而height[N]只要都相等就好;

find_set( x )函数 在构成的集合中寻找 x 的根结点

        *都找到最前面的那个结点,故如果两个数在一个集合中,那么他们搜索到的根结点是相同的( 所以可以用find_set ( a ) == find_set ( b ) 来判断他们在不在一个集合中

 union_set( x , y )函数 将 x , y 合并(就是 s[ x ] = s [ y ] 的操作函数

        *首先都寻找到 x , y 的根,判断是否相等,

        相等则把 y 树接在 x 上

        不相等则把小的树接在大的树上(路径压缩,用树构成集合

        能索引到同一个根,则说明他们是在一个集合内的

#include<bits/stdc++.h>
using namespace std;
int s[20000]={0}; //s[3] = 1,s[2] = 1;表示 1 和 2 连通,2 和 3 连通;
int height[20000]={0};  //树的高度 
//int vec[1000]={0};
void inte_set(){						//初始化 
    for(int i = 1;i <= 20000;i ++){ s[i]=i,height[i]=0 ;}
} 
int find_set(int n){					//查找 **路径压缩
	if(n!=s[n]) s[n]=find_set(s[n]);
	//vec[n]+=vec[s[n]];      //权
	return s[n];
}
void union_set(int x,int y){				//合并 
	x=find_set(x);y=find_set(y);
	if(height[x]==height[y]){
		height[x]++;
		s[y]=x;
	}
	else if(height[x] > height[y]) s[y]=x;
	else s[x]=y;
}
int main(void){
    inte_set();
    int N,M;cin >> N >> M;
    for(int i = 0;i < M;i ++){
        int z,x,y;cin >> z >> x >> y ;
        if(z == 1) union_set(x , y) ;
        else { if(find_set(x) == find_set(y)) cout << 'Y' << endl ;else cout << 'N' << endl ;}
    }
    // cout << s[1] << " " << s[2] << " " << s[3] << " " << s[4] << " " << s[5] << " " << s[6] << endl ;
    // cout << height[1] << " " << height[2] << " " <<  height[3] << " " <<  height[4] << " " << height[5] << " " << height[6] << endl ;
    return 0;
}

计算有多少个集合:

for(int i = 1;i < n;i ++) if(s[i] == i) sum ++;

如果有负数 , 你可以将最小的负数当做0来处理

如果负数太大 , 可以进行离散化
//低配版
int find(int n){
    if(n != _vector[n]) _vector[n] = find(_vector[n]);
    return _vector[n];
}
signed main(){
    int x = find(n1), y = find(n2);
    if(x != y) _vector[x] = y;
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值