• 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
    ",ans);
        return 0;
    }
  • 相关阅读:
    mysql max_allowed_packet设置及问题
    mybatis之foreach用法
    uniapp编译小程序分包配置
    鼠标点击页面显示文字
    element ui el-date-picker 判断所选时间是否交叉
    前端处理跨域的几种方式
    uniapp的ajax封装请求
    js获取两个时间差
    vue文件下载功能
    nextTick使用
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj4653.html
Copyright © 2020-2023  润新知