题意:
给一个整数序列,多达10万个。问:有多少个区间满足“区间最大元素与最小元素之差不超过k“
解析:
如果用穷举法,有 O(n2) 复杂度,这肯定是不可取的。
所以可以用ST算法先预处理每个区间最大和最小值, O(nlog(n)) 。
注意一个区间固定起点,延长终点,那么这个区间的最大值和最小值的差肯定是单调递增的。
所以这题用双指针的方法,枚举右指针 rp ,用左指针 lp 向前移动,求出满足 rmq(lp,rp)<k ,且 lp 和 rp 最大的区间,统计 ans+=(rp−lp+1) 。因为在 [lp,rp] 这个区间是满足要求的,那么以 rp 为结尾的, [lp,rp] 、 [lp+1,rp] … [rp−1,rp] 、 [rp,rp] 就都是满足要求的,刚好 (rp−lp+1) 个。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef __int64 ll;
const int N = 100005;
int A[N];
int n, K;
int maxv[N*2][20], minv[N*2][20];
void rmq_init() {
for(int i = 1; i <= n; i++) {
maxv[i][0] = minv[i][0] = A[i];
}
for(int j = 1; (1<<j) <= n; j++) {
for(int i = 1; i + (1<<j) - 1 <= n; i++) {
maxv[i][j] = max(maxv[i][j-1], maxv[i + (1<<(j-1))][j-1]);
minv[i][j] = min(minv[i][j-1], minv[i + (1<<(j-1))][j-1]);
}
}
}
int rmq(int L, int R) {
int len = R - L + 1, k = 0;
while(1 << (k+1) <= len) k++;
int Max = max(maxv[L][k], maxv[R-(1<<k)+1][k]);
int Min = min(minv[L][k], minv[R-(1<<k)+1][k]);
return Max - Min;
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &K);
for(int i = 1; i <= n; i++) {
scanf("%d", &A[i]);
}
rmq_init();
int lp = 1;
ll ans = 0;
for(int rp = 1; rp <= n; rp++) {
while(rmq(lp, rp) >= K && lp < rp) lp++;
ans += (rp - lp + 1);
}
printf("%I64d\n", ans);
}
return 0;
}