假设右端点r固定,那么如果能找到离得最远的一个l,使l到r满足要求,那么[l+1~r],[l+2~r].....都满足要求。所以可以枚举右端点,去找最远的满足条件的左端点,使满足条件,答案就是把这些长度求和。
因为序列是静态的,所以可以用ST算法在log n时间求出任意区间内的最大,最小值,然后用这些值二分求解最远的l。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define LL long long
int N,k;
int a[100005];
int mx[100005][20];
int mi[100005][20];
void RMQ_init(){
for(int i=0;i<N;i++){
mx[i][0]=a[i];
mi[i][0]=a[i];
}
for(int j=1;(1<<j)<=N;j++){
for(int i=0;i+(1<<j)-1<N;i++){
mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
}
}
}
int RMQx(int L,int R){
int k=0;
while((1<<(k+1)) <=R-L+1) k++;
return max(mx[L][k],mx[R-(1<<k)+1][k]);
}
int RMQi(int L,int R){
int k=0;
while((1<<(k+1)) <=R-L+1) k++;
return min(mi[L][k],mi[R-(1<<k)+1][k]);
}
int BS(int pos){
int l=0,r=pos;
int res=pos;
while(r>=l){
int mid=(l+r)/2;
if(RMQx(mid,pos)-RMQi(mid,pos)<k){
res=mid;
r=mid-1;
}
else l=mid+1;
}
return res;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&N,&k);
for(int i=0;i<N;i++){
scanf("%d",&a[i]);
}
RMQ_init();
LL res=0;
for(int i=0;i<N;i++){
//cout<<px<<' '<<pi<<endl;
int pos=BS(i);
res+=(i-pos+1);
}
printf("%I64d\n",res);
}
return 0;
}