洛谷 2698 题解

这是一篇关于洛谷第2698题的题解,主要讲解如何利用单调队列来解决寻找满足条件的最小区间长度的问题。题目要求在给定点集(x, y)中找到一段x上的区间,使得该区间内点的y值最大值与最小值之差大于等于d,同时区间长度最小。通过分析,作者指出可以利用单调队列的性质,不断更新满足条件的最小区间。在维护单调不减的队列过程中,不断检查是否能进一步缩小区间长度,并更新答案。最后给出实现代码。" 111219790,10297402,深度学习目标检测:从RCNN到Faster RCNN,"['深度学习', '目标检测', '卷积神经网络', 'Faster RCNN']

题意简述

给定n,dn,dn,d,以下nnn行每行x,yx,yx,y,表示(x,y)(x,y)(x,y)上有一点。请选择一段xxx上的区间,使得这段区间内的点的yyy值最大-最小>=d>=d>=d,并且是这段区间长度最小。

数据

输入
4 5
6 3
2 4
4 10
12 15
输出
2

思路

一看就是个单调队列。前几天单调队列开窍了,趁着开窍赶快写一篇题解。

我们会发现,假设我们现在正在考虑[l,r][l,r][l,r]之内的点(离散化之后),其中[l,r][l,r][l,r]是一段满足条件的区间。现在我们要转移到[∗,r+1][*,r+1][,r+1]的位置,并且[∗,r+1][*,r+1][,r+1]也满足条件,那么我们一定要取使[l,r+1][l,r+1][l,r+1]满足条件并且[l+1,r+1][l+1,r+1][l+1,r+1]不满足条件的lll(即满足条件且离rrr最近的lll)来更新答案。至于为什么取最近。。。因为我们要区间长度最小嘛。

那么就珂以用单调队列优化了。毕竟不是所有点都要考虑的,我们只要维护一个单调不减的队列,那么第一个(Q[head]Q[head]Q[head])就是最小,最后一个(Q[tail−1]Q[tail-1]Q[tail1])就是最大。然后我们每次加入一个点,维护好单调性。如果此时我们的队列的长度珂以继续缩小,那么就缩小,一边缩小,一边更新最小答案。最后输出答案。

代码:

#include<bits/stdc++.h>
#define N 1001000
using namespace std;
namespace Flandle_Scarlet
{
    struct node
    {
        int x,y;
    }a[N];
    bool operator<(node x,node y)
    {
        return x.x<y.x;//按x排序
    }
    int n,d;
    void Input()
    {
        scanf("%d%d",&n,&d);
        for(int i=1;i<=n;++i)
        {
            scanf("%d%d",&a[i].x,&a[i].y);
        }
        sort(a+1,a+n+1);//千万要记得排序。。。
    }

    node Q[N];
    int head,tail;
    void Solve()
    {
        head=tail=1;//初始化队列
        int ans=0x3f3f3f3f;//由于要求最小,所以答案一开始是INF
        Q[tail++]=a[1];
        for(int i=2;i<=n;++i)//枚举右端点
        {
            while(head<tail and Q[tail-1].y>a[i].y) --tail;
            Q[tail++]=a[i];//加入队列

            while(head<tail and Q[tail-1].y-Q[head].y>=d)
            //如果区间能缩小
            {
                ans=min(ans,Q[tail-1].x-Q[head].x);
                //更新答案
                ++head;
                //缩小
            }
        }
        printf("%d\n",ans==0x3f3f3f3f?-1:ans);
        //记得判误解(为了这个送一次WA)
    }

    void Main()
    {
        Input();
        Solve();
    }
}
int main()
{
    Flandle_Scarlet::Main();
    return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值