题目
传送门
P1955 [NOI2015] 程序自动分析 - 洛谷 | 计算机科学教育新生态https://www.luogu.com.cn/problem/P1955
思路
主要用到的知识是并查集 (如何实现并查集,这里不赘述了)
若 xi = xj,则合并它们所在的集合。若 xi != xj,则 i 和 j 若在同一个集合,则 false
但是用最简单的并查集并不能 AC 本题,因为 i、j 相当大,数组承受不了
需要做离散化。用哈希表做离散化比较方便
细节
需要在处理完所有 = 情况时才能处理 != 情况,否则 != 会漏判后面再合并的情况
虽然每组测试数据是 n 行,但是每行可能有两个数据需要做离散化,所以 N 要开 2*5^10+
输入数据有多组,记得重置共享资源,或者干脆设为局部变量
更多细节见代码
代码
#include <unordered_map>
#include <vector>
#include <iostream>
using namespace std;
typedef pair<int, int> PII;
const int N = 200005;
int f[N], t, n;
int find(int a) { return f[a] == a ? a : f[a] = find(f[a]); } //并查集模板,没什么好说的
int main()
{ios::sync_with_stdio(false); //输入量不小,最好采用较快的 I/O 方式cin.tie(0);cin >> t;while (t--){cin >> n;int sz = 2 * n, cnt = 0; //注意 2*n //cnt 用于分配离散化的下标unordered_map<int, int> idx; //idx 用于离散化,通过 i、j 映射到它们离散化后的下标。操作全基于离散化后的下标vector<PII> v; //不等于的式子需要先存下来,后面再处理bool flag = true;for (int i = 0; i < sz; i++) f[i] = i; //重置共享资源while (n--){int x, y, z;cin >> x >> y >> z;if (idx.count(x) == 0) idx[x] = cnt++; //没分配过下标的,新分配if (idx.count(y) == 0) idx[y] = cnt++;if (z) f[find(idx[x])] = find(idx[y]); //并查集模板,没什么好说的else v.push_back({ idx[x], idx[y] }); //存离散化后的下标}for (auto& x : v)if (find(x.first) == find(x.second)){ flag = false; break; }cout << (flag ? "YES\n" : "NO\n");}return 0;
}