https://www.luogu.org/problem/show?pid=1955
并查集+离散化。
先执行所有x=y问题,即合并x和y。
再依次执行所有x!=y问题,即查询x和y是否处于同一集合。如果是,则有x=y且x!=y,不满足条件。
如果所有的x!=y都得到满足,这组数据就可以满足。
注意到i,j范围为[1,1e9],并查集数组开不了这么大的范围。又注意到n范围只有[1,1e5],考虑离散化。
先读入所有出现的数字,存到一个数组,然后排序并去重。之后操作用到的数字都在这个数组进行二分查找。
时间复杂度O(nlogn)。
注意的坑:
- 最多有n个操作,每个操作有两个数字,所以并查集的大小应该是n*2。
#include <algorithm> #include <cstring> #include <iostream> #include <vector> #define maxn 100005 * 2 // n个操作,每个操作两个数,最多出现n*2个数 using namespace std; typedef unsigned long long ullint; namespace djs { int parent[maxn]; inline void init() { for (int i = 0; i < maxn; i++) parent[i] = -1; } inline int find(int x) { if (parent[x] < 0) return x; else return parent[x] = find(parent[x]); } inline void merge(int x, int y) { x = find(x); y = find(y); if (x == y) return; else { //令x为rank更大的,即parent值更小的 if (parent[x] > parent[y]) swap(x, y); parent[x] += parent[y]; parent[y] = x; } } inline bool is_related(int x, int y) { return find(x) == find(y); } } typedef pair<ullint, ullint> query; vector<query> q, m; // 暂存查询与合并操作 vector<ullint> data; // 存储读入的所有数据 vector<ullint>::iterator unique_end; // 去重后的数据的尾后迭代器 inline int get_pos(ullint v) // 二分查找v在data所处的位置 { return lower_bound(data.begin(), unique_end, v) - data.begin(); } int main() { ios::sync_with_stdio(false); int t; cin >> t; while (t--) { int n; cin >> n; djs::init(); m.clear(); q.clear(); data.clear(); ullint a, b, c; for (int i = 0; i < n; i++) { cin >> a >> b >> c; data.push_back(a); data.push_back(b); switch (c) { case 1: m.push_back(make_pair(a, b)); break; case 0: q.push_back(make_pair(a, b)); break; } } //离散化 sort(data.begin(), data.end()); unique_end = unique(data.begin(), data.end()); //合并 for (int i = 0; i < m.size(); i++) djs::merge(get_pos(m[i].first), get_pos(m[i].second)); //查询 bool yes = true; for (int i = 0; i < q.size(); i++) { if (djs::is_related(get_pos(q[i].first), get_pos(q[i].second))) { yes = false; break; } } if (yes) cout << "YES" << endl; else cout << "NO" << endl; } return 0; }