我们需要枚举区间 看是否有一个点被覆盖m次 暴力的枚举肯定是不行的 那么可以采用尺取法
首先根据长度对n个区间进行升序排序 假设当前枚举的为 标号L~R的区间 我们用线段树维护最大值 看是否有一个位置被覆盖了m次 如果有 更新答案 接着我们压缩L~R区间 (因为我们要最小值 当L越大 差值越小) 也就是在 有一个位置被覆盖次数>=m时让L最大 更新完这个答案后 在向后扩展R就行了
尺取法的一般步骤是:
1.初始时 L=R=0
2.R向右扩展知道满足条件
3.在第二步的基础上 L向右扩展 并保证满足条件
4.此时得到了 一个以R为右端点的最小可行区间 更新答案
5.重复上述过程
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+100;
int has[N*2],tot;
int mx[N<<4],lazy[N<<4];
struct node{
int l,r,len;
bool operator < (const node &a){
return len<a.len;
}
}p[N];
int get(int x){
return lower_bound(has+1,has+1+tot,x)-has;
}
void pushup(int id){
mx[id]=max(mx[id<<1],mx[id<<1|1]);
}
void pushdown(int id){
if(lazy[id]){
lazy[id<<1]+=lazy[id];
lazy[id<<1|1]+=lazy[id];
mx[id<<1]+=lazy[id];
mx[id<<1|1]+=lazy[id];
lazy[id]=0;
return;
}
}
void update(int id,int l,int r,int L,int R,int v){
if(L<=l&&R>=r){
mx[id]+=v;
lazy[id]+=v;
return;
}
int mid = l+r>>1;
pushdown(id);
if(L<=mid) update(id<<1,l,mid,L,R,v);
if(R>mid) update(id<<1|1,mid+1,r,L,R,v);
pushup(id);
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
scanf("%d%d",&p[i].l,&p[i].r),p[i].len=p[i].r-p[i].l,has[++tot]=p[i].l,has[++tot]=p[i].r;
sort(p+1,p+1+n);
sort(has+1,has+1+tot);
tot=unique(has+1,has+1+tot)-has;
for(int i = 1; i <= n; i++)
p[i].l=get(p[i].l),p[i].r=get(p[i].r);
int L=1,ans=2e9;
for(int i = 1; i <= n; i++){
update(1,1,tot,p[i].l,p[i].r,1);
while(mx[1]>=m&&L<=i){
ans=min(ans,p[i].len-p[L].len);
update(1,1,tot,p[L].l,p[L].r,-1);
L++;
}
}
printf("%d\n",ans==2e9?-1:ans);
return 0;
}