区间覆盖(重叠)问题
区间覆盖总点数(区间合并)
P2082 区间覆盖(加强版)
题目描述
已知有\(N\)个区间,每个区间的范围是\([si,ti]\),请求出区间覆盖后的总长。
输入格式
N s1 t1 s2 t2 …… sn tn
输出格式
共一行,一个正整数,为覆盖后的区间总长。
输入
3
1 100000
200001 1000000
100000000 100000001
输出
900002
说明/提示
【数据范围】
对于\(40\%\)的数据 \(N≤1000,0<Si<Ti≤10000\)
对于\(100\%\)的数据 \(N≤10^5,0<Si<Ti≤10^{17}\),且为整数
- 时间复杂度:\((nlogn)\)
代码
//区间覆盖,求区间的覆盖点数
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
using LL=long long;
pair<LL,LL> a[100005];
int n;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].fi,&a[i].se);
sort(a+1,a+1+n);
LL res=0,s=a[1].fi,e=a[1].se;
for(int i=2;i<=n;i++)
if(a[i].fi<=e)e=max(e,a[i].se);
else
{
res+=e-s+1;
s=a[i].fi,e=a[i].se;
}
res+=e-s+1;
printf("%lld",res);
return 0;
}
最少覆盖区间区间数
907. 区间覆盖
给定 \(N\) 个闭区间 \([a_i,b_i]\) 以及一个线段区间 \([s,t]\),请你选择尽量少的区间,将指定线段区间完全覆盖。
输出最少区间数,如果无法完全覆盖则输出 \(−1\)。
输入格式
第一行包含两个整数 \(s\) 和 \(t\),表示给定线段区间的两个端点。
第二行包含整数 \(N\),表示给定区间数。
接下来 \(N\) 行,每行包含两个整数 \(a_i,b_i\),表示一个区间的两个端点。
输出格式
输出一个整数,表示所需最少区间数。
如果无解,则输出 \(−1\)。
数据范围
\(1≤N≤10^5\),
\(−10^9≤a_i≤b_i≤10^9\),
\(−10^9≤s≤t≤10^9\)
输入样例:
1 5
3
-1 3
2 4
3 5
输出样例:
2
- 时间复杂度:\(O(nlogn)\)
代码
//区间覆盖,求最少覆盖区间数
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
int n,s,t;
pair<int,int> a[100005];
int main()
{
scanf("%d%d%d",&s,&t,&n);
for(int i=1;i<=n;i++)scanf("%d%d",&a[i].fi,&a[i].se);
sort(a+1,a+1+n);
int res=0,r=-2e9;
for(int i=1;i<=n;i++)
{
int j=i;
r=-2e9;
while(j<=n&&a[j].fi<=s)
{
r=max(r,a[j].se);
j++;
}
res++;
if(r<s||r>=t)break;
s=r;
i=j-1;
}
printf("%d",r>=t?res:-1);
return 0;
}
覆盖区间的最少点数(不重叠的区间数)
905. 区间选点
给定 \(N\) 个闭区间 \([a_i,b_i]\),请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。
输出选择的点的最小数量。
位于区间端点上的点也算作区间内。
输入格式
第一行包含整数 \(N\),表示区间数。
接下来 \(N\) 行,每行包含两个整数 \(a_i,b_i\),表示一个区间的两个端点。
输出格式
输出一个整数,表示所需的点的最小数量。
数据范围
\(1≤N≤10^5\),
\(−10^9≤a_i≤b_i≤10^9\)
输入样例:
3
-1 1
2 4
3 5
输出样例:
2
908. 最大不相交区间数量
给定 \(N\) 个闭区间 \([a_i,b_i]\),请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。
输出可选取区间的最大数量。
输入格式
第一行包含整数 \(N\),表示区间数。
接下来 \(N\) 行,每行包含两个整数 \(a_i,b_i\),表示一个区间的两个端点。
输出格式
输出一个整数,表示可选取区间的最大数量。
数据范围
\(1≤N≤10^5\),
\(−10^9≤a_i≤b_i≤10^9\)
输入样例:
3
-1 1
2 4
3 5
输出样例:
2
- 时间复杂度:\(O(nlogn)\)
代码
//区间不覆盖,覆盖所有区间的最少点数
#include<bits/stdc++.h>
using namespace std;
int n;
struct Range
{
int l,r;
bool operator<(const Range &o)
{
return r<o.r;
}
}a[100005];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d",&a[i].l,&a[i].r);
sort(a+1,a+1+n);
int res=0,t=-2e9;
for(int i=1;i<=n;i++)
if(a[i].l>t)
{
res++;
t=a[i].r;
}
printf("%d",res);
return 0;
}
最少内部不相交区间组数
906. 区间分组
给定 \(N\) 个闭区间 \([a_i,b_i]\),请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。
输出最小组数。
输入格式
第一行包含整数 \(N\),表示区间数。
接下来 \(N\) 行,每行包含两个整数 \(a_i,b_i\),表示一个区间的两个端点。
输出格式
输出一个整数,表示最小组数。
数据范围
\(1≤N≤10^5\),
\(−10^9≤a_i≤b_i≤10^9\)
输入样例:
3
-1 1
2 4
3 5
输出样例:
2
- 时间复杂度:\(O(nlogn)\)
代码
//区间分组,组内区间互不相交的最少组数
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
int n;
pair<int,int> a[100005];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d",&a[i].fi,&a[i].se);
sort(a+1,a+1+n);
priority_queue<int,vector<int>,greater<int> > q;
for(int i=1;i<=n;i++)
{
auto t=a[i];
if(q.empty()||q.top()>=t.fi)q.push(t.se);
else
{
q.pop();
q.push(t.se);
}
}
printf("%d",q.size());
return 0;
}
最多重叠区间数
#34. 「LYOI2016 Summer」Doges
题目描述
在一个遥远的地方,住着 \(n\) 只 Doge,它们分别被编号为 \(1\) 到 \(n\) 之间的正整数。
有一天,一个叫 Jrisme 的人来到这里,进行了一些「虐狗」行为。具体的,Jrisme 每次会虐编号连续的一些 Doge。现给出每次虐狗的区间,求最幸运(被虐次数最多)Doge 被虐了多少次。
输入格式
第一行两个正整数 \(n\) 和 \(m\),分别表示 Doge 的数量和 Jrisme 的虐狗次数。
从第二行开始,之后的 \(m\) 行,第 \(i\) 行为两个正整数 \(l_i\)、\(r_i\),表示 Jrisme 虐了编号在区间 \([l_i,r_i]\) 内的 Doge。
输出格式
一行一个整数,最幸运的 Doge 的被虐次数。
输入样例
10 3
1 4
4 7
4 9
输出样例
3
数据范围与提示
对于 \(30\%\) 的数据,\(n,m\leq 1000\);
对于另外 \(20\%\) 的数据,\(n\leq 10^6\);
对于另外 \(20\%\) 的数据,\(n\leq 5\times 10^5\);
对于另外 \(20\%\) 的数据,\(m\leq 5000\);
对于 \(100\%\) 的数据,\(1\leq n\leq 10^9\),\(1\leq m\leq 200000\),\(1\leq l_i \leq r_i \leq n\)。
- 时间复杂度:\(O(nlogn)\)
代码
//区间重叠,最多重叠区间数
#include<bits/stdc++.h>
using namespace std;
int n,m;
struct Range
{
int x,flag;
bool operator<(const Range &o)
{
if(x!=o.x)return x<o.x;
return o.flag<flag;
}
}a[400005];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i].x,&a[i+m].x);
a[i].flag=1,a[i+m].flag=-1;
}
sort(a+1,a+1+2*m);
int res=0,t=0;
for(int i=1;i<=2*m;i++)
t+=a[i].flag,res=max(res,t);
printf("%d",res);
return 0;
}