洛谷1712 [NOI2016]区间

算法竞赛 数据结构-线段树
编辑文章

题意

有 $n(\le 5\times 10^5)$ 个区间,要从中选出 $m(\le 2\times 10^5)$ 个区间,要求存在一个点被覆盖了 $m$ 次,求最大区间长度与最小区间长度差值 的最小值。

题解

贪心,将所有区间按长度从小到大排序,答案一定是一段连续的区间。所以可以用线段树维护覆盖的次数,然后尺取法不断取被覆盖次数最大为 $m$ 的一段并更新答案。

需要离散化预处理。需要注意区间长度是原来区间的长度而不是离散化后的区间长度。

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    char ch=getchar(); int f=1,x=0;
    while (ch<'0' || ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
    while (ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
    return f*x;
}

const int N=500005;
struct Tree {
    int left,right,mx,delta;
} tree[N<<3];
struct node {
    int s,id,len;
} s[N<<1];
struct node2 {
    int l,r,len;
} x[N];
int n,m;

inline bool cmp1(node x,node y) { return x.s<y.s; }

inline bool cmp2(node2 x,node2 y) { return x.len<y.len; }

inline void pushup(int x) { tree[x].mx=max(tree[x<<1].mx,tree[x<<1|1].mx); }

inline void pushdown(int x)
{
    tree[x<<1].mx+=tree[x].delta;
    tree[x<<1|1].mx+=tree[x].delta;
    tree[x<<1].delta+=tree[x].delta;
    tree[x<<1|1].delta+=tree[x].delta;
    tree[x].delta=0;
}

void build(int x,int l,int r)
{
    tree[x].left=l;
    tree[x].right=r;
    if (r-l>1)
    {
        int mid=(l+r)>>1;
        build(x<<1,l,mid);
        build(x<<1|1,mid,r);
    }
}

void add(int x,int l,int r,int delta)
{
    if (l<=tree[x].left && r>=tree[x].right)
    {
        tree[x].mx+=delta;
        tree[x].delta+=delta;
    }
    else
    {
        if (tree[x].delta) pushdown(x);
        int mid=(tree[x].left+tree[x].right)>>1;
        if (l<mid) add(x<<1,l,r,delta);
        if (r>mid) add(x<<1|1,l,r,delta);
        pushup(x);
    }
}

signed main()
{
    n=read(); m=read();
    for (int i=1;i<=n;i++)
    {
        s[(i<<1)-1].s=read();
        s[i<<1].s=read();
        s[(i<<1)-1].id=s[i<<1].id=i;
        s[(i<<1)-1].len=s[i<<1].len=s[i<<1].s-s[(i<<1)-1].s;
    }
    n<<=1;
    sort(s+1,s+n+1,cmp1);
    int cnt=0;
    s[0].s=-1;
    for (int i=1;i<=n;i++)
    {
        if (s[i].s!=s[i-1].s) cnt++;
        if (!x[s[i].id].l) x[s[i].id].l=cnt;
        else x[s[i].id].r=cnt,x[s[i].id].len=s[i].len; //离散化
    }
    n>>=1;
    sort(x+1,x+n+1,cmp2); //按长度排序
    build(1,1,cnt+1);
    int ans=1e9;
    for (int l=0,r=0;l<=n;)
    {
        for (;r<=n && tree[1].mx<m;r++,add(1,x[r].l,x[r].r+1,1));
        if (r>n) break;
        for (;l<r && tree[1].mx>=m;l++,add(1,x[l].l,x[l].r+1,-1));
        ans=min(ans,x[r].len-x[l].len);
    }
    if (ans==1e9) return 0&puts("-1");
    return !printf("%d",ans);
}

新评论

称呼不能为空
邮箱格式不合法
网站格式不合法
内容不能为空