栈 先进后出 就像一个桶一样 先进的到栈底 最后进的是栈顶
队列 先进先出

[模拟栈] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

const int N=100010;

int stk[N],tt; tt表示栈顶下标
//插入
stk[++tt] =x;

//弹出
tt--;

//判断栈是否为空
if(tt>0) not empty
else empty

//栈顶
stk[tt];

单调栈
很抽象 类似于删掉逆序的对 最后得到单调的栈
单调栈主要解决以下问题:
寻找下一个更大元素
寻找前一个更大元素
寻找下一个更小元素
寻找前一个更小元素 诸如此类
有点抽象 类似于删掉逆序的对 最后得到单调的栈
例 给定一个长为N的整数数列 输入每个数左边第一个比它小的数 不存在则-1

[单调栈] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<bits/stdc++.h>
using namespace std;
const int N=100010;

int n,stk[N],tt;

int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=0;i<n;i++)
{
int x;
cin>>x;
while(tt&stk[tt]>=x) tt--; //如果栈不为空且栈顶大于当前数 那么栈顶必不是答案了 直接删掉
if(tt) cout<<stk[tt]<<" "; 如果这样处理了 栈不为空 那么栈顶就是答案
else cout<<-1<<" ";

stk[++tt]=x; //记得将新数入栈

}
}

这样时间复杂度就超级屌 O(n)

[模拟队列] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
//队尾插入元素 队头弹出元素
int q[N],hh,tt=-1; //hh队头 tt队尾 头在左边便于数组操作

//插入
q[++tt]=x;

//弹出
hh++; 队头指针右移一个位置

//判断是否为空
if(hh<tt) not empty
else empty

单调队列经典例题 滑动窗口 求窗口内最小值

只要前面的数比后面大 前面的数就无用了 只要存在这种逆序对 就删掉大的

[单调队列] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<bits/stdc++.h>
using namespace std;

const int N=1000010;
int n,k;
int a[N],q[N]; //数组a存原数列 q存的单调队列下标 注意是下标
int main()
{
cin>>n>>k;
ios::sync_with_stdio(false)
cin.tie(0);
for(int i=0;i<n;i++) cin>>a[i];
int hh=0,tt=-1;
for(int i=0;i<n;i++)
{
//判断队头是否划出窗口 直接对比下标就可以了
if(hh<=tt&&i-k+1>q[hh]) hh++; //没有用while 因为每次只移动一次 最多就窗口左边一个位置

while(hh<=tt&&a[q[tt]]>=a[i]) tt--; //求窗口最小值 若插入的数比队尾小 队尾一定不是答案了 就删去
q[++tt]=i;//更新右端点 与下一个插入的a[i]比较
if(i>=k-1) cout<<a[q[hh]];//一开始 元素不满k时不输出
}
}