单调队列学习笔记(还是再回首)

单调队列的应用很常见,比如用于dp优化,以及滑动窗口问题等。

其思想也比较简单易懂。我们以求区间最大值的单调队列为例。

具体的来讲,我们让队头始终是最大的元素。为了保证数都在区间内,我们记录一个 t 数组。该数组表示某个元素加入的时间。我们每次将新元素(设为 x)入队时,先将队头超时的元素弹出。然后,将队尾小于 x 的元素全部弹走。可以这样想: x 是新加入的元素,比队尾的元素时间要短;而 x 比这些元素大,因此,队尾小于 x 的元素不会对答案产生任何贡献。这样,我们就维护好一个单调队列了。

代码(这里最大值和最小值都求出来了):

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+100;
int lmx = 1, rmx, lmn = 1, rmn;
int tmx[N], tmn[N];
int qmx[N], qmn[N];
int a[N];
int n, K;
void push_mx(int x, int t){
while(tmx[lmx]<=t-K&&lmx<=rmx){
lmx++;
}
while(qmx[rmx]<=x&&lmx<=rmx){
rmx--;
}
qmx[++rmx] = x;
tmx[rmx] = t;
}
void push_mn(int x, int t){
while(tmn[lmn]<=t-K&&lmn<=rmn){
lmn++;
}
while(qmn[rmn]>=x&&lmn<=rmn){
rmn--;
}
qmn[++rmn] = x;
tmn[rmn] = t;
}
int main(){
scanf("%d%d", &n, &K);
for(int i = 1; i<= n; i++){
scanf("%d", &a[i]);
}
for(int i = 1; i<=n; i++){
push_mn(a[i], i);
if(i>=K){
printf("%d ", qmn[lmn]);
}
}
putchar('\n');
for(int i = 1; i<=n; i++){
push_mx(a[i], i);
if(i>=K){
printf("%d ", qmx[lmx]);
}
}
system("pause");
return 0;
}
posted @   霜木_Atomic  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示