题目大意:问数组a中,区间[i,j]中最大值和最小值之差不超过k,问这样的区间有多少个。
思路:预处理出区间[i,j]中的最大值最小值(这里用的是ST算法,也有用线段树的),然后枚举左端点l,二分出符合条件的右端点r,以l为左端点,j为右端点(l<=j<=r)的符合条件的集合为(r-l+1)。
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath>
#include<ctime>
#define N 100005
#define LL long long
#define mod 1000000007
#define esp 1e-6
#define y1 y1234
#define INF 0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 200005
const double PI = acos(-1.0);
using namespace std;
int a[N];
int mx[N][21], mi[N][21];
int n, k;
void RMQ(){
for (int j = 1; (1<<j) <= n; j++){
for (int i = 1; i + (1<<j)-1 <= n; i++){
int p = 1 << (j - 1);
mx[i][j] = max(mx[i][j - 1], mx[i + p][j - 1]);
mi[i][j] = min(mi[i][j - 1], mi[i + p][j - 1]);
}
}
}
int q(int i, int j){
int k = log2(j - i + 1.0);
int mma = max(mx[i][k], mx[j - (1 << k) + 1][k]);
int mmi = min(mi[i][k], mi[j - (1 << k) + 1][k]);
return mma - mmi;
}
int main(){
int t;
cin >> t;
while (t--){
cin >> n >> k;
for (int i = 1; i <= n; i++){
scanf("%d", &a[i]);
mx[i][0] = mi[i][0] = a[i];
}
RMQ();
LL ans = 0;
for (int i = 1; i <= n; i++){
int l = i, r = n;
while (l + 1 < r){
int m = (l + r) >> 1;
if (q(i, m) < k)l = m;
else r = m;
}
if (q(i, r) < k)
ans += (r * 1LL - i + 1);
else ans += (l * 1LL - i + 1);
}
cout << ans << endl;
}
return 0;
}