文章目录
-
- 栈的定义
- [单调栈 & 单调队列](#单调栈 & 单调队列)
-
- 单调栈的详细解释【图文讲解】
- [例题:洛谷P5788 【模板】单调栈](#例题:洛谷P5788 【模板】单调栈)
-
- code↓
- [洛谷P5788 【模板】单调栈 AC](#洛谷P5788 【模板】单调栈 AC)
栈的定义
栈的修改
与访问
是按照后进先出
的原则进行的
栈通常被称为是后进先出
(last in first out)表,简称 LIFO 表
是只允许在一端进行插入或删除操作的线性表
此动图来源于:oi-wiki
栈的STL运用
stack<T> st
:建立一个名为st
的T类型
栈
st.top()
:返回栈顶
st.push()
:插入传入的参数到栈顶
st.pop()
:弹出栈顶
st.empty()
:返回是否为空
st.size()
:返回元素数量
单调栈 & 单调队列
单调栈的定义其实与单调队列
的定义差不多,都需要保持单调性
,单调栈即满足单调性的栈结构
有关单调队列
可以看我的另一篇博文:
单调队列【deque】 & 队列【STL】& 洛谷P1886 滑动窗口 & 洛谷P9905 [COCI 2023_2024 #1] AN2DL 【矩阵区间最大值】
单调栈的详细解释【图文讲解】
假设输入的数为:
5
1 5 2 4 3
其中5
是个数,剩下的1,5,2,4,3
是输入的数列
假设:我们用这个数列以1~n
的顺序维护一个单调递增
的单调栈
(PS:栈初始为空
)
当i=1
时,因为栈是空的
,所以直接将1给压入栈
当i=2
时,因为5 > 1
所以直接将5
压入栈
当i=3
时,因为2<5
,所以将5
弹出,因为2>1
,所以直接将2
压入栈
当i=4
时,因为4>2
,所以直接将4
压入栈
当i=5
时,因为3<4
,所以将4
弹出,因为3>2
,所以直接将3
压入栈
单调栈的伪代码:
cpp
insert x//这是现在输入的数,insert的意思是输入
while (!sta.empty() && sta.top()<x)//如果这个栈不为空,并且栈顶比现在输入的数小则弹出这个数
sta.pop()//弹出栈顶
sta.push(x)//将现在这个数给压入栈顶(现在这个数已经比栈顶小了)
总结而言,就是不断地弹出栈顶直到这(整个栈+现在输入的数)所组成的栈满足单调性为止
例题:洛谷P5788 【模板】单调栈
题意:这道题目就是模板题,只需要从后向前依次维护单调栈,最后反着输出答案即可
题目链接:P5788 【模板】单调栈
code↓
cpp
#include <bits/stdc++.h>
using namespace std;
const int maxn=3e6+5;//边界的值为maxn
long long n,a[maxn]={},ans[maxn]={};//a[]是输入数组,ans[]是答案数组,用来存储答案
stack<int> st;//这个栈里面存储的是编号
int f(int i){
while(!st.empty()&&a[st.top()]<=a[i]) st.pop();//用于维护栈的单调性
ans[i]=st.empty()?0:st.top();
//这里运用了三元运算符,上方代码等同于↓
//if(st.empty()==true) ans[i]=0;
//else ans[i]=st.top();
st.push(i);//将现在这个数的编号压入栈
return 0;
}
int main(){
cin>>n;//输入个数
for(int i=1;i<=n;i++) cin>>a[i];//输入数组
for(int i=n;i>=1;i--) f(i);
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";//因为最后存储的就是编号,所以直接输出即可
return 0;
}