题目
此题,他说用线段树,但我发现只要二分答案+two pointers,
二分出答案后,维护区间最大值最小值,来验证答案是否合法。
维护区间最小,就是维护最长不下降子序列。(因为,有比当前小的,直接替代了)
维护区间最大,就是维护最长不上升子序列。(有比当前大的,也直接替代了)
#include<iostream>
#include<cstdio>
using namespace std;
int n,d,num;
int q1[2000000],q2[2000000];
int a1[2000000],a2[2000000];
bool check(int x){
int head1=0,tail1=0;
int head2=0,tail2=0;
q1[0]=0;
q2[0]=0;
for (int i=0;i<=num;++i){
if (a1[i]!=0){
while (head1<tail1&&a1[q1[tail1-1]]>=a1[i])--tail1;
q1[tail1]=i;++tail1;
}
while (head1<tail1&&q1[head1]<i-x) ++head1;
if (a2[i]!=0){
while (head2<tail2&&a2[q2[tail2-1]]<=a2[i])--tail2;
q2[tail2]=i;++tail2;
}
while (head2<tail2&&q2[head2]<i-x) ++head2;
if (i>=x){
//cout<<a[q2[head2]]<<" "<<a[q1[head1]]<<endl;
if (a2[q2[head2]]-a1[q1[head1]]>=d) return true;
}
}
return false;
}
int main(){
scanf("%d%d",&n,&d);
num=0;
for (int i=1;i<=n;++i){
int x,y;
scanf("%d%d",&x,&y);
if (a1[x]==0)
a1[x]=y;
else a1[x]=min(a1[x],y);
a2[x]=max(a2[x],y);
num=max(num,x);
}
int l=0,r=num;
while (l<r){
int mid=(l+r)/2;
if (check(mid)==true) r=mid;
else l=mid+1;
}
if (check(r)==true) printf("%d\n",r);
else printf("-1\n");
return 0;
}