abc235_e MST + 1 题解
MST + 1
题意
给定一个
有
对于每组询问,请你判断:对于加入这条边后的图,问其最小生成树中是否包含了这条边,如果是,输出Yes
,否则输出No
。
保证题目给定的原图边权两两不同,保证加入的边的边权与原图中的任意一条边都不相同。
每组询问是独立的,互相不产生影响。
思路
使用克鲁斯卡尔算法。
首先这题数据范围不小,直接模拟是肯定不行的。
我们知道,克鲁斯卡尔算法是按边权从小到大排序,然后用并查集判断这条边是否有必要加入最小生成树,而每条边能否加入最小生成树中,取决于那些边权比这条边小的边。
同理,每组询问中给出的边,只取决于那些原图中的边权比其小的边。
那么就可以推出一种做法:
- 首先将每个询问给出的边和原图中的边共同记录下来。
- 给所有边按边权从小到大排序。
- 就像普通的最小生成树一样处理,只是那些询问中的边只需要判断、不需要加入图中。
最后输出即可。
Code
点击查看代码
#include <iostream> #include <algorithm> using namespace std; const int M = 4e5 + 10; // 记得开两倍空间 struct Node { int x, y, z, f; // 记录每条边的边权等,f 用来记录是第几次询问的边 bool operator < (const Node &i) const { return z < i.z; } } a[M]; int n, m, q, ans[M], f[M]; int Find (int x) { return (f[x] ? f[x] = Find(f[x]) : x); } int main(){ ios::sync_with_stdio(0), cin.tie(0); cin >> n >> m >> q; for (int i = 1; i <= m; i++) { cin >> a[i].x >> a[i].y >> a[i].z; } for (int i = 1; i <= q; i++) { cin >> a[i + m].x >> a[i + m].y >> a[i + m].z; // 将所有边记录在一起 a[i + m].f = i; // 记录是第几次询问 } sort(a + 1, a + m + q + 1); for (int i = 1; i <= m + q; i++) { if (a[i].f) { // 如果不是原图中的边 int l = Find(a[i].x), r = Find(a[i].y); ans[a[i].f] = (l != r); // 只需判断,不需加入 } else { // 是原图中的边 // 克鲁斯卡尔算法 int l = Find(a[i].x), r = Find(a[i].y); if (l != r) { f[l] = r; } } } for (int i = 1; i <= q; i++) { // 输出 cout << (ans[i] ? "Yes" : "No") << '\n'; } return 0; }
本文作者:wnsyou の blog
本文链接:https://www.cnblogs.com/wnsyou-blog/p/17410396.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步