给定个整数和个询问,对于每个询问给定一个常数k,你需要找到有多少个区间满足序列的内所有元素。注意序列无序。
,显然需要一个高效的算法,首先考虑双指针求解。
首先对于一段区间,如果其区间最大值和区间最小值之差大于,那么当前区间可以产生个符合条件的区间:设分别表示当前区间的最大值、最小值,如果,那么说明该区间一定符合要求,那么包含该区间的区间也一定符合要求(值只会越来越小,值指挥越来越大),因此符合要求的区间数
那么我们可以每次固定区间左端点,右端点向后找到第一个满足区间最大值和区间最小值之差大于的点,然后将符合要求的区间数累加到答案中即可。
接下来考虑如何处理区间最大值最小值。考虑最优RMQ问题解决方案:ST表。因此可以建大小ST表,然后在上述过程中查询。
一开始左指针没控制好,WA了几发,心态爆炸。。。
#include <bits/stdc++.h>
using namespace std;
#define N 2000010
int stmax[N][22], stmin[N][22], mn[N];
int a[N];
int t, q, n, x, y;
void init(){
mn[0]=-1;
for (int i=1;i<=n;i++){
mn[i]=((i & (i-1))==0) ? mn[i-1]+1 : mn[i-1];
stmax[i][0]=stmin[i][0]=a[i];
}
for (int j=1;j<=mn[n];j++)
for (int i=1;i+(1<<j)-1<=n;i++){
stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<(j-1))][j-1]);
stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<(j-1))][j-1]);
}
}
int rmq_max(int L,int R){
int k=mn[R-L+1];
return max(stmax[L][k],stmax[R-(1<<k)+1][k]);
}
int rmq_min(int L,int R){
int k=mn[R-L+1];
return min(stmin[L][k],stmin[R-(1<<k)+1][k]);
}
signed main(){
cin >> n >> q;
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
init();
while (q--){
int k = 0; cin >> k;
long long ans = 0;
int l = 1, r = 0, maxn, minn;
while(l <= n){
r = max(r, l);
maxn = rmq_max(l, r), minn = rmq_min(l, r);
while (maxn - minn <= k && r < n) {
r++;
maxn = max(maxn, a[r]), minn = min(minn, a[r]);
}
if (maxn - minn > k) ans += n - r + 1;
l++;
}
cout << ans << endl;
}
return 0;
}