1 条题解

  • 0
    @ 2025-8-24 21:28:14

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 上进的z君
    **

    搬运于2025-08-24 21:28:13,当前版本为作者最后更新于2016-09-15 18:17:07,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    首先分析一下题目,l,r这么大很显然就是要离散化了。

    接着我们又注意到题目要求的答案跟“最大”,“最小”有关,所以我们就会联想到单调性。

    既然是跟区间长度有关,那我们不妨就先按区间长度排个序好了,反正这样子并不会影响答案。

    然后我们思考一种最朴素的做法,那就是按排序后的顺序逐一加入区间,然后看看是否有 一个点的被覆盖次数>=m。

    如果有的话那就统计一下答案,然后将前面加入的按顺序删掉,直到<m。

    重复上诉的过程。

    很显然这利用了尺取法的思想。

    那么问题就是我们如何快速地得知是否有 一个点的被覆盖次数>=m。

    那就很显然维护一棵线段树就好了。

    于是这题就成功解决。

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<stack>
    #include<queue>
    using namespace std;
    const int maxn=501000;
    const int INF=1e9;
    struct Point{
        int val,ord;
    }p[maxn*4];
    struct Data{
        int len,ord;
    }a[maxn*4];
    int L[maxn*2],R[maxn*2],n,m,Right,cur=0;
    int tree[maxn*8],add[maxn*8];
    bool Cmp1(Point x1,Point x2){
        if(x1.val<x2.val)return true;
        return false;
    }
    bool Cmp2(Data x1,Data x2){
        if(x1.len<x2.len)return true;
        return false;
    }
    void Down(int rt,int l,int r){
        if(!add[rt])return;
        int ls=rt*2,rs=rt*2+1;
        tree[ls]+=add[rt];
        tree[rs]+=add[rt];
        add[ls]+=add[rt];
        add[rs]+=add[rt];
        add[rt]=0;
        return;
    }
    void Update(int rt,int l,int r,int x,int y,int val){
        if(x>r||y<l)return;
        if(x<=l&&y>=r){
            tree[rt]+=val;
            add[rt]+=val;
            return;
        }
        int mid=(l+r)/2;
        Down(rt,l,r);
        Update(rt*2,l,mid,x,y,val);
        Update(rt*2+1,mid+1,r,x,y,val);
        tree[rt]=max(tree[rt*2],tree[rt*2+1]);
        return;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            a[i].len=v-u;
            a[i].ord=i;
            cur++;
            p[cur].val=u;
            p[cur].ord=i;
            cur++;
            p[cur].val=v;
            p[cur].ord=i;
        }
        sort(p+1,p+cur+1,Cmp1);
        int num=0;
        p[0].val=-1;
        for(int i=1;i<=cur;i++){
            if(p[i].val!=p[i-1].val)
            num++;
            int u=p[i].ord;
            if(!L[u])
            L[u]=num;
            else R[u]=num;
        }
        Right=num;
        sort(a+1,a+n+1,Cmp2);
        int ans=INF,le=0,ri=0;
        while(true){
            while(tree[1]<m&&ri<=n){
                ri++;
                int u=a[ri].ord,v=L[u],w=R[u];
                Update(1,1,Right,v,w,1);
            }
            if(tree[1]<m)break;
            while(tree[1]>=m&&le<=n){
                le++;
                int u=a[le].ord,v=L[u],w=R[u];
                Update(1,1,Right,v,w,-1);
            }
            ans=min(ans,a[ri].len-a[le].len);
        }
        if(ans==INF)printf("-1\n");
        else
        printf("%d\n",ans);
        return 0;
    }
    
    • 1

    信息

    ID
    690
    时间
    1000~3000ms
    内存
    250MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者