• BZOJ 4653: [Noi2016]区间 双指针 + 线段树


    只要一堆线段有重叠次数大于等于 $m$ 次的位置,那么一定有解 

    因为重叠 $m$ 次只需 $m$ 个线断,将那些多余的线断排除掉即可 

    先将区间按照长度从小到大排序,再用 $two-pointer$ 从左到右扫描

    不难发现左右两个指针都是不递减的,所以时间复杂度是 $O( exttt{nlogn})$ 的

    #include <cstdio>
    #include <string>
    #include <algorithm> 
    using namespace std;  
    namespace IO {
        inline void setIO(string s) {
            string in=s+".in";
            string out=s+".out"; 
            freopen(in.c_str(),"r",stdin);  
        } 
    };  
    const int maxn=500005;
    const int inf=1000030000;   
    int n,m;   
    namespace tree { 
        int tag[maxn*5],maxv[maxn*5]; 
        inline void pushup(int now) {
            maxv[now]=tag[now]; 
            maxv[now]+=max(maxv[now<<1],maxv[now<<1|1]);   
        }  
        void update(int l,int r,int now,int L,int R,int v) {  
            if(l>=L&&r<=R) { 
                tag[now]+=v, maxv[now]+=v;    
                return;  
            } 
            int mid=(l+r)>>1;    
            if(L<=mid) update(l,mid,now<<1,L,R,v); 
            if(R>mid) update(mid+1,r,now<<1|1,L,R,v); 
            pushup(now);  
        }
        int query(int l,int r,int now,int L,int R) {
            if(l>=L&&r<=R) return maxv[now];       
            int mid=(l+r)>>1,re=0; 
            if(L<=mid) re=max(re,query(l,mid,now<<1,L,R)); 
            if(R>mid) re=max(re,query(mid+1,r,now<<1|1,L,R));   
            return re+tag[now];       
        }
    };   
    int Arr[maxn*2];  
    struct Seg {   
        int l,r,len,L,R;    
    }seg[maxn]; 
    bool cmp(Seg a,Seg b) {
        return a.len<b.len; 
    }     
    int main() {
        // IO::setIO("input"); 
        scanf("%d%d",&n,&m);
        int cc=0,i,j; 
        for(i=1;i<=n;++i) {
            scanf("%d%d",&seg[i].l,&seg[i].r);      
            seg[i].len=seg[i].r-seg[i].l;  
            Arr[++cc]=seg[i].l,Arr[++cc]=seg[i].r;   
        }   
        sort(seg+1,seg+1+n,cmp);            
        sort(Arr+1,Arr+1+cc);   
        for(i=1;i<=n;++i) {
            seg[i].L=lower_bound(Arr+1,Arr+1+cc,seg[i].l)-Arr; 
            seg[i].R=lower_bound(Arr+1,Arr+1+cc,seg[i].r)-Arr;   
        }   
        int ans=inf;  
        int l=1,r=0; 
        while(l<=n&&r<=n) {            
            if(tree::query(1,cc,1,1,cc)>=m) {
                ans=min(ans, seg[r].len-seg[l].len);      
                tree::update(1,cc,1,seg[l].L,seg[l].R,-1);               
                ++l;                
            }
            else {          
                ++r;       
                if(r<=n) tree::update(1,cc,1,seg[r].L,seg[r].R,1);           
            }
        }   
        printf("%d
    ",ans==inf?-1:ans);  
        return 0; 
    }
    

      

  • 相关阅读:
    【SQL查询】查询列中使用条件逻辑_case when then end
    【SQL查询】查询的列起别名_AS
    【SQL查询】查询的值为空时,给出默认值_NVL函数
    工薪阶层理财建议
    软件文档编写_软件开发过程中的文档
    等价边界值测试_日期
    【登录】测试用例
    来纪中的第一天
    普及C组第二题(8.1)
    普及C组第一题(8.1)
  • 原文地址:https://www.cnblogs.com/guangheli/p/11283620.html
Copyright © 2020-2023  润新知