51Nod 1275 双指针 + 双端队列

题目链接


题意:
给定一个数组 a 和一个整数 k ,问有多少个连续区间的最大值和最小值的差不大于 k


思路:
首先对于固定起点的连续区间,随着终点的增大,其区间最大值一定非递减,区间最小值一定非递增,故区间最大值和最小值的差一定是非递减的。
故可以利用双指针来快速求出合法区间的个数。

但该过程还需要快速求出区间最小值和最大值,故使用双端队列来实现滑动窗口。
保持队列的单调性,同时维护队首元素始终有效。
此题得解。


代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define lson rt<<1
#define rson rt<<1|1

const int INF = 1e9 + 7;
const int A = 1e5 + 10;
int N,K,a[A];
int que_Mx[A], que_Mn[A];
int Ln,Rn,Lx,Rx;

int main(){
    scanf("%d%d",&N,&K);
    for(int i = 1; i <= N; i++){
        scanf("%d",&a[i]);
    }

    int st = 1,ed = 1;
    Ln = Rn = Lx = Rx = 0;
    ll ans = 0;
    while(st<=N){
        while(ed <= N){
            while(Ln < Rn && a[que_Mn[Rn]] >= a[ed]) Rn--;
            while(Lx < Rx && a[que_Mx[Rx]] <= a[ed]) Rx--;
            que_Mn[++Rn] = que_Mx[++Rx] = ed;
            if(a[que_Mx[Lx+1]] - a[que_Mn[Ln+1]] > K) break;
            ed++;
        }
        ans += 1LL*(ed - st);
        if(que_Mx[Lx+1] == st) Lx++;
        if(que_Mn[Ln+1] == st) Ln++;
        st++;
    }
    printf("%I64d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wubaizhe/article/details/81009370