1. 程式人生 > >[2019.2.27]BZOJ4653 [Noi2016]區間

[2019.2.27]BZOJ4653 [Noi2016]區間

大於 mps ++ n+1 struct uil using sin 末尾

首先看到左右端點的範圍為\(10^9\),首先離散化。

考慮將所有區間按照原來的長度升序排序,每次將開頭一個區間加入,看有沒有被大於等於\(m\)個區間覆蓋的點,如果有,不停地從末尾刪掉區間,直到沒有點的覆蓋次數大於等於\(m\)的點。那麽我們就得到了以我們新加入的那個區間的原長度為最長區間長度,那麽使得有點出現次數大於等於\(m\)的最短區間長度的最大值為我們上一個刪去的區間,用這兩個數的差更新答案。

線段樹維護每個點被覆蓋的次數即可。

code:

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9+10;
struct s{
    int l,r,sl;
}as[500010];
struct val{
    int v,id,tg;
}v[1000010];
struct node{
    int l,r,mx,tag;
}t[4000010];
int n,m,sz,nw,l,r,tg,ans=INF;
bool cmp(val x,val y){
    return x.v<y.v;
}
bool cmps(s x,s y){
    return x.sl<y.sl;
}
void Upd(int x){
    t[x].mx=max(t[x<<1].mx,t[x<<1|1].mx);
}
void Psd(int x){
    t[x].tag?t[x<<1].mx+=t[x].tag,t[x<<1].tag+=t[x].tag,t[x<<1|1].mx+=t[x].tag,t[x<<1|1].tag+=t[x].tag,t[x].tag=0:0;
}
void Build(int x,int l,int r){
    t[x].l=l,t[x].r=r;
    if(l==r)return;
    int mid=l+r>>1;
    Build(x<<1,l,mid),Build(x<<1|1,mid+1,r);
}
void Change(int x,int l,int r,int v){
    if(t[x].l==l&&t[x].r==r)return(void)(t[x].tag+=v,t[x].mx+=v);
    int mid=t[x].l+t[x].r>>1;
    Psd(x);
    r<=mid?Change(x<<1,l,r,v):(l>mid?Change(x<<1|1,l,r,v):(Change(x<<1,l,mid,v),Change(x<<1|1,mid+1,r,v))),Upd(x);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d%d",&v[sz+1].v,&v[sz+2].v),sz+=2,v[sz-1].id=v[sz].id=i,v[sz-1].tg=0,v[sz].tg=1,as[i].sl=v[sz].v-v[sz-1].v;
    sort(v+1,v+sz+1,cmp),v[0].v=-1;
    for(int i=1;i<=sz;++i)v[i].v>v[i-1].v?++nw:0,v[i].tg?as[v[i].id].r=nw:as[v[i].id].l=nw;
    sort(as+1,as+n+1,cmps);
    Build(1,1,nw),l=1;
    for(r=1;r<=n;++r,tg=0){
        Change(1,as[r].l,as[r].r,1);
        while(t[1].mx>=m)tg=1,Change(1,as[l].l,as[l].r,-1),++l;
        ans=min(ans,tg?as[r].sl-as[l-1].sl:INF);
    }
    printf("%d",ans==INF?-1:ans);
    return 0;
}

[2019.2.27]BZOJ4653 [Noi2016]區間