csp信奥赛C++高频考点专项训练之贪心算法 --【区间贪心】:区间覆盖(加强版)

题目描述
已知有 N N N 个区间,每个区间的范围是 [ s i , t i ] [s_i,t_i] [si,ti],请求出区间覆盖后的总长。
输入格式
第一行一个正整数 N N N,表示区间个数。
接下来 N N N 行,每行两个正整数,表示 s i s_i si 和 t i t_i ti。
输出格式
共一行,一个正整数,为覆盖后的区间总长。
输入输出样例 1
输入 1
3
1 100000
200001 1000000
100000000 100000001
输出 1
900002
说明/提示
对于 40 % 40 \% 40% 的数据, N ≤ 1000 N \le 1000 N≤1000, 1 ≤ s i < t i ≤ 10000 1 \le s_i < t_i \le 10000 1≤si<ti≤10000。
对于 100 % 100 \% 100% 的数据 , N ≤ 10 5 N \le 10^5 N≤105, 1 ≤ s i < t i ≤ 10 17 1 \le s_i < t_i \le 10^{17} 1≤si<ti≤1017。
思路分析
给定 N 个闭区间 [ s i , t i ] [s_i, t_i] [si,ti],需要求它们合并后的总长度。由于坐标最大可达 10 17 10^{17} 1017,不能使用数组差分,必须通过排序 + 贪心合并。
- 排序:将所有区间按左端点升序排列。这样能保证从左到右依次处理,当前区间只可能和后续区间重叠或相邻。
- 合并 :
- 初始化当前合并段的左右端点为第一个区间的
l和r。 - 遍历后续区间:
- 若当前区间的左端点
a[i].l大于 当前合并段的右端点cur,说明两段之间有空隙,无法合并。此时将当前段的长度cur - cul + 1累加到答案,并开始一个新的合并段(用当前区间重置cul和cur)。 - 否则(
a[i].l <= cur),说明有重叠或相邻(闭区间下[1,2]和[3,4]不相邻,因为3 > 2,所以用>判断不会错误合并不相邻区间),此时更新当前段的右端点cur = max(cur, a[i].r)。
- 若当前区间的左端点
- 循环结束后,将最后一段的长度加入答案。
- 初始化当前合并段的左右端点为第一个区间的
- 输出:输出累加的总长度。
时间复杂度 O ( N log N ) O(N \log N) O(NlogN),空间复杂度 O(N)。
代码实现
cpp
#include<bits/stdc++.h>
using namespace std;
typedef long long ll; // 使用ll表示long long,适应1e17的大数
const int N=1e5+10; // 最大区间数+10
int n; // 区间个数
struct node{ // 区间结构体
ll l,r; // 左端点、右端点
}a[N]; // 存储所有区间
bool cmp(node a,node b){// 按左端点升序排序的比较函数
return a.l<b.l;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].l>>a[i].r;
}
sort(a+1,a+n+1,cmp);// 将区间按左端点排序
ll cul=a[1].l;// 当前合并段的左端点(current left)
ll cur=a[1].r;// 当前合并段的右端点(current right)
ll ans=0; // 总覆盖长度
for(int i=2;i<=n;i++){// 从第二个区间开始合并
if(a[i].l>cur){// 当前区间与之前段不相连(有间隙)
ans+=(cur-cul+1);// 加上之前段的长度
cul=a[i].l; // 开启新段:左端点为当前区间左端点
cur=a[i].r; // 右端点为当前区间右端点
}else{ // 可以合并
cur=max(cur,a[i].r);// 扩展当前段的右端点
}
}
ans+=(cur-cul+1); // 加上最后一段的长度
cout<<ans; // 输出结果
return 0;
}
功能分析
- 输入处理:读取整数 N 和 N 行区间,每个区间包含左右端点。
- 排序 :调用
sort并传入自定义比较函数cmp,将所有区间按照左端点从小到大排列。 - 贪心合并 :
- 维护当前合并段的左右端点
cul和cur,初始化为第一个区间。 - 依次考察每个后续区间:
- 如果当前区间的左端点 大于
cur,说明中间有缝隙,不能合并:将当前段的长度加入答案,并重置新段为当前区间。 - 否则,说明当前区间与当前段有重叠或恰好相接。
- 如果当前区间的左端点 大于
- 循环结束后,将最后一段的长度累加。
- 维护当前合并段的左右端点
- 输出:打印最终总长度。
正确性:基于排序后贪心合并,每次遇到不重叠区间就结算当前段,保证每个点只被计数一次,最终得到所有区间覆盖的并集总长度。
边界处理:
- 当
N=1时,循环不会执行,直接输出cur-cul+1,正确。 - 当区间有包含关系时,
cur = max(cur, a[i].r)能正确扩展右端点。 - 数据范围使用
long long,避免溢出。
各种学习资料,助力大家一站式学习和提升!!!
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"########## 一站式掌握信奥赛知识! ##########";
cout<<"############# 冲刺信奥赛拿奖! #############";
cout<<"###### 课程购买后永久学习,不受限制! ######";
return 0;
}
【秘籍汇总】(完整csp信奥赛C++学习资料):
1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):
https://edu.csdn.net/lecturer/7901 点击跳转

2、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转

https://edu.csdn.net/course/detail/41081 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:
CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转
CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转
信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html 点击跳转
4、csp信奥赛冲刺一等奖有效刷题题解:
CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13125089.html 点击跳转
5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html 点击跳转
· 文末祝福 ·
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"跟着王老师一起学习信奥赛C++";
cout<<" 成就更好的自己! ";
cout<<" csp信奥赛一等奖属于你! ";
return 0;
}