2022-11-08 Acwing每日一题
本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的。同时也希望文章能够让你有所收获,与君共勉!
昨天学习了离散化,而今天来学习一下区间和并。
区间和并
给定 n 个区间 [li,ri],要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
例如:[1,3] 和 [2,6] 可以合并为一个区间 [1,6]。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含两个整数 l 和 r。
输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。
数据范围
1≤n≤100000,
−109≤li≤ri≤109
输入样例:
5
1 2
2 4
5 6
7 8
7 9
输出样例:
3
算法原理
实现区间的合并需要定义pair<int,int>segs
变量来存储区间的左右端点。
第一步要对所给区间的左端点排序,这样才能根据单调性对所有区间进行有序的合并(从左到右)。
第二步是定义一个虚拟区间[start,end]
。
第三步就是合并区间了,遍历排序后的区间,从左至右对每一个都判断当前区间的左端点segs.first
与虚拟区间[start,end]
的右端点end
的关系,如果右端点小于左端点,说明该区间不能合并,因此需要将当前的虚拟区间[start,end]
作为新的合并过的区间存储到res
(一个临时存储合并区间的pair
),如果大于左端点,则说明该区间可以合并,那么就将较大值赋值给end
。
第四步就是将最后一个合并的区间放进res
中,注意第三步的遍历时会剩下最后一个虚拟区间[start,end]
没有放进,放进去的始终是上一个区间合并过的区间,同时也要考虑如果res
中没有区间,我们也不需要把虚拟区间[start,end]
装进去,因此需要特判最后一个区间不为虚拟区间。
第五步就是将res
赋值给segs
。
代码实现
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
void merge(vector<PII> &s){
sort(s.begin(),s.end());
vector<PII> res;
int start = -2e9,end = -2e9;
for(auto item : s){
if(item.first > end){
if(start != -2e9) res.push_back({start,end});
start = item.first,end = item.second;
}
else end = max(end,item.second);
}
if(start != -2e9) res.push_back({start,end});
segss = res;
}
int main(){
vector<PII> s;
int n;
cin >> n;
for(int i=0; i< n ; ++i){
int l,r;
cin >> l >> r;
s.push_back({l,r});
}
merge(s);
cout << s.size() << endl;
return 0;
}