单调栈一般可以对于给定的数列,求每个值v在他左右的区间[l,r]是最小值(最大值),通过单调递增(递减)栈来实现。
1.用处
求每个值v是哪个区间[l,r]的最小(大)值,一般还会和区间[l,r]有关系
给定数列 要求一个区间内最小值乘区间和,的最大值。
poj2559 Largest rectangle in a Histogram
给定几个不同高度的矩形,求能画出的最大矩形面积
其实就是区间最小值*区间长度,的最大值
poj3494 Largest Submatrix of All 1’s
给定01矩阵,求全是1的矩阵的最大面积
经过对每一行处理,他可以向上长多少,就转换成poj2559的直方图样子,求区间最小值*区间长度的最大值即可。
给定一列牛,求每头牛能看到他右侧几头牛,求和。
求比他矮的,所以是递减栈,而且只需要一侧,所以只记录r也可以。每个值作为区间最大值,的区间长度,求和。
2.步骤(以递增栈为例)
a.初始化值和区间[l,r]
可用结构体
struct node{
int v,l,r;//v是[l,r]内的最小值
};
vi题目给定,l,r如果表示vi是[l,r]的最小值,一般初始化为[i,i]b.for i = 1 to n 遍历准备入栈
if 栈为空 || 准备入栈元素v[i] >= 栈顶
入栈
else
while 栈不为空 && 栈顶仍然比准备入栈元素大
node t = stk.top();stk.pop();
可以根据t,stk.top(),v[i]之间的大小关系,更新stk.top(),v[i]的区间[l,r] // 更新stk.top()前要记得判断栈是否为空
用t更新答案
退出while 可以将v[i]入栈了
用t更新答案
模版
#include <iostream>
#include <cstdio>
#include <stack>
using namespacestd;
const int maxn =8e4 +5;
typedef longlong ll;
struct node{
int h,l,r;//h是[l,r]内最小值
}cow[maxn];
stack<node> stk;
int main()
{
int n;
scanf("%d",&n);
for (int i =0; i < n; i ++) {
scanf("%d",&cow[i].h);
cow[i].l =cow[i].r = i;
}
ll ans =0;
for (int i =0; i < n; i ++) {
if(stk.empty() ||cow[i].h >=stk.top().h )stk.push(cow[i]);
else {
while(!stk.empty() &&cow[i].h <stk.top().h){
node t =stk.top();stk.pop();
ans += t.r;//根据题目计算答案
cow[i].l = t.l;
if(!stk.empty())stk.top().r = t.r;
}
stk.push(cow[i]);
}
}
while (!stk.empty()) {
node t =stk.top();stk.pop();
ans += t.r;//
if(!stk.empty())stk.top().r = t.r;
}
printf("%lld\n",ans);
return0;
}
1.注意根据题目是递增栈还是递减栈,是否严格增减
2.超时的话手写栈
3.根据题目,决定答案怎么更新,不拘泥于形式,比如SCU2511