题目:[NOI2016]区间
思路:
将区间离散化,并按照长度从小到大排序。
考虑将区间按顺序加入,如果当加入区间 [L,R] 时,存在一个点使被覆盖次数==M,那么,可以用这条线段的长度减去覆盖这个点的第一条线段的长度更新答案,并弹出第一条线段。
用线段树维护这个过程即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 500000
#define inf (1<<30)
#define read(x) scanf("%d",&x)
struct Pair{
int x,y;
int sz;
Pair(){}
Pair(int xx,int yy) {x=xx,y=yy;}
bool operator < (const Pair& oth) const {
return sz<oth.sz;
}
} a[maxn+5];
int n,m;
map<int,int> mp;
int cnt;
struct SGT{
#define mid (L+R)/2
#define lson o*2
#define rson o*2+1
int c[maxn*10+5],lzy[maxn*10+5];
int P,Q,sz;
SGT(){}
void Set(int L,int R) {P=L,Q=R;}
void push_down(int o) {
c[lson]+=lzy[o],c[rson]+=lzy[o];
lzy[lson]+=lzy[o],lzy[rson]+=lzy[o];
lzy[o]=0;
}
void push_up(int o) {
c[o]=max(c[lson],c[rson]);
}
void Add(int o,int L,int R,int d) {
if(L>Q||R<P) return ;
if(L>=P&&R<=Q) {
c[o]+=d,lzy[o]+=d;
return ;
}
push_down(o);
Add(lson,L,mid,d),Add(rson,mid+1,R,d);
push_up(o);
}
} sgt;
int main() {
read(n),read(m);
for(int i=1;i<=n;i++) {
read(a[i].x),read(a[i].y),a[i].sz=a[i].y-a[i].x;
mp[a[i].x]=mp[a[i].y]=true;
}
for(map<int,int>::iterator it=mp.begin();it!=mp.end();++it) {
mp[it->first]=++cnt;
}
for(int i=1;i<=n;i++) {
a[i].x=mp[a[i].x],a[i].y=mp[a[i].y];
}
sort(a+1,a+n+1);
int t=1,ans=inf;
for(int i=1;i<=n;i++) {
sgt.Set(a[i].x,a[i].y);
sgt.Add(1,1,n*2,1);
while(sgt.c[1]>=m) {
ans=min(ans,a[i].sz-a[t].sz);
sgt.Set(a[t].x,a[t].y);
sgt.Add(1,1,n*2,-1);
t++;
}
}
printf("%d",ans==inf?-1:ans);
return 0;
}