• [NOI2016]区间(线段树+尺取法)


    [NOI2016]区间(线段树+尺取法)

    题面

    在数轴上有n个闭区间 。现在要从中选出 m个区间,使得这m个区间共同包含至少一个位置.对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。求所有合法方案中最小的花费。如果不存在合法的方案,输出-1 。

    分析

    看到长度最大最小值的差,考虑按长度排序。然后类似尺取法的思路,从小到大不断加入区间,直到存在一个位置被覆盖了至少(m)次,此时最后一个加入的区间就是当前条件下最大的区间长度。但此时最短区间长度还可以增加,所以不断从头删除区间,保证存在一个位置被覆盖了至少(m)次,并更新答案。区间离散化后用线段树维护区间覆盖次数。

    正确性证明: 我们只需要证左端点随右端点单调增加即可。假设一个合法的解的区间是([x,y]). 假设右端点(>y)后,左端点(p)(x)小,那么会在([p,y])找到更优的解,矛盾

    时间复杂度:(O(nlog n))

    代码

    //[NOI2016]区间 
    #include<iostream>
    #include<cstdio>
    #include<cstring> 
    #include<algorithm>
    #define INF 0x3f3f3f3f
    #define maxn 500000
    using namespace std;
    struct segment_tree{
        struct node{
            int l;
            int r;
            int val;
            int mark;
            int len(){
                return r-l+1;
            }
        }tree[maxn*2*4+5];
        void push_up(int pos){
            tree[pos].val=max(tree[pos<<1].val,tree[pos<<1|1].val);//找到最大的覆盖次数 
        }
        void build(int l,int r,int pos){
            tree[pos].l=l;
            tree[pos].r=r;
            if(l==r) return;
            int mid=(l+r)>>1;
            build(l,mid,pos<<1);
            build(mid+1,r,pos<<1|1);
            push_up(pos);
        }
        void push_down(int pos){
            if(tree[pos].mark){
                tree[pos<<1].val+=tree[pos].mark;
                tree[pos<<1].mark+=tree[pos].mark;
                tree[pos<<1|1].val+=tree[pos].mark;
                tree[pos<<1|1].mark+=tree[pos].mark;
                tree[pos].mark=0;
            }
        }
        void update(int L,int R,int val,int pos){
            if(L<=tree[pos].l&&R>=tree[pos].r){
                tree[pos].val+=val;
                tree[pos].mark+=val;
                return;
            }
            push_down(pos);
            int mid=(tree[pos].l+tree[pos].r)>>1;
            if(L<=mid) update(L,R,val,pos<<1);
            if(R>mid) update(L,R,val,pos<<1|1);
            push_up(pos);
        }
        int query_all(){
            return tree[1].val;
        }
    }T;
    
    int n,m;
    struct seg{
        int len;
        int l;
        int r;
        friend bool operator < (seg p,seg q){
            return p.len<q.len;
        }
    }a[maxn+5];
    int tmp[maxn*2+5];
    int dn=0;
    int main(){
    #ifndef LOCAL
        freopen("interval.in","r",stdin);
        freopen("interval.out","w",stdout); 
    #endif 
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d %d",&a[i].l,&a[i].r);
            tmp[++dn]=a[i].l;
            tmp[++dn]=a[i].r; 
            a[i].len=a[i].r-a[i].l+1;
        }
        sort(tmp+1,tmp+1+dn);
        dn=unique(tmp+1,tmp+1+dn)-tmp-1;
        for(int i=1;i<=n;i++){
            a[i].l=lower_bound(tmp+1,tmp+1+dn,a[i].l)-tmp;
            a[i].r=lower_bound(tmp+1,tmp+1+dn,a[i].r)-tmp;
        }
        sort(a+1,a+1+n);
        T.build(1,dn,1);
        int ans=INF;
        for(int i=1,j=1;i<=n;i++){
            T.update(a[i].l,a[i].r,1,1);
            while(T.query_all()>=m){
                ans=min(ans,a[i].len-a[j].len);
                T.update(a[j].l,a[j].r,-1,1); 
                j++;
            } 
        }
        if(ans==INF) printf("-1
    ");
        else printf("%d
    ",ans);
    }
    
  • 相关阅读:
    第04组 Beta冲刺(2/5)
    第04组 Beta冲刺(1/5)
    第04组 Alpha事后诸葛亮
    第04组 Alpha冲刺(6/6)
    第04组 Alpha冲刺(5/6)
    第04组 Alpha冲刺(4/6)
    第04组 Alpha冲刺(3/6)
    作业2-1:矩阵协方差
    作业lab1-1:lammps教程总结
    如何在服务器上传/下载文件
  • 原文地址:https://www.cnblogs.com/birchtree/p/14080865.html
Copyright © 2020-2023  润新知