思路: 排序+rmq+二分
按x排序,对每个关键部门 二分可以延伸的位置 (二分的时候判定条件要缩一下,因为h最大值为20,可以设判定为d -40 ),然后继续往右延伸到(大概d+40)就可以退出了,
#include <iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=200000*2;
int h[maxn];
struct point{
int x,y;
}p[maxn];
bool cmp(const point &e1,const point &e2){
return e1.x <e2.x ;
}
int dp[maxn][22];
int mm[maxn];
int n,d,m;
void initrmq(int n,int h[]){
mm[0]=-1;
for(int i=1;i<=n;i++){
mm[i]=((i&(i-1))==0) ? mm[i-1]+1:mm[i-1];
dp[i][0]=h[i];
}
for(int j=1;j<=mm[n];j++){
for(int i=1;i+(1<<j)-1<=n;i++){
dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int rmq(int x,int y){
int k=mm[y-x+1];
return min(dp[x][k],dp[y-(1<<k)+1][k]);
}
int check(int x,int mid){
int tmp=min(p[x].y,p[mid].y);
if(p[mid].x-1>=p[x].x+1){
tmp=min(tmp,rmq(p[x].x+1,p[mid].x-1));
}
int len= p[x].y-tmp + p[mid].y-tmp+p[mid].x-p[x].x;
if(len<=d-42){
return 1;
}
return 0;
}
int main()
{
// cout << "Hello world!" << endl;
if(fopen("H:\\acm.txt","r")!=NULL)
{
freopen("H:\\acm.txt","r",stdin);
}
while(scanf("%d%d",&n,&d)!=EOF){
for(int i=1;i<=n;i++){
scanf("%d",&h[i]);
}
initrmq(n,h);
cin>>m;
for(int i=1;i<=m;i++){
scanf("%d%d",&p[i].x ,&p[i].y);
}
sort(p+1,p+m+1,cmp);
ll ans=0;
for(int i=1;i<=m;i++){
int l=i,r=m,res=l;
while(l<=r){
int mid=(l+r)>>1;
if(check(i,mid)){
l=mid+1;
res=mid;
}else{
r=mid-1;
}
}
ans+=res-i;
for(int k=res+1;k<=m;k++){
int tmp=min(p[i].y,p[k].y);
if(p[k].x-1>=p[i].x+1){
tmp=min(tmp,rmq(p[i].x+1,p[k].x-1));
}
int len= p[i].y-tmp + p[k].y-tmp+p[k].x-p[i].x;
if(len<=d){
ans++;
}
if(len>=d+142){
break;
}
}
}
cout<<ans<<endl;
}
return 0;
}