题目描述:
题目给你一个长度为n的序列,m次询问,每次询问给一个k,寻找有多少个区间【l,r】满足区间内的数组最大值减数组最大值大于k(不等于k)
思路分析:
我们给定一个i,为满足条件的区间左边界。然后往后找右区间边界,我们令j为区间右边界,而我们只需要找出这个区间内满足条件的最小j即可,因为这个j后面的右边界都满足条件。而我们可以用两个单调队列分别来维护这个区间内最小值和最大值。
AC代码:

#include<bits/stdc++.h>
using namespace std;
int m,n,k;
long long ans;
int mm,mx,mi,xi;
int a[100005],maxi[100005],mini[100005];//mini为维护最小值得递增队列,maxi为维护最大值的递减队列
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    while(m--){
        ans=0;
        cin>>k;
        mm=mx=mi=xi=1;//mm,mx,mi,xi分别是maxi队首队尾和mini队首队尾
        maxi[1]=mini[1]=1;
        int j=1;
        for(int i=1;i<=n;i++){
            if(maxi[mx]<i)mx++;
            if(mini[mm]<i)mm++;
            while(j<i||a[maxi[mx]]-a[mini[mm]]<=k){
                if(j==n)break;
                j++;
                while(xi>=mx&&a[maxi[xi]]<a[j])--xi;//维护单调递减队列
                while(mi>=mm&&a[mini[mi]]>a[j])--mi;//维护单调递增队列
                maxi[++xi]=j;
                mini[++mi]=j;
            }
            if(a[maxi[mx]]-a[mini[mm]]<=k)break; 
            ans+=n-j+1;//j后面的所有右区间都满足条件         
        }
        cout<<ans<<endl;
    }
    return 0;
}