[NOI2016] 区间

Solution

答案贡献只与区间长度最大的和最小的有关,故长度介于它们之间的选不选无所谓。再贪一下,发现区间加得越多有可能会更优,那么一定要把所有能加的区间都加进去才最好。所以按长度排序之后,选了的区间一定是连续的一段。

考虑一个朴素的暴力算法,我们枚举最大区间和最小区间,然后把其间的所有区间也加入,把对应位置打上标记。那么只需要知道有没有一个位置被打的标记次数大于等于 (m)。复杂度 (O(n^4))。线段树随便维护一下就能优化到 (O(n^3 log n)) ,但是好像没有什么用。

发现枚举是连续的,不用每次全部重新统计。这样可以降到 (O(n^2 log n)),期望得分 60。

瓶颈在于枚举端点。考虑固定右端点,那么最大的能使得标记大于等于 (m) 的点存在的左端点可以唯一确定。把右端点往右移动一格时,左端点也会跟着移动,而且我们发现左端点一定是单调的往右移动。这实际上就是一个 2-pointer 。那么复杂度就将为 (O(n log n)) ,期望得分 100。

#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 500007
#define lid id<<1
#define rid id<<1|1

inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}

struct Seg{
    int l,r,len;
    bool operator <(const Seg &X)const{return len<X.len;}
}a[N];

struct Node{
    int mx,tag,lf,rf;
}t[(N*2)<<2];

int n,m,sz;

inline void update(int id){t[id].mx=max(t[lid].mx,t[rid].mx);}
inline void Push(int id,int val){t[id].mx+=val,t[id].tag+=val;}
inline void pushdown(int id){Push(lid,t[id].tag),Push(rid,t[id].tag),t[id].tag=0;}

int L,R,V;

#define Lf t[id].lf
#define Rf t[id].rf

void modify(int id){
    if(L<=Lf&&Rf<=R) Push(id,V);
    else{
        int mid=(Lf+Rf)>>1;
        if(t[id].tag) pushdown(id);
        if(L<=mid) modify(lid);
        if(R>mid) modify(rid);
        update(id);
    }
}

void build(int id,int lf,int rf){
    t[id].mx=t[id].tag=0;
    t[id].lf=lf,t[id].rf=rf;
    if(lf==rf) return ;
    int mid=(lf+rf)>>1;
    build(lid,lf,mid),build(rid,mid+1,rf);
}

inline bool check(int x){
    build(1,1,sz);
    for(int l=1,r=1;r<=n;r++){
        while(a[l].len+x<a[r].len)
            L=a[l].l,R=a[l].r,V=-1,modify(1),l++;
        L=a[r].l,R=a[r].r,V=1,modify(1);
        if(t[1].mx>=m) return 1;
    }
    return 0;
}

int X[N<<1];
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)
        a[i].l=read(),a[i].r=read(),a[i].len=a[i].r-a[i].l,
        X[(i<<1)-1]=a[i].l,X[i<<1]=a[i].r;
    sort(a+1,a+1+n),sort(X+1,X+1+2*n);
    sz=unique(X+1,X+1+2*n)-(X+1);
    for(int i=1;i<=n;i++)
        a[i].l=lower_bound(X+1,X+1+sz,a[i].l)-X,
        a[i].r=lower_bound(X+1,X+1+sz,a[i].r)-X;
    int l=1,ans=X[sz]+1;
    build(1,1,sz);
    for(int i=1;i<=n;i++){
        L=a[i].l,R=a[i].r,V=1,modify(1);
        while(l<i){
            L=a[l].l,R=a[l].r,V=-1,modify(1);
            if(t[1].mx>=m) l++;
            else{V=1,modify(1);break;}
        }
        if(t[1].mx>=m) ans=min(ans,a[i].len-a[l].len);    
    }
    printf("%d",ans==X[sz]+1? -1:ans);
}
原文地址:https://www.cnblogs.com/wwlwQWQ/p/14528030.html