NOI - 2016 - 区间(双指针+线段树)

NOI - 2016 - 区间

首先离散化,然后对所有区间按照区间长度排序。然后用双指针。双指针保持 [l,r] 这段的所有区间叠加后存在叠加次数为 m 的点。然后 ans 等于每一次合法时的最小值。这样显然是对的。因为一个合法的答案一定在某次双指针区间内计数。

#include<bits/stdc++.h>
#define lson (rt<<1)
#define rson (rt<<1|1)
using namespace std;
const int N=5e5+7;
const int INF=0x3f3f3f3f;
inline int Max(int a,int b) { return a>b?a:b; }
inline int Min(int a,int b) { return a<b?a:b; }
struct Interval
{
    int l,r,len;
    bool operator < (const Interval & t) const
    {
        return len<t.len;
    }
}a[N];
int b[N*4],c[N*16],lz[N*16],ans=INF,n,m,k;
inline void push_down(int rt)
{
    if(lz[rt])
    {
        c[lson]+=lz[rt];
        c[rson]+=lz[rt];
        lz[lson]+=lz[rt];
        lz[rson]+=lz[rt];
        lz[rt]=0;
    }
}
inline void push_up(int rt)
{
    c[rt]=Max(c[lson],c[rson]);
}
void update(int rt,int l,int r,int ql,int qr,int v)
{
    if(ql<=l&&qr>=r)
    {
        lz[rt]+=v;
        c[rt]+=v;
        return ;
    }
    push_down(rt);
    int m=(l+r)>>1;
    if(ql<=m) update(lson,l,m,ql,qr,v);
    if(qr>m)  update(rson,m+1,r,ql,qr,v);
    push_up(rt);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i)
    {
        scanf("%d%d",&a[i].l,&a[i].r);
        b[k++]=a[i].l;
        b[k++]=a[i].l+1;
        b[k++]=a[i].r;
        b[k++]=a[i].r+1;
        a[i].len=a[i].r-a[i].l+1;
    }
    sort(b,b+k);
    k=unique(b,b+k)-b;
    for(int i=0;i<n;++i)
    {
        a[i].l=lower_bound(b,b+k,a[i].l)-b+1;
        a[i].r=lower_bound(b,b+k,a[i].r)-b+1;
    }
    sort(a,a+n);
    int l=0,r=0;
    for(;r<n;++r)
    {
        update(1,1,k,a[r].l,a[r].r,1);
        if(c[1]>=m)
        {
            while(c[1]>=m) update(1,1,k,a[l].l,a[l].r,-1),++l;
            ans=Min(ans,a[r].len-a[l-1].len);
        }
    }
    printf("%d\n",ans==INF?-1:ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值