训练题解_P8654合根植物
关键词
并查集、集合合并、查询集合归属
思路
本题是并查集的经典应用,主要涉及两个核心操作:集合合并和查询元素是否在同一集合。并查集是一种用于处理不相交集合的合并与查询问题的数据结构,通过维护每个元素的父节点,来表示元素所属的集合。在本题中,我们需要根据输入的操作类型(合并或查询),对元素进行相应的处理。
步骤
- 初始化并查集:创建一个数组
parent
,用于存储每个元素的父节点,初始时每个元素的父节点是它自身,表示每个元素都属于一个独立的集合。 - 查找元素所在集合的根节点:实现
find
函数,用于查找一个元素所在集合的根节点。在查找过程中,可以使用路径压缩优化,将元素直接连接到根节点,减少后续查找的时间复杂度。 - 合并两个集合:实现
unite
函数,将两个元素所在的集合合并为一个集合。具体做法是找到两个元素所在集合的根节点,然后将其中一个根节点的父节点设置为另一个根节点。 - 处理输入操作:根据输入的操作类型(\(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)\)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理