传送门

看到求最小,考虑二分答案

发现二分答案后直接搞两个单调队列维护最大最小值就好了

然后就没有然后了

话说这题也可以用尺取法动态维护左右区间$O(n)$过...

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=2e6+7,INF=1e9+7;
int n,D,ans=INF;
struct Poi{
    int x,y;
    inline bool operator < (const Poi &tmp) const {
        return x!=tmp.x ? x<tmp.x : y<tmp.y;
    }
}d[N];
int qa[N],qb[N],la,ra,lb,rb;
inline bool check(int p)
{
    la=lb=1,ra=rb=0;
    for(int i=1;i<=n;i++)
    {
        while( d[i].x-d[qa[la]].x>p && la<=ra ) la++;
        while( d[i].x-d[qb[lb]].x>p && lb<=rb ) lb++;
        while( d[i].y<=d[qa[ra]].y && la<=ra ) ra--;
        while( d[i].y>=d[qb[rb]].y && lb<=rb ) rb--;
        qa[++ra]=i; qb[++rb]=i;
        if( d[qb[lb]].y-d[qa[la]].y >=D) return 1;
    }
    return 0;
}
int main()
{
    n=read(),D=read();
    for(int i=1;i<=n;i++) d[i].x=read(),d[i].y=read();
    sort(d+1,d+n+1);
    int L=1,R=d[n].x-d[1].x,mid;
    while(L<=R)
    {
        mid=L+R>>1;
        if(check(mid)) R=mid-1,ans=mid;
        else L=mid+1;
    }
    printf("%d",ans < INF ? ans : -1);
    return 0;
}