题面描述
思路
观察完题意之后,我们看到最小
就会想到二分枚举花盆长度 x x x,需要用两个队列来维护最大值与最小值。
我们检测 [ i , i − x + 1 ] [i,i-x+1] [i,i−x+1]中是否有两个水滴下落时间之差是否 ≥ D \ge D ≥D(考虑取纵坐标之差极值)
那么我们往右移一个单位区间变为 [ i + 1 , i − x + 2 ] [i+1,i-x+2] [i+1,i−x+2],继续检测。
由于具有单调性,所以我们可以用单调队列优化这个过程。
先将横坐标排序。
bool cmp(node a,node b){return a.x<b.x;}
判断两个雨滴是否可以被接到
while(l1<=r1&&a[i].x-a[q1[l1]].x>x)++l1;
while(l2<=r2&&a[i].x-a[q2[l2]].x>x)++l2;
我们需要比较在合法前提下,也就是在队列中,时间最长的雨滴与时间最短的雨滴之差,是否
大于
D
D
D
if(a[q1[l1]].y-a[q2[l2]].y>=d)
进入队列的最优状态
while(l1<=r1&&a[q1[r1]].y<=a[i].y)--r1;
while(l2<=r2&&a[q2[r2]].y>=a[i].y)--r2;
关于最大值的维护,如果队尾的值比当前值还小,而且队尾的位置一定在现在位置之前,那么对后面状态的贡献小于当前位置,可以踢出队尾。
最小值的维护类似。
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define gc getchar()
using namespace std;
const int N=1e6+10;
inline int mymin(int x,int y){return x<y?x:y;}
inline int mymax(int x,int y){return x>y?x:y;}
inline void qr(int &x)
{
x=0;char c=gc;
while(c<'0'||c>'9')c=gc;
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
}
void qw(int x)
{
if(x/10)qw(x/10);
putchar(x%10+48);
}
struct node{int x,y;}a[N];
bool cmp(node a,node b){return a.x<b.x;}
int q1[N],q2[N],l1,r1,l2,r2,n,d;
bool check(int x)
{
l1=r1=l2=r2=1;q1[1]=q2[1]=0;
for(int i=1;i<=n;i++)
{
while(l1<=r1&&a[i].x-a[q1[l1]].x>x)++l1;
while(l2<=r2&&a[i].x-a[q2[l2]].x>x)++l2;
while(l1<=r1&&a[q1[r1]].y<a[i].y)--r1;
while(l2<=r2&&a[q2[r2]].y>a[i].y)--r2;
q1[++r1]=i,q2[++r2]=i;
if(a[q1[l1]].y-a[q2[l2]].y>=d)return true;
}
return false;
}
int main()
{
qr(n),qr(d);int l=1e9,r=0;
for(int i=1;i<=n;i++)qr(a[i].x),qr(a[i].y),l=mymin(l,a[i].y),r=mymax(r,a[i].y);
r=r-l;l=0;
if(r<d)
{
puts("-1");return 0;
}
sort(a+1,a+n+1,cmp);
r=a[n].x-a[1].x;
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
qw(l);puts("");
return 0;
}