首页 > 代码库 > 区间(bzoj 4653)

区间(bzoj 4653)

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
/*
    不得不说,本弱是真弱啊,这道题的思路好像不是很难,但是就是想不出。
    首先将区间离散化,然后按照区间长度排序,一种暴力的方法是枚举左区间,然后枚举用线段树判定找到第一个满足条件的右区间,这样的方法是O(n^2logn)的。
    其实我们可以发现对于递增的左区间来说,第一个满足条件的右区间也是递增的,这样复杂度就降到了O(nlogn)。 
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 500010
#define inf 1000000000
using namespace std;
int b[N*2],n,m;
int mx[N*8],tag[N*8];
struct node{int l,r,len;}a[N];
bool cmp(const node&x,const node&y){return x.len<y.len;}

void push_up(int k){
    mx[k]=max(mx[k*2],mx[k*2+1]);
}
void push_down(int k){
    if(!tag[k]) return;
    mx[k*2]+=tag[k];
    tag[k*2]+=tag[k];
    mx[k*2+1]+=tag[k];
    tag[k*2+1]+=tag[k];
    tag[k]=0;
}
void add(int k,int l,int r,int x,int y,int val){
    if(l>=x&&r<=y){
        mx[k]+=val;
        tag[k]+=val;
        return;
    }
    push_down(k);
    int mid=l+r>>1;
    if(x<=mid) add(k*2,l,mid,x,y,val);
    if(y>mid) add(k*2+1,mid+1,r,x,y,val);
    push_up(k);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i].l,&a[i].r);
        a[i].len=a[i].r-a[i].l;
        b[i*2-1]=a[i].l;
        b[i*2]=a[i].r;
    }
    sort(b+1,b+n*2+1);
    int tot=unique(b+1,b+2*n+1)-b-1;
    for(int i=1;i<=n;i++){
        a[i].l=lower_bound(b+1,b+tot+1,a[i].l)-b;
        a[i].r=lower_bound(b+1,b+tot+1,a[i].r)-b;
    }
    sort(a+1,a+n+1,cmp);
    int tt=1,ans=inf;
    for(int i=1;i<=n;i++){
        while(mx[1]<m&&tt<=n){
            add(1,1,tot,a[tt].l,a[tt].r,1);
            tt++;
        }
        if(mx[1]>=m) ans=min(ans,a[tt-1].len-a[i].len);
        add(1,1,tot,a[i].l,a[i].r,-1);
    }
    if(ans!=inf) printf("%d",ans);
    else printf("-1");
    return 0;
}

 

区间(bzoj 4653)