BZOJ 4653: [Noi2016]区间 线段树

来源:互联网 发布:数据服务 编辑:程序博客网 时间:2024/06/05 17:09

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

题解

首先我们将所有区间按照长度排序,然后我们依次扫描每个区间,用线段树找到它第一次有点覆盖次数超过k的另一个区间,更新一下答案,因为左端点递增时右端点也一定递增,所以维护两个指针扫一下即可。

#include<cstdio>#include<cstdlib>#include<iostream>#include<iomanip>#include<cstring>#include<string>#include<algorithm>#include<ctime>#include<cmath>using namespace std;struct xianduan{    int l,r,maxx,lazy;    void add(int val)    {        maxx+=val;        lazy+=val;    }}a[5000000];void make_tree(int o,int l,int r){    a[o].l=l;    a[o].r=r;    a[o].maxx=0;    a[o].lazy=0;    if(l==r) return;    int mid=l+r>>1;    make_tree(2*o,l,mid);    make_tree(2*o+1,mid+1,r);}void push_down(int o){    if(a[o].l==a[o].r) return;    if(!a[o].lazy) return;    a[2*o].add(a[o].lazy);    a[2*o+1].add(a[o].lazy);    a[o].lazy=0;}void change(int o,int l,int r,int d){    if(a[o].r<l || a[o].l>r) return;    push_down(o);    if(a[o].l>=l && a[o].r<=r)     {         a[o].add(d);         return;    }    change(2*o,l,r,d);    change(2*o+1,l,r,d);    a[o].maxx=max(a[2*o].maxx,a[2*o+1].maxx);}struct interval{    int l,r,val;    bool operator < (interval b) const    {        return val<b.val;    }}q[600000];int dd[1100000];int top=0;int main(){    int n,m;    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].val=q[i].r-q[i].l+1,dd[++top]=q[i].l,dd[++top]=q[i].r;    sort(dd+1,dd+1+top);    top=unique(dd+1,dd+1+top)-dd-1;    for(int i=1;i<=n;i++) q[i].l=lower_bound(dd+1,dd+1+top,q[i].l)-dd,q[i].r=lower_bound(dd+1,dd+1+top,q[i].r)-dd;    sort(q+1,q+1+n);    int r=1;    int ans=2147483647;    make_tree(1,1,top);    for(int i=1;i<=n;i++)    {        while(a[1].maxx<m && r<=n)        {            change(1,q[r].l,q[r].r,1);            r++;        }        if(a[1].maxx<m) break;        ans=min(ans,q[r-1].val-q[i].val);        change(1,q[i].l,q[i].r,-1);    }    if(ans==2147483647) cout<<-1;    else cout<<ans<<endl;    return 0;}