【NOI2016】区间(线段树+离散化)

题目描述

我们可以发现对于最优解的被m次覆盖的某个位置一定是某一个线段的端点,故离散化。
先将所有区间按照区间长度排序。
我们可以发现对于最优解一定出现在排序后的连续区间内。
比如若对于最优解需要排序后的第一个区间与第三个区间,那么此时如果加上第二个区间,那么最优解的值也是一样的。
那么维护两个指针l和r,用线段树对区间作区间覆盖,用尺取法求解。

#include<bits/stdc++.h>
#define fer(i,j,n) for(int i=j;i<=n;i++)
#define far(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define pa pair<int,int>
const int maxn=4000010;
const int INF=1e9+7;
using namespace std;
/*----------------------------------------------------------------------------*/
inline ll read()
{
    char ls;ll x=0,sng=1;
    for(;ls<'0'||ls>'9';ls=getchar())if(ls=='-')sng=-1;
    for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
    return x*sng;
}
/*----------------------------------------------------------------------------*/
int n,m,cnt,ans=INF;
int b[maxn];
struct kaga
{
    int l,r,maxx,lazy;
}tr[maxn];
struct akagi
{
    int l,r,len;
    bool friend operator <(akagi a,akagi b)
    {
        return a.len<b.len; 
    }
}a[maxn];
void maxup(int x)
{
    tr[x].maxx=max(tr[x<<1].maxx,tr[x<<1|1].maxx);
}
void pushdown(int x)
{
    if(tr[x].lazy)
    {
        tr[x<<1].lazy+=tr[x].lazy;
        tr[x<<1].maxx+=tr[x].lazy;
        tr[x<<1|1].lazy+=tr[x].lazy;
        tr[x<<1|1].maxx+=tr[x].lazy;
        tr[x].lazy=0;
    }
    return ;
}
void build(int x,int l,int r)
{
    int mid=(l+r)>>1;
    tr[x].l=l;tr[x].r=r;
    if(l==r)
    {
        tr[x].maxx=0;
        return ;    
    }
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    maxup(x);
}
void change(int x,int L,int R,int val)
{
    int l=tr[x].l,r=tr[x].r,mid=(l+r)>>1;
    if(l>=L&&r<=R)
    {tr[x].lazy+=val;tr[x].maxx+=val;return ;}
    pushdown(x);
    if(R<=mid)change(x<<1,L,R,val);
    else if(L>mid)change(x<<1|1,L,R,val);
    else change(x<<1,L,mid,val),change(x<<1|1,mid+1,R,val);
    maxup(x);
}
int main()
{
    cnt=0;
    n=read();m=read();
    fer(i,1,n)
    {
        a[i].l=read();a[i].r=read();a[i].len=a[i].r-a[i].l;
        b[++cnt]=a[i].l;b[++cnt]=a[i].r;
    }
    if(m==1)ans=0;
    sort(a+1,a+n+1);
    sort(b+1,b+cnt+1);
    cnt=unique(b+1,b+cnt+1)-b-1;
    build(1,1,cnt);
    fer(i,1,n)
    {
        a[i].l=lower_bound(b+1,b+cnt+1,a[i].l)-b;
        a[i].r=lower_bound(b+1,b+cnt+1,a[i].r)-b;   
    }
    int l=1,r=0;
    while(l<=n)
    {
        while(tr[1].maxx<m)
        {
            if(r==n)
            {
                if(ans==INF)cout<<-1<<endl;
                else cout<<ans<<endl;
                return 0;   
            }
            r++;
            change(1,a[r].l,a[r].r,1);
        }
        ans=min(ans,a[r].len-a[l].len);
        change(1,a[l].l,a[l].r,-1);
        l++;
    }
    cout<<ans<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值