题目:
题解:先按照左端点排序,然后以此考虑每个区间,设一个token变量,首先把所有左端点小于等于token+1的区间的右端点加入小根堆,然后token+1,选择右端点最小的可选区间。 如果队列空了,说明这已经不是token+1能解决的了,应该直接token=L,然后差不多做完了。主要考察的是贪心,需要一些码力来实现想法。复杂度:O(nlogn)
(你可以搜到优快云里有个不断把区间左端点更新成now+1,然后重新push进优先队列里的做法,能过纯属是因为数据太水了,但凡构造1e5个[1,1e9]的区间,都可以T飞)
代码:
#define pii pair<int, int>
signed main() {
ios_base::sync_with_stdio(0), cin.tie(0);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
int l, r;
priority_queue<int, vector<int>, greater<int>> q;
//小根堆
vector<pii> a(n);
for (auto &[l, r] : a) {
cin >> l >> r;
}
sort(a.begin(), a.end());
int ans = 0, now = 0, i = 0;
while (1) {
while (i < n and a[i].first <= now + 1) {
//保证q里的区间一定可以被now覆盖
q.push(a[i].second);
i++;
}
while (!q.empty() and q.top() <= now) //右端点都错过了 就可以淘汰了
q.pop();
if (!q.empty()) {
// now+1 选择右端点最小的区间
ans++;
now++;
q.pop();
} else {
if (i < n) {
//说明这个连通块已经处理完了,走向下一个连通块
now = a[i].first;
ans++;
i++;
}
}
if (i >= n and q.empty()) //结束条件
break;
}
cout << ans << '\n';
}
}