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

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

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

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

不难发现左右两个指针都是不递减的,所以时间复杂度是 $O(\texttt{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\n",ans==inf?-1:ans);  
    return 0; 
}

  

posted @ 2019-08-01 16:44  EM-LGH  阅读(208)  评论(0编辑  收藏  举报