LuoguP2698 【[USACO12MAR]花盆Flowerpot】

题目描述

首先我们简化一下题意:

要找一段区间[L,R],使区间[L,R]内元素最大值减最小值大于等于D。

做法:

首先很容易想到采用二分,分什么呢?

我们二分区间长度为mid

这个时候,检验就成为了我们的目标

最暴力的检验就是枚举左端点,在区间内找最大和最小,有一个max-min>=D

让我们模拟一下:

假如mid=2:

(1) [1,3]

(2) [2,4]

(3) [3 5]

(4) .....

我们震惊的发现:P1886 滑动窗口

这貌似有点相似

于是正解出现了

正解:

二分区间长度为mid,检验时用单调队列维护区间最大最小值,复杂度nlogn,更多细节见代码:

代码时间到:

#include<bits/stdc++.h>
using namespace std;
int n,D,l,r;
struct WATER{
    int x,y;
}p[100010];
int ans=2100000000;
int q1[100010],q2[100010];
int p1[100010],p2[100010];
int head1=1,tail1=1,head2=1,tail2=1;
bool check(int k){
    int L=1;
    q1[1]=p[1].y;p1[1]=p[1].x;
    q2[1]=p[1].y;p2[1]=p[1].x;
    head1=1,tail1=1,head2=1,tail2=1;
    for(int i=2;i<=n;i++){
        while((p[i].x-p[L].x)>k) L++;
        while(p1[head1]<p[L].x&&head1<=tail1)  
              head1++;
        while(p2[head2]<p[L].x&&head2<=tail2)  
              head2++;
        while(q1[tail1]<=p[i].y&&head1<=tail1) 
              tail1--;
        p1[++tail1]=p[i].x;q1[tail1]=p[i].y;
        while(q2[tail2]>=p[i].y&&head2<=tail2) 
              tail2--;
        p2[++tail2]=p[i].x;q2[tail2]=p[i].y;
        if((q1[head1]-q2[head2])>=D) return 1; 
    }
    return 0;
}
bool cmp(WATER a,WATER b){
    return a.x<b.x;
}
int main(){
    scanf("%d%d",&n,&D);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&p[i].x,&p[i].y);
    l=0,r=1000010;
    sort(p+1,p+n+1,cmp);
    while(l<=r){
        int mid=(l+r)/2;
        if(check(mid)){
            r=mid-1;
            ans=min(ans,mid);
        }
        else l=mid+1;
    }
    if(ans==2100000000) printf("-1");
    else printf("%d",ans);
    return 0;
}

 

posted @ 2019-10-30 18:07  优少  阅读(175)  评论(0编辑  收藏  举报