『单调队列』单调队列板子

单调队列学习前提需知

单调队列一般用于一类优化中,比如dp优化,或者二分的一系列题中,单调队列相比于同类型的单调栈而言,适用范围更广,考的范围也更广。单调队列是在一个长度为\(n\)的数列中,找到连续\(m\)个数,很快的求出其最大最小值

算法内容

竞赛需要用到胡点

1、单调队列一般用于优化或者二分答案的判定中

2、单调队列适用范围很广,建议集中练习

单调队列求区间最大最小值略讲

单调队列类似于一个双端队列的结构,其满足队列的从尾进从头出,也满足双端队列的从头出可以,从尾出也可以的形式,令进入的数有两个值,第一个值是进入的数本身有值,第二个值是进入的数有一个时间表示多久进入的,那么一定会满足的是,当当前数的价值大于(小于)队列中的从队尾开始的数时,那么就可以直接将队尾的数踢出,直到队列为空或者队列中有数大于(小于)当前的数为止,或者在队列的队首的时间已经在考虑区域外了了,那么我们就将队首弹出。通过这个思路,代码似乎就出来了

比如我们求区间最小值,那么我们可以得到以下代码

int front = 1, back = 0;
    for (int i = 1; i <= n; i++) { 
        if(q[front].idx + m < i) front++; //判断队首是否越界
        while(front <= back && q[back].x >= arr[i]) back--; //查看进入的数是否小于队尾的数
        back++; q[back].idx = i - 1, q[back].x = arr[i];
        if(i >= m) printf("%d ", q[front].x);
    } puts("");

这就是我们的单调队列的整个代码了,以下代码参考滑动窗口

//#define fre yes

#include <cstdio>

int n, m;

const int N = 1000005;
struct Node {
    int idx, x;
} q[N];
int arr[N];

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &arr[i]);
    }
    
    int front = 1, back = 0;
    for (int i = 1; i <= n; i++) {
        if(q[front].idx + m < i) front++;
        while(front <= back && q[back].x >= arr[i]) back--;
        back++; q[back].idx = i - 1, q[back].x = arr[i];
        if(i >= m) printf("%d ", q[front].x);
    } puts("");
    
    front = 1, back = 0;
    for (int i = 1; i <= n; i++) {
        if(q[front].idx + m < i) front++;
        while(front <= back && q[back].x <= arr[i]) back--;
        back++; q[back].idx = i - 1, q[back].x = arr[i];
        if(i >= m) printf("%d ", q[front].x);
    } return 0;
}

猜你喜欢

转载自www.cnblogs.com/Nicoppa/p/11545302.html