P2698 [USACO12MAR]花盆Flowerpot——单调队列

记录每天看(抄)题解的日常;

https://www.luogu.org/problem/P2698

我们可以把坐标按照x递增的顺序排个序,这样我们就只剩下纵坐标了;

如果横坐标(l,r)区间,纵坐标的最大值减去最小值大于d,那么就可以更新答案;

看出随着l的增长,r一定是递增的;

可以证明不存在(l2,r2),l2>l1且r2<r,(maxy-miny)>d,且能对答案造成影响;

因为如果有这种存在,那么r2应该是l第一个匹配的对象,是更优的答案;

 

这就涉及到滑动窗口方法了;

用q1[]记录纵坐标最大值的位置,q2[]记录纵坐标最小值的位置;

范围是l到r;

更新队列区间范围:

while(h1<=t1&&q1[h1]<l) h1++;
while(h2<=t2&&q2[h2]<l) h2++;

 

更新r,最大值,最小值;

    while(a[q1[h1]].y-a[q2[h2]].y<d&&r<n)
        {
            ++r;
            while(a[q1[t1]].y<a[r].y&&h1<=t1) t1--;
            q1[++t1]=r;
            while(a[q2[t2]].y>a[r].y&&h2<=t2) t2--;
            q2[++t2]=r;
        }

 

 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
int q1[maxn],q2[maxn],h1=1,h2=1,t1,t2;
int n,d;
struct node
{
    int x,y;
}a[maxn];
bool cmp(node qw,node we)
{
    return qw.x<we.x;
}
int ans=2147483647;
int main()
{
    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,cmp);
    for(int l=1,r=0;l<=n;l++)
    {
        while(h1<=t1&&q1[h1]<l) h1++;
        while(h2<=t2&&q2[h2]<l) h2++;
        while(a[q1[h1]].y-a[q2[h2]].y<d&&r<n)
        {
            ++r;
            while(a[q1[t1]].y<a[r].y&&h1<=t1) t1--;
            q1[++t1]=r;
            while(a[q2[t2]].y>a[r].y&&h2<=t2) t2--;
            q2[++t2]=r;
        }
        if(a[q1[h1]].y-a[q2[h2]].y>=d) ans=min(ans,a[r].x-a[l].x); 
    }
    if(ans==2147483647) printf("-1");
    else printf("%d",ans);
    return 0;
}

 

posted @ 2019-09-25 21:48  AiRomance  阅读(131)  评论(0编辑  收藏  举报