[bzoj4653] [NOI2016]区间
Description
在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn]。现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置。换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri。
对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值。
求所有合法方案中最小的花费。如果不存在合法的方案,输出 −1。
Input
第一行包含两个正整数 n,m用空格隔开,意义如上文所述。保证 1≤m≤n
接下来 n行,每行表示一个区间,包含用空格隔开的两个整数 li 和 ri 为该区间的左右端点。
N<=500000,M<=200000,0≤li≤ri≤10^9
Output
只有一行,包含一个正整数,即最小花费。
Sample Input
6 3
3 5
1 2
3 4
2 2
1 5
1 4
Sample Output
2
Solution
由于答案是最大的区间减最小的区间,而且和顺序没关系,所以可以按区间长度排序。
按顺序加入,显然当有一个点的覆盖次数大于\(m\)时,就不加了。
然后对于已经加进去的,从小到大删除,直到覆盖次数全都小于\(m\)时,最后一个删掉的和当前加入的最大的区间肯定可以构成一个当前最优的方案。
然后开个线段树,拿两个指针指一下,模拟下上面的过程就行了。
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 5e6+1;
struct node {
int l,r,len;
bool operator < (const node &rhs) const {return len<rhs.len;}
}in[maxn<<1];
int a[maxn],b[maxn],n,m,tot,head,tail;
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
struct Segment_Tree {
int tr[maxn],tag[maxn];
void push_tag(int p,int v) {tr[p]+=v,tag[p]+=v;}
void update(int p) {tr[p]=max(tr[ls],tr[rs]);}
void pushdown(int p) {
if(tag[p]) push_tag(ls,tag[p]),push_tag(rs,tag[p]),tag[p]=0;
}
void modify(int p,int l,int r,int x,int y,int v) {
if(x<=l&&r<=y) return push_tag(p,v),void();
pushdown(p);
if(x<=mid) modify(ls,l,mid,x,y,v);
if(y>mid) modify(rs,mid+1,r,x,y,v);
update(p);
}
}SGT;
#undef ls
#undef rs
#undef mid
int main() {
read(n),read(m);
for(int i=1;i<=n;i++) read(in[i].l),read(in[i].r),in[i].len=in[i].r-in[i].l;
sort(in+1,in+n+1);
for(int i=1;i<=n;i++) a[++tot]=in[i].l,a[++tot]=in[i].r;
sort(a+1,a+tot+1);int M=unique(a+1,a+tot+1)-a-1;
for(int i=1;i<=n;i++) {
in[i].l=lower_bound(a+1,a+M+1,in[i].l)-a;
in[i].r=lower_bound(a+1,a+M+1,in[i].r)-a;
}
int ans=1e9;
while(tail<n) {
while(tail<n&&SGT.tr[1]<m) tail++,SGT.modify(1,1,n*2,in[tail].l,in[tail].r,1);
if(SGT.tr[1]<m) break;
while(head<=tail&&SGT.tr[1]>=m) head++,SGT.modify(1,1,n*2,in[head].l,in[head].r,-1);
ans=min(ans,in[tail].len-in[head].len);
}
if(ans!=1e9) write(ans);else puts("-1");
return 0;
}