单调队列学习前提需知
单调队列一般用于一类优化中,比如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;
}