想到了一个二分 + 线段树检验的方法. 就是二分长度, 然后用线段树记录最小&最大值, 暴力扫一遍查询.
但是这样复杂度貌似是 (O(N(logN)^2)) 的, 太菜了.
按照以往的经验, 凡是想到这样的思路多半可以用单调队列优化, 一个队列维护最小值, 一个维护最大值就ok.
#include <cstdio>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> P;
const int MAXN = 100000 + 10;
const int MAXD = 1000000 + 10;
inline int read(){
char ch = getchar(); int x = 0;
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
return x;
}
int N, D;
P a[MAXN], lim[MAXD];
int qmin[MAXD], qmax[MAXD];
inline bool check(int x, int len) {
int lmin = 1, lmax = 1, rmin = 0, rmax = 0;
for(int i = 1; i <= len; i++) {
while(lmin <= rmin && (i - qmin[lmin]) > x) ++lmin;
while(lmax <= rmax && (i - qmax[lmax]) > x) ++lmax;
while(lmin <= rmin && lim[qmin[rmin]].first > lim[i].first) --rmin;
while(lmax <= rmax && lim[qmax[rmax]].second < lim[i].second) --rmax;
qmin[++rmin] = i, qmax[++rmax] = i;
if(lim[qmax[lmax]].second - lim[qmin[lmin]].first >= D) return true;
}
return false;
}
int main(){
// freopen("p2698.in", "r", stdin);
cin>>N>>D;
for(int i = 1; i <= N; i++)
a[i].first = read(), a[i].second = read();
int len = 0;
for(int i = 1; i <= N; i++) len = max(len, a[i].first);
for(int i = 1; i <= len; i++) lim[i] = P((1 << 30), 0);
for(int i = 1; i <= N; i++)
lim[a[i].first].first = min(lim[a[i].first].first, a[i].second),
lim[a[i].first].second = max(lim[a[i].first].second, a[i].second);
int l = 0, r = len + 1;
while(l < r) {
int mid = (l + r) >> 1;
if(check(mid, len)) r = mid;
else l = mid + 1;
}
if(l == len + 1) puts("-1");
else printf("%d
", l);
return 0;
}