【NOI2016】区间 题解(线段树+尺取法)

题目链接

题目大意:给定$n$个区间$[l_i,r_i]$,选出$m$个区间使它们有一个共同的位置$x$,且使它们产生的费用最小。求最小费用。费用定义为最长的区间长度减去最短区间长度。

-----------------

因为区间顺序改动又不影响答案,我们不妨按照长度排个序。看到数据范围果断离散化。

思考一种最朴素的做法:将排好序的区间逐一加入数轴,看有没有一个点被覆盖的次数$\geq m$。

有的话就统计一下答案,然后将前面加入的数删掉,直到$<m$。

显然用到了尺取法。维护是否有一个点被覆盖的次数可以用线段树。

然后就可以成功A掉此题。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,maxx,b[1000005],cnt,size,head=0,tail=0,ans=0x3f3f3f3f;
struct node
{
    int l,r,len;
}a[500005];
struct tree
{
    int index,l,r,max,lazy;
}tree[4000005];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
bool cmp(node x,node y)
{
    return x.len<y.len;
}
inline void build(int index,int l,int r)
{
    tree[index].l=l;
    tree[index].r=r;
    if (l==r) return;
    int mid=(l+r)>>1;
    build(index*2,l,mid);
    build(index*2+1,mid+1,r);
}
inline void pushdown(int index)
{
    tree[index*2].lazy+=tree[index].lazy;
    tree[index*2+1].lazy+=tree[index].lazy;
    tree[index*2+1].max+=tree[index].lazy;
    tree[index*2].max+=tree[index].lazy;
    tree[index].lazy=0;
}
inline void update(int index,int l,int r,int x)
{
    if (l<=tree[index].l&&tree[index].r<=r)
    {
        tree[index].max+=x;
        tree[index].lazy+=x;
        return;
    }
    if (tree[index].lazy) pushdown(index);
    int mid=(tree[index].l+tree[index].r)>>1;
    if (l<=mid) update(index*2,l,r,x);
    if (r>mid) update(index*2+1,l,r,x);
    tree[index].max=max(tree[index*2+1].max,tree[index*2].max);
}
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;
        b[++cnt]=a[i].l;b[++cnt]=a[i].r;
    }
    sort(b+1,b+cnt+1);
    size=unique(b+1,b+cnt+1)-b-1;
    sort(a+1,a+n+1,cmp);
    for (int i=1;i<=n;i++)
    {
        a[i].l=lower_bound(b+1,b+size+1,a[i].l)-b;
        a[i].r=lower_bound(b+1,b+size+1,a[i].r)-b;
        maxx=max(maxx,a[i].r);
    }
    build(1,1,maxx);
    while(tail<n)
    {
        while(tree[1].max<m&&tail<=n){tail++;update(1,a[tail].l,a[tail].r,1);}
        if (tree[1].max<m) break;
        while(head<=tail&&tree[1].max>=m)
        {
            head++;update(1,a[head].l,a[head].r,-1);
            ans=min(ans,a[tail].len-a[head].len);
        }
    }
    if (ans==0x3f3f3f3f) printf("-1");
    else printf("%d",ans);
    return 0;
}

 

posted @ 2020-07-20 18:31  我亦如此向往  阅读(148)  评论(0编辑  收藏  举报