2018.08.17 bzoj4653: [Noi2016]区间

传送门
将坐标离散化之后直接用双指针+线段树维护。
其实就是说只要目前所有点的被覆盖次数是大于等于m的就移动左指针删除区间更新答案,否则移动右指针加入区间更新答案。
话说忘记排序以及建树的时候参数带错是几个意思??
代码:

#include<bits/stdc++.h>
#define N 500005
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
using namespace std;
inline int read(){
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
int n,m,L[N],R[N],cnt=0,b[N<<1];
struct Node{int l,r,mx,add;}T[N<<2];
struct Q{int l,r,len;}q[N];
inline int max(int a,int b){return a>b?a:b;}
inline void pushup(int p){T[p].mx=max(T[lc].mx,T[rc].mx);}
inline void pushnow(int p,int v){T[p].mx+=v,T[p].add+=v;}
inline void pushdown(int p){if(T[p].add)pushnow(lc,T[p].add),pushnow(rc,T[p].add),T[p].add=0;}
inline void build(int p,int l,int r){
    T[p].l=l,T[p].r=r,T[p].add=T[p].mx=0;
    if(l==r)return;
    build(lc,l,mid),build(rc,mid+1,r);
}
inline void update(int p,int ql,int qr,int v){
    if(ql>T[p].r||qr<T[p].l)return;
    if(ql<=T[p].l&&T[p].r<=qr)return pushnow(p,v);
    pushdown(p);
    if(qr<=mid)update(lc,ql,qr,v);
    else if(ql>mid)update(rc,ql,qr,v);
    else update(lc,ql,mid,v),update(rc,mid+1,qr,v);
    pushup(p); 
}
inline bool cmp(Q a,Q b){return a.len<b.len;}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;++i)b[++cnt]=L[i]=read(),b[++cnt]=R[i]=read();
    sort(b+1,b+cnt+1);
    cnt=unique(b+1,b+cnt+1)-b-1;
    for(int i=1;i<=n;++i){
        q[i].l=lower_bound(b+1,b+cnt+1,L[i])-b;
        q[i].r=lower_bound(b+1,b+cnt+1,R[i])-b;
        q[i].len=R[i]-L[i]+1;
    }
    sort(q+1,q+n+1,cmp);
    build(1,1,q[n].r);
    int ans=0x3f3f3f3f;
    for(int l=1,r=1;r<=n;++r){
        update(1,q[r].l,q[r].r,1);
        while(T[1].mx>=m){
            ans=min(ans,q[r].len-q[l].len);
            update(1,q[l].l,q[l].r,-1);
            ++l;
        }
    }
    cout<<(ans==0x3f3f3f3f?-1:ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/81781088