[模板] 并查集 - 一般并查集 (洛谷 P3367 并查集)

P3367 【模板】并查集

P3367 【模板】并查集 - 洛谷

题目描述

  如题,现在有一个并查集,你需要完成合并和查询操作。

输入格式

  第一行包含两个整数N,M,表示共有N个元素和M个操作。接下来M行,每行包含三个整数Zi,Xi,Yi

  • Zi=1时,将XiYi所在的集合合并。

  • Zi=2时,输出XiYi是否在同一集合内,是的输出Y;否则输出N

输出格式

  对于每一个Zi=2的操作,都有一行输出,每行包含一个大写字母,为Y或者N

输入输出样例

输入输出
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
N
Y
N
Y

说明/提示

  对于30%的数据,N≤10M≤20

  对于70%的数据,N≤100M≤1E3

  对于100%的数据,1≤N≤1E41≤M≤2×1E5

代码

  并查集没什么好讲的,解释都在注释里了

//c++ --std=c++99

#include <cstdio>

struct ufsets_elem{ //并查集元素
	ufsets_elem *root;
	ufsets_elem(){
		root = this;
	}
	ufsets_elem *find(){
		return root == this ? root : root = root->find(); //路径压缩
	}
};

struct ufsets{	//并查集
protected:
	int ufsets_num;			  //独立集合数量
	ufsets_elem *ufsets_base; //并查集数组
public:
	explicit ufsets(const int &n){
		ufsets_base = new ufsets_elem[n + 1]();
		ufsets_num = n;
	}
	bool catenate(const int &a, const int &b){ //合并a,b集合,返回false则说明两元素已是同一集合
		if (ufsets_base[a].find() != ufsets_base[b].find()){ //若a,b不在同一集合则合并b至a
			--ufsets_num;
			ufsets_base[b].root->root = ufsets_base[a].root;
			return true;
		}
		return false;
	}
	bool relative(const int &a, const int &b){ //查询是否在同一个集合中,是则返回true
		return ufsets_base[a].find() == ufsets_base[b].find();
	};
	int size(){//独立集合数量
		return ufsets_num;
	}
	~ufsets(){
		delete[] ufsets_base;
	}
};

int main(){
	int n, m;
	int tmp1, tmp2, tmp3;
	scanf("%d%d", &n, &m);
	ufsets u(n);
	for (int i = 1; i <= m; ++i){
		scanf("%d%d%d", &tmp1, &tmp2, &tmp3);
		switch (tmp1){
		case 1:
			u.catenate(tmp2, tmp3); //将tmp3所在集加入到tmp2中
		break;
		case 2:
			printf("%c\n", u.relative(tmp2, tmp3) ? 'Y' : 'N');
		break;
		}
	}
	return 0;
}
//java
import java.util.*;
import java.math.*;

class ufsets_elem{ //并查集元素
	public ufsets_elem root;
	ufsets_elem(){
		root = this;
	}
	ufsets_elem find(){
		return root == this ? root : (root = root.find()); //路径压缩
	}
};

class ufsets{	//并查集,依赖于class ufsets_elem
	int ufsets_num;			  //独立集合数量
	ufsets_elem[] ufsets_base; //并查集数组
	ufsets(final int n){
		ufsets_base = new ufsets_elem[n + 1];
		for(int i=1;i<=n;i++)//ufsets_base[0]用不到
			ufsets_base[i]=new ufsets_elem();
		ufsets_num = n;
	}
	boolean catenate(final int a, final int b){ //合并a,b集合,返回false则说明两元素已是同一集合
		if (ufsets_base[a].find() != ufsets_base[b].find()){ //若a,b不在同一集合则合并b至a
			--ufsets_num;
			ufsets_base[b].root.root = ufsets_base[a].root;//b更改的是其父节点的<root>
			return true;
		}
		return false;
	}
	boolean relative(final int a, final int b){ //查询是否在同一个集合中,是则返回true
		return ufsets_base[a].find() == ufsets_base[b].find();
	};
	int size(){//独立集合数量
		return ufsets_num;
	}
};

public class Main {
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt(), m=sc.nextInt();
		int tmp1, tmp2, tmp3;
		ufsets u=new ufsets(n);
		for (int i = 1; i <= m; ++i){
			tmp1=sc.nextInt();tmp2=sc.nextInt();tmp3=sc.nextInt();
			switch (tmp1){
			case 1:
				u.catenate(tmp2, tmp3); //将tmp3所在集加入到tmp2中
			break;
			case 2:
				System.out.print((u.relative(tmp2, tmp3) ? 'Y' : 'N')+"\n");
			break;
			}
		}
	}
}


  同一套代码java慢好多,枯了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值