求调,详细注释,思路和题解差不多
查看原帖
求调,详细注释,思路和题解差不多
637788
kimi0705楼主2024/9/2 18:47

详细注释,思路和题解差不多

#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;
}

2024/9/2 18:47
加载中...