训练题解_P8654合根植物

关键词

并查集、集合合并、查询集合归属

思路

本题是并查集的经典应用,主要涉及两个核心操作:集合合并和查询元素是否在同一集合。并查集是一种用于处理不相交集合的合并与查询问题的数据结构,通过维护每个元素的父节点,来表示元素所属的集合。在本题中,我们需要根据输入的操作类型(合并或查询),对元素进行相应的处理。

步骤

  1. 初始化并查集:创建一个数组 parent,用于存储每个元素的父节点,初始时每个元素的父节点是它自身,表示每个元素都属于一个独立的集合。
  2. 查找元素所在集合的根节点:实现 find 函数,用于查找一个元素所在集合的根节点。在查找过程中,可以使用路径压缩优化,将元素直接连接到根节点,减少后续查找的时间复杂度。
  3. 合并两个集合:实现 unite 函数,将两个元素所在的集合合并为一个集合。具体做法是找到两个元素所在集合的根节点,然后将其中一个根节点的父节点设置为另一个根节点。
  4. 处理输入操作:根据输入的操作类型(\(Z_i = 1\) 表示合并,\(Z_i = 2\) 表示查询),调用相应的函数进行处理。对于查询操作,判断两个元素是否在同一集合内,并输出结果。

CPP \(Code\)

#include<bits/stdc++.h>
using namespace std;
long long m,n,k,a,b,ans;
int f[1000005];
int find(int x)
{
if(f[x]!=x)f[x]=find(f[x]);
return f[x];
}
// 快读整数模板,支持不同整数类型
template <typename T>
inline T read() {
T x = 0;
int f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
// 快读 double 类型
inline double readDouble() {
double x = 0, base = 0.1;
int f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + (ch ^ 48);
ch = getchar();
}
if (ch == '.') {
ch = getchar();
while (isdigit(ch)) {
x += base * (ch ^ 48);
base /= 10;
ch = getchar();
}
}
return x * f;
}
// 快写整数模板,支持不同整数类型
template <typename T>
inline void write(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
// 快写 double 类型,可指定保留小数位数
inline void writeDouble(double x, int precision = 6) {
if (x < 0) {
putchar('-');
x = -x;
}
long long integerPart = static_cast<long long>(x);
write(integerPart);
putchar('.');
double decimalPart = x - integerPart;
for (int i = 0; i < precision; ++i) {
decimalPart *= 10;
int digit = static_cast<int>(decimalPart);
putchar(digit + '0');
decimalPart -= digit;
}
}
int main() {
// 使用 read 函数读取数据( int intValue = read<int>();)
int m=read<int>();
int n=read<int>();
int k=read<int>();
for(int i=1;i<=m*n;i++)f[i]=i;
for(int i=1;i<=k;i++)
{
int a=read<int>();
int b=read<int>();
f[find(a)]=find(b),f[find(b)]=find(a);
}
for(int i=1;i<=m*n;i++){
if(f[i]==i)ans++;
}
write(ans);
// 使用 write 或 writeDouble 函数输出结果(write(intValue);)
return 0;
}

复杂度分析

  • 时间复杂度:初始化并查集的时间复杂度为 \(O(N)\),每次查找和合并操作的平均时间复杂度接近 \(O(1)\),因此总的时间复杂度为 \(O(N + M)\)
  • 空间复杂度:主要使用了一个数组来存储每个元素的父节点,空间复杂度为 \(O(N)\)
posted @   半眠七点不想睡  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
/* 设置动态特效 */
点击右上角即可分享
微信分享提示