传送门:https://www.luogu.org/problem/P1712
学到了一种据说是普及组的思想--取尺法。(具体是啥忘了。。。。。。好像是一种很优秀的枚举方法。
这道题就是先把区间按照区间长度排个序 (好像有了单调性好多问题就很简单了
然后把区间计算到答案里 (何为计算到贡献里? 就是这个区间里的点被覆盖次数++
当发现有一个点出现到达m次然后更新答案
再把之前加入的区间贡献减去(类似队列..........为什么能直接把贡献减去呢?因为没用了.......后面的区间长度只会更长,而它却比别人都短......所以说没用了对吧
然后这道题离散化一下,用线段树维护被覆盖次数的最大值就可以了

#include<cstdio>
#include<algorithm>
#define R register
#define ls(p) p<<1
#define rs(p) p<<1|1
using namespace std;
int n,m,lsh[1001000],mx,ans=1e9;
struct qqq{
int l,r,len;
inline bool operator <(const qqq i) const{
return len<i.len;
}
}ln[500100];
struct ddd{
int l,r,lazy,cnt;
}t[4001000];
inline void down(int p){
if(t[p].lazy){
t[ls(p)].cnt+=t[p].lazy;
t[ls(p)].lazy+=t[p].lazy;
t[rs(p)].cnt+=t[p].lazy;
t[rs(p)].lazy+=t[p].lazy;
t[p].lazy=0;
}
}
inline void update(int p){
t[p].cnt=max(t[ls(p)].cnt,t[rs(p)].cnt);
return;
}
inline void build(int p,int l,int r){
t[p].l=l;t[p].r=r;
if(l==r) return;
int mid=(l+r)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
return;
}
inline void change(int p,int l,int r,int v){
if(t[p].l>=l&&t[p].r<=r){
t[p].cnt+=v;
t[p].lazy+=v;
return;
}
down(p);
int mid=(t[p].l+t[p].r)>>1;
if(mid>=l) change(ls(p),l,r,v);
if(mid< r) change(rs(p),l,r,v);
update(p);
}
int main (){
scanf("%d%d",&n,&m);
for(R int i=1;i<=n;i++){
scanf("%d%d",&ln[i].l,&ln[i].r);
lsh[++mx]=ln[i].l;lsh[++mx]=ln[i].r;
ln[i].len=ln[i].r-ln[i].l;
}
sort(lsh+1,lsh+1+mx);
mx=unique(lsh+1,lsh+1+mx)-lsh-1;
build(1,1,mx);
for(R int i=1;i<=n;i++){
ln[i].l=lower_bound(lsh+1,lsh+1+mx,ln[i].l)-lsh;
ln[i].r=lower_bound(lsh+1,lsh+1+mx,ln[i].r)-lsh;
}
sort(ln+1,ln+1+n);
int li=0;
for(R int i=1;i<=n;i++){
change(1,ln[i].l,ln[i].r,1);
if(t[1].cnt==m){
while(t[1].cnt==m){
li++;
change(1,ln[li].l,ln[li].r,-1);
}
ans=min(ans,ln[i].len-ln[li].len);
}
}
printf("%d\n",ans==1e9?-1:ans);
return 0;
}
