详细注释,思路和题解差不多
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5e5;
int parent[MAXN]; // 记录每个节点的父节点
// 初始化并查集
void initUnionFind(int n) {
for (int i = 0; i < n; ++i) {
parent[i] = i; // 每个节点的父节点初始化为自己
}
}
// 查找操作,带路径压缩
int find(int x) {
if (parent[x] != x)
parent[x] = find(parent[x]); // 路径压缩
return parent[x];
}
// 合并操作
void unionSets(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
parent[rootY] = rootX; // 合并 rootY 到 rootX
}
}
int main() {
int n;
scanf("%d", &n);
vector<pair<int, int>> segments(n); // 存储线段
for (int i = 0; i < n; ++i) {
int l, r;
scanf("%d %d", &l, &r);
segments[i] = {l, r};
}
// 按线段的起始点进行排序
sort(segments.begin(), segments.end());
initUnionFind(n); // 初始化并查集
set<pair<int, int>> activeSegments; // 活跃线段集合 (结束点, 索引)
for (int i = 0; i < n; ++i) {
auto [l, r] = segments[i];
// 移除所有结束点在当前线段起始点之前的线段
while (!activeSegments.empty() && activeSegments.begin()->first <= l) {
activeSegments.erase(activeSegments.begin());
}
// 检查与当前线段相交的活跃线段
for (auto &[end, index] : activeSegments) {
if (end > l) { // 如果线段相交
if (find(i) == find(index)) { // 检查是否已经在同一个连通分量中
printf("NO\n");
return 0;
}
unionSets(i, index);
cout << i << " - " << index << '\n';
}
}
// 将当前线段添加到活跃集合中
activeSegments.insert({r, i});
}
// 检查是否有环和连通性
int root = find(0); // 获取第一个线段的根节点
for (int i = 1; i < n; ++i) {
if (find(i) != root) { // 如果有线段不在同一个连通分量中
printf("NO\n");
return 0;
}
}
// 如果没有发现环且所有线段在一个连通分量中
printf("YES\n");
return 0;
}