单调栈详解 + poj 2796 poj 2559 CF 547B
来源:互联网 发布:淘宝网时尚女牛仔裤 编辑:程序博客网 时间:2024/04/29 18:52
单调栈:
定义:用栈结构来实现,使得遍历数组中栈顶元素保持一定范围的最大或最小,并且栈中元素始终保持单调性的栈。
功能:用以快速(O(n))求出数组中某连续子集中的最大值或者最小值。
原理:
以求某连续子集中的最小值为例:
假设某数组为:
模拟过程:
栈顶下标表示当前元素为从此下标到 上一个栈顶下标的最小值。
1.栈为空,将3的下标压入栈中。 //当前栈状态:(栈底 0)1 (栈顶)
2.元素1 <= 3,所以3的下标出栈,1的下标入栈。 //当前栈状态:(栈底 0)2 (栈顶)
3.元素1 < 6,6的下标入栈。 //当前栈状态:(栈底 0) 2 3 (栈顶) 此时表示6为 2 + 1 到 3 的最小值。
4.元素4 <= 6,6的下标出栈,1 < 4,4的下标入栈。 //当前栈状态:(栈底0)2 4 (栈顶) 此时表示4为 2 + 1 到 4的最小值。
5.元素4 < 5,5的下标入栈。 //当前栈状态:(栈底0)2 4 5 (栈顶) 此时表示5为 4 + 1 到 5的最小值。
6.元素2 < 5, 5的下标出栈,2<4,4的下标出栈,2的下标入栈。 //当前栈状态:(栈底0)2 6 (栈顶) 此时表示2为 2 + 1 到 6的最小值。
7.更新完毕。
整个过程,每出栈一次记录一次,就可以记录下整个过程中某个连续子段的最小值,达到了其功能。
以下为例题。
poj 2796:
题意:
1e6的数据向量,求连续的子集的和与子集中最小的数的积的最大值, 并求出这段子集的左右坐标。
解析:
不造为啥用stack的stl错了,用数组的过了。
这题有两个注意的点,一个是开始ans置为-1,不然会wa的很惨很惨,因为ans = 0 的时候也更新ansL, ansR。
另一个就是要把-1的节点插入到数组最后,以便单调栈遍历完整个数组。
栈顶为当前的最小值。
代码:
#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <climits>#include <cassert>#define LL long long#define lson lo, mi, rt << 1#define rson mi + 1, hi, rt << 1 | 1using namespace std;const int maxn = 1e5 + 10;const int inf = 0x3f3f3f3f;const double eps = 1e-8;const double pi = acos(-1.0);const double ee = exp(1.0);LL a[maxn];LL sum[maxn];int s[maxn];int main(){#ifdef LOCAL freopen("in.txt", "r", stdin);#endif // LOCAL int n; while (~scanf("%d", &n)) { memset(sum, 0, sizeof(sum)); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); sum[i] += sum[i - 1] + a[i]; } a[++n] = -1;///debug LL ans = -1;///debug int ansL = -1, ansR = -1; int top = 0; for (int i = 1; i <= n; i++) { while (top && a[i] <= a[s[top]]) { LL t = a[s[top]] * (sum[i - 1] - sum[s[top - 1] + 1 - 1]); if (ans < t) { ans = t; ansL = s[top - 1] + 1; ansR = i - 1; } top--; } s[++top] = i; } printf("%lld\n%d %d\n", ans, ansL, ansR); } return 0;}
poj 2559:
题意:
如上图,给一些宽度为1的矩形的高度,求由矩形围成的大矩形的最大面积。
数据量1e5。
解析:
找每个范围中的最小高度,此时这个最小高度作为整个范围的高,计算面积,扫一遍取最大面积即可。
往前扫一遍,后扫一遍,相当于记录当前这个点a[i]在哪个区域内始终是最小的。
注意的是后扫的时候,要将栈顶置为-1,否则后扫时栈值无法置为n+1。
比如 5 0 0 0 0 1,这组数据。
代码:
#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <climits>#include <cassert>#define LL long long#define lson lo, mi, rt << 1#define rson mi + 1, hi, rt << 1 | 1using namespace std;const int maxn = 1e5 + 10;const int inf = 0x3f3f3f3f;const double eps = 1e-8;const double pi = acos(-1.0);const double ee = exp(1.0);LL a[maxn];int s[maxn];//stackint pre[maxn];int las[maxn];int main(){#ifdef LOCAL freopen("in.txt", "r", stdin);#endif // LOCAL int n; while (~scanf("%d", &n) && n) { memset(s, 0, sizeof(s)); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); } int top = 0; a[0] = -1; for (int i = 1; i <= n; i++) { while (top && a[i] <= a[s[top]]) { top--; } pre[i] = s[top]; s[++top] = i; } top = 0; s[top++] = n + 1; a[n + 1] = -1; for (int i = n + 1; i >= 1; i--) { while (top && a[i] <= a[s[top]]) { top--; } las[i] = s[top]; s[++top] = i; } LL ans = 0; for (int i = 1; i <= n; i++) {// cout << pre[i] << " " << las[i] << endl; LL t = (las[i] - pre[i] - 1) * a[i]; if (ans < t) ans = t; } printf("%lld\n", ans); } return 0;}
CF 547B:
题目:
Description
Mike is the president of country What-The-Fatherland. There are n bears living in this country besides Mike. All of them are standing in a line and they are numbered from1 ton from left to right.i-th bear is exactlyai feet high.
A group of bears is a non-empty contiguous segment of the line. The size of a group is the number of bears in that group. The strength of a group is the minimum height of the bear in that group.
Mike is a curious to know for each x such that1 ≤ x ≤ n the maximum strength among all groups of sizex.
Input
The first line of input contains integer n (1 ≤ n ≤ 2 × 105), the number of bears.
The second line contains n integers separated by space,a1, a2, ..., an (1 ≤ ai ≤ 109), heights of bears.
Output
Print n integers in one line. For each x from 1 to n, print the maximum strength among all groups of size x.
Sample Input
101 2 3 4 5 4 3 2 1 6
6 4 4 3 3 2 2 1 1 1
题意:
给n个数,找到长度为1 ~ n 的子集中,每个子集中元素的最小值,然后取代表每个子集的最小值的最大值。
解析:
如上题一样,前后扫一遍,相减出长度。
然后扫一遍就好啦。
感谢这题让我认识了单调栈!
这题有个要注意的地方:
所有长度扫完之后要做一个下面的更新:
for (int i = n - 1; i >= 1; i--){ maxValue[i] = max(maxValue[i + 1], maxValue[i]);}因为有可能一些长度是取不到的,所以酱紫更新一下就行了。
代码:
#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <climits>#include <cassert>#define LL long long#define lson lo, mi, rt << 1#define rson mi + 1, hi, rt << 1 | 1using namespace std;const int maxn = 2e5 + 10;const int inf = 0x3f3f3f3f;const double eps = 1e-8;const double pi = acos(-1.0);const double ee = exp(1.0);int a[maxn];int pre[maxn], las[maxn];int maxValue[maxn];int main(){#ifdef LOCAL freopen("in.txt", "r", stdin);#endif // LOCAL int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } stack<int> s; s.push(0); for (int i = 1; i <= n; i++) { while (!s.empty() && a[i] <= a[s.top()]) s.pop(); pre[i] = s.top(); s.push(i); } stack<int> t; t.push(n + 1); for (int i = n; i >= 1; i--) { while (!t.empty() && a[i] <= a[t.top()]) { t.pop(); } las[i] = t.top(); t.push(i); } for (int i = 1; i <= n; i++) {// cout << pre[i] << " " << las[i] << endl; int len = las[i] - pre[i] - 1; maxValue[len] = max(maxValue[len], a[i]); } for (int i = n - 1; i >= 1; i--) { maxValue[i] = max(maxValue[i + 1], maxValue[i]); } for (int i = 1; i <= n; i++) { printf("%d ", maxValue[i]); } return 0;}
- 单调栈详解 + poj 2796 poj 2559 CF 547B
- cf 547B 单调栈
- poj 2796#单调栈
- POJ 2796 单调栈~
- poj 2796(单调栈)
- poj 2796 单调栈
- poj 2796 单调栈
- poj 2796 单调栈
- poj 2796 单调栈
- POJ 2559 单调栈
- POJ 2559 单调栈
- poj 2559(单调栈)
- poj 2559 单调栈
- POJ 2559 单调栈
- poj 2559 单调栈
- poj 2559 单调栈
- POJ 2796 Feel Good 单调栈的应用 代码详解
- poj 2796 单调栈(经典)
- 南宁肛门瘙痒吃什么药
- 合图原理
- jboss安全问题
- data mining - 实用机器学习与技术 读书笔记(六)
- 自定义控件其实很简单2/3
- 单调栈详解 + poj 2796 poj 2559 CF 547B
- twemproxy 简介
- 数据结构网图(C++)
- 如何在VMware Workstation11的Windows Server 2008 R2中安装XAMPP?
- Android 添加同名通讯录自动合并的问题
- java 工作流osworkflow
- 关于Unity3D中的日志
- 南宁便秘都有什么症状
- cygwin 的安装使用