BZOJ4653 - [NOI2016]区间

Portal

Description

给出数轴上的\(n(n\leq5\times10^5)\)个闭区间,从中选出\(m(m\leq2\times10^5)\)个,并且它们的交集不为空。一个合法方案的代价为所选区间中的最长长度减去最短长度,求最小代价。

Solution

将区间按长度由小到大排序。每次钦定区间\(i\)为最短区间,然后寻找\(j\geq i\)使得存在至少一个数被区间\(i..j\)中的\(m\)个覆盖,这可以用线段树实现。因为\(j\)是不退的,所以循环\(i=1..n\),每次向后寻找\(j\)即可。

时间复杂度\(O(nlogn)\)

Code

//[NOI2016]区间
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
inline char gc()
{
    static char now[1<<16],*s,*t;
    if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
    return *s++;
}
inline int read()
{
    int x=0; char ch=gc();
    while(ch<'0'||'9'<ch) ch=gc();
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x;
}
int const N=1e6+10;
int n,m; int n0,map[N];
struct range{int L,R;} r[N>>1];
bool cmpRng(range x,range y) {return x.R-x.L<y.R-y.L;}
#define Ls (p<<1)
#define Rs ((p<<1)|1)
int rt; int maxV[N<<2],tag[N<<2];
int L,R;
void update(int p) {maxV[p]=max(maxV[Ls],maxV[Rs]);}
void add(int p,int x) {maxV[p]+=x,tag[p]+=x;}
void pushdw(int p) {if(tag[p]) add(Ls,tag[p]),add(Rs,tag[p]),tag[p]=0;}
void ins(int p,int L0,int R0,int x)
{
    if(L<=L0&&R0<=R) {add(p,x); return;}
    pushdw(p);
    int mid=L0+R0>>1;
    if(L<=mid) ins(Ls,L0,mid,x);
    if(mid<R) ins(Rs,mid+1,R0,x);
    update(p);
}
int query(int p,int L0,int R0)
{
    if(L<=L0&&R0<=R) return maxV[p];
    pushdw(p);
    int mid=L0+R0>>1; int res=0;
    if(L<=mid) res=max(res,query(Ls,L0,mid));
    if(mid<R) res=max(res,query(Rs,mid+1,R0));
    return res;
}
int main()
{   
    n=read(),m=read();
    for(int i=1;i<=n;i++) map[i*2-1]=r[i].L=read(),map[i*2]=r[i].R=read();
    sort(r+1,r+n+1,cmpRng);
    sort(map+1,map+n+n+1); n0=unique(map+1,map+n+n+1)-map-1;
    for(int i=1;i<=n;i++) r[i].L=lower_bound(map+1,map+n0+1,r[i].L)-map;
    for(int i=1;i<=n;i++) r[i].R=lower_bound(map+1,map+n0+1,r[i].R)-map;
    int ans=2e9; rt=1;
    for(int i=1,j=0;i<=n;i++)
    {
        while(true)
        {
            if(maxV[rt]>=m) break;
            if(++j>n) break;
            L=r[j].L,R=r[j].R,ins(rt,1,n0,1);
        }
        if(j>n) break;
        ans=min(ans,(map[r[j].R]-map[r[j].L])-(map[r[i].R]-map[r[i].L]));
        L=r[i].L,R=r[i].R; ins(rt,1,n0,-1);
    }
    if(ans==2e9) puts("-1");
    else printf("%d\n",ans);
    return 0;
}

P.S.

我菜死了...其实很简单的,也做过类似的题

posted @ 2018-04-02 11:23  VisJiao  阅读(102)  评论(0编辑  收藏  举报