BZOJ 4653 [Noi2016]区间(Two pointers+线段树)

 

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=4653

 

【题目大意】

  在数轴上有n个闭区间 [l1,r1],[l2,r2],...,[ln,rn]。
  现在要从中选出m个区间,使得这m个区间共同包含至少一个位置。
  对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。
  区间[li,ri]的长度定义为它的右端点的值减去左端点的值。
  求所有合法方案中最小的花费。如果不存在合法的方案,输出-1。

 

【题解】

  我们将所有的区间按照长度从小到大排序,那么我们枚举左端点和右端点,
  将区间内的所有区间在线段树上更新1,
  那么当有个点被覆盖m次的时候这个区间就可以用来更新答案,该操作只要求最大值即可。
  区间的最大值对于左右端点的枚举具有单调性,
  可以用Twopointers来实现,前后指针各移动n次,
  复杂度O(nlogn)。

 

【代码】

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std; 
const int N=2000000;
struct node{int l,r,a,b,tag,max;}T[N];
const int INF=0x3f3f3f3f;
int tot,n,m,l,r,c;
void addtag(int x,int tag){
    T[x].tag+=tag;
    T[x].max+=tag;
}
void pb(int x){
    if(T[x].l){addtag(T[x].l,T[x].tag);addtag(T[x].r,T[x].tag);}
    T[x].tag=0;
}
void up(int x){T[x].max=max(T[T[x].l].max,T[T[x].r].max);}
void build(int l,int r){
    int x=++tot;
    T[x].a=l;T[x].b=r;T[x].tag=T[x].l=T[x].r=T[x].max=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    T[x].l=tot+1;build(l,mid);
    T[x].r=tot+1;build(mid+1,r);
    up(x);
}
void change(int x,int a,int b,int p){
    if(T[x].a>=a&&T[x].b<=b){addtag(x,p);return;}
    if(T[x].tag)pb(x); int mid=(T[x].a+T[x].b)>>1;
    if(mid>=a&&T[x].l)change(T[x].l,a,b,p);
    if(mid<b&&T[x].r)change(T[x].r,a,b,p);up(x);
}
int cnt,disc[N<<1];
struct data{int l,r,len;}p[N];
bool cmp(data a,data b){return a.len<b.len;}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&p[i].l,&p[i].r); p[i].len=p[i].r-p[i].l;
        disc[++cnt]=p[i].l; disc[++cnt]=p[i].r;
    }sort(disc+1,disc+cnt+1);
    cnt=unique(disc+1,disc+cnt+1)-disc-1;
    build(1,cnt);
    for(int i=1;i<=n;i++){
        p[i].l=lower_bound(disc+1,disc+cnt+1,p[i].l)-disc;
        p[i].r=lower_bound(disc+1,disc+cnt+1,p[i].r)-disc;
    }sort(p+1,p+n+1,cmp); int pt=0,ans=INF;
    for(int i=1;i<=n;i++){
        while(T[1].max<m&&pt<n){
            pt++; change(1,p[pt].l,p[pt].r,1);
        }if(T[1].max==m)ans=min(ans,p[pt].len-p[i].len);
        change(1,p[i].l,p[i].r,-1);
    }if(ans==INF)puts("-1");
    else printf("%d\n",ans);
    return 0;
}
posted @ 2017-07-14 16:10  forever97  阅读(260)  评论(0编辑  收藏  举报