单调栈
来源:互联网 发布:淘宝有哪些直通车 编辑:程序博客网 时间:2024/04/26 08:12
从某一个元素开始,以该元素为最值,一直向前延伸找最优值(若需要两个方向的解,则再从右往左扫描一遍即可).每个元素最多进出栈一次,复杂度O(n)
应用:
①栈维护上升序列求解不小于i的最大区间:
题目链接: hdu1506 Largest Rectangle in a Histogram
求直方图能覆盖的最大矩阵的面积,则矩阵的高度为其中直方图中的最小高度。对某个直方图h[i],向两边搜寻不小于该高度的区间。
以左边界为例,使用单调栈维护一个递增序列的下标,每次取栈顶j进行比较。若h[j] >= h[i],则说明i可以延伸至j的左边界,则更新i的左边界。由于高度小于h[i]的直方图可以覆盖i的区间,大于h[i]的直方图直接被i中断,所以j对后续节点并无作用,将j弹出栈。
直到h[j] < h[i],说明i不能再向更远处延伸,将i进栈。
代码如下:
#include <cstdio>#include <stack>using namespace std;#define N 100005int a[N], l[N], r[N];stack<int> h;int main(){ int n; while(scanf("%d", &n) && n){ h.push(0); for(int i = 0; i < n; i ++){ scanf("%d", &a[i]); l[i] = 1; r[i] = 1; } for(int i = 1; i < n; i ++){ while(!h.empty() && a[i] <= a[h.top()]){ l[i] += l[h.top()]; h.pop(); } h.push(i); } while(!h.empty()) h.pop(); h.push(n - 1); for(int i = n - 2; i >= 0; i --){ while(!h.empty() && a[i] <= a[h.top()]){ r[i] += r[h.top()]; h.pop(); } h.push(i); } while(!h.empty()) h.pop(); long long max_val = 0; for(int i = 0; i < n; i ++){ long long temp = (long long)a[i] * (l[i] + r[i] - 1); if(temp > max_val) max_val = temp; } printf("%I64d\n", max_val); }}
②栈维护下降序列求解不大于i的最大值
题目链接:hdu3410 Passing the Message
left messenger为左边不超过h[i]的最高者j.因为若h[j] > h[i],则j一定先从别处得到message。维护一个下降序列的下标,保存当前的最高值、次高值……
每次将h[i]与栈顶比较,若大于栈顶,说明left messenger的位置不晚于这个位置,而且栈顶元素会被i挡住,所以对于i以后的点,栈顶元素也没有意义了,应该出栈。直到小于栈顶的高度,说明i的视线会被栈顶的元素挡住,则上一次的栈顶元素为left messenger。同理,求解right从右往左扫描即可。
代码如下:
#include <cstdio>using namespace std;#define N 50005int h[N], stack[N], L[N], R[N];int main(){int n, tc, ca = 0;scanf("%d", &tc);while(tc --){scanf("%d", &n);for(int i = 1; i <= n; ++i)scanf("%d", &h[i]);stack[0] = 1; //维护一个下降序列,栈中存放下标int top = 0;for(int i = 2; i <= n; ++i){int cur = 0;while(top >= 0 && h[stack[top]] < h[i])cur = stack[top], --top;L[i] = cur; //最后一个比h[i]小的位置stack[++top] = i;}stack[0] = n, top = 0;for(int i = n - 1; i > 0; --i){int cur = 0;while(top >= 0 && h[stack[top]] < h[i])cur = stack[top], --top;R[i] = cur;stack[++top] = i;}printf("Case %d:\n", ++ca);for(int i = 1; i <= n; ++i){printf("%d %d\n", L[i], R[i]);}}return 0;}
单调栈不涉及区间长度,可以一直往一个方向延伸,所以只在栈顶进出栈。
当需要在一定范围内搜索时,要用单调队列,队头为该范围内的最优值,当下标不在有效范围时,队头要出队。由于篇幅有限,单调队列令开一篇记录。
- 单调栈 单调队列
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- 单调栈
- CodeForces 2A-Winner
- python wmi 学习
- 9.5位操作(四)——解释代码(n&(n-1))==0的具体含义
- 如何知道android应用是第一次运行
- Java中关于String的split(String regex, int limit) 方法
- 单调栈
- 代码分类之删除文件、目录及目录下的所有文件
- phpcms下载页直接显示下载真实地址方法
- 多态的表现形式
- PHP获取用户IP地址
- 回忆
- 用文件流的形式读写xml文件到MFC的树控件中
- AppDelegate.h
- android - 模仿微博的@人功能