单 于 十 万 貔 貅 拥
调 燮 千 金 一 丈 夫
队 队 鱼 龙 真 乐 事
列 仙 何 必 问 江 湖
单 于 车 骑 来
调 鼎 出 蓬 莱
队 队 人 千 里
列 仙 酒 一 杯
看看这两首诗每句话的开头,连起来就是单调队列,单调队列是一个好东西啊,他在各路算法中间都有极大的用处,特别是用来卡时间,优化算法,所一不学好是不行的啊。
现在开始正式讲一讲单调队列
首先来看一看一道题
滑动窗口
乍一看,不是线段树吗?随随便便就过了,但是速度十分慢,而且这只是训练单调队列的一道题而已
用一个头指针,一个尾指针,模拟,满足每次队列满足单调性。
新的数从尾部加入,如果大于等于前面一个数则弹出前一个数,tail++,直到不满足条件,在尾部放入这个数。
是不是很绕?
现在将它具体化,假设有一个oier在机房颓游戏,导致忘记了它接下来还有课外班,可怜,残酷。等他想起来已经要上课了,于是他飞奔至公交站台,好不容易等到车来了,但是发现上车人太多了。他决定采取一些措施,已知每个人都有一个武力值。如果他的武力值大于前面的人,直接将他扔到后面去,自己则向前一位,如此反复。如果等于,因为他心中有着一个抢座位的信念,所以经过殊死搏斗,还是把那人扔后面去了。
是不是理解了,接下来看代码
代码如下:
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define rg register
using namespace std;
struct node{
int v,x;
}Max[1000001],Min[1000001];
int a[1000001];
inline int read(){
int x=0,c=getchar(),f=1;
while(c<'0'||c>'9')
f= (c=='-')?-1:1,c=getchar();
while(c>='0'&&c<='9')
x=x*10+c-48,c=getchar();
return f*x;
}
inline void print(int x){
if(x<0)
putchar('-'),x=-x;
if(x>9)
print(x/10);
putchar(x%10+'0');
}
int main(){
int n,m;
rg int head=1,tail=1;
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(rg int i=1;i<=n;i++){
while(Min[tail].v>=a[i]&&head<=tail)
tail--;
tail++,Min[tail].x=i,Min[tail].v=a[i];
if(i<m)
continue;
int flag=0;
while(head<=tail){
(Min[head].x>=i-m+1)?(print(Min[head].v),putchar(' '),flag=1):head++;
if(flag==1) break;
}
}
putchar('\n');
head=tail=1;
for(rg int i=1;i<=n;i++){
while(Max[tail].v<=a[i]&&head<=tail)
tail--;
tail++,Max[tail].x=i,Max[tail].v=a[i];
if(i<m)
continue;
int flag=0;
while(head<=tail){
(Max[head].x>=i-m+1)?(print(Max[head].v),putchar(' '),flag=1):head++;
if(flag==1) break;
}
}
}