单调栈
单调栈的性质从字面意思上就是利用其单调性对元素进行入栈与出栈的操作的过程来达到所需的要求。
因为其进行整个操作过程中只有出栈与入栈所以时间是O(n)。
题目集:https://www.csdn.net/.
(如果您用的是移动网那么请将net 改成 z180.cn 我也不知为什么)
单调栈例题:
<1> HDU - 1506:
直方图是由在共同基线上排列的矩形序列组成的多边形。矩形具有相等的宽度,
但可以具有不同的高度。请在直方图中计算最大矩形的面积,该直方图也是在
公共基线上对齐的。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
#define MM(a,b) memset(a,b,sizeof(a))
ll a[N],l[N],r[N],ans=-1;
int main()
{
int n;
while(cin >> n ){
MM(a,0);
ans=-1;
if(n == 0) break;
for(int i = 0 ; i < n ; i++){
cin >> a[i];
}
stack<ll> s;
for(int i = 0 ; i < n ; i++){
while(!s.empty() && a[i]<= a[s.top()])
s.pop();
l[i]=s.empty()?0:s.top()+1;
s.push(i);
}
stack<ll> ss;
for(int i = n-1 ; i >=0 ; i--){
while(!ss.empty() && a[i] <= a[ss.top()])
ss.pop();
r[i]=ss.empty()==1?n-1:ss.top()-1;
ss.push(i);
}
for(int i = 0 ; i < n ; i++){
ans=max(ans,a[i]*(r[i]-l[i]+1));
}
cout << ans << endl;
}
}
<2>POJ - 3250
Farmer John的奶牛在风中凌乱了它们的发型……
每只奶牛都有一个身高hi(1 ≤ hi ≤ 1,000,000,000),现在在这里有一排全部
面向右方的奶牛,一共有N只(1 ≤ N ≤ 80,000)。对于奶牛i来说,
如果奶牛i+1,i+2,……,N这些奶牛的身高严格小于奶牛i,则奶牛i可以
看到它们凌乱的发型。
令ci表示第i只奶牛能够看到的发型数量,请计算c1 + c2 + c3 + … + cN的值
#include <iostream>
#include <stack>
using namespace std;
const int N = 8e4+10;
typedef long long ll;
ll a[N],ans=0;
int main()
{
int n,x;
cin >> n;
for(int i = 0 ; i < n ; i++){
cin >> a[i];
}
stack<int> s;
for(int i = n-1 ; i >= 0 ; i--){
while(s.size() && a[s.top()] < a[i]){
s.pop();
}
x = s.empty()?n-1:s.top()-1;
ans += 1ll*(x-i);
s.push(i);
}
cout << ans;
return 0;
}
<3>POJ - 2796
给定n天,每一天有一个非负权值ai。某一段时间[l, r]的权值被定义为
即时间内的每天的权值和乘以这段时间内的最小权值。
求一个时间段,使这个时间段的权值最大。
#include <iostream>
#include <stack>
#include <stdio.h>
using namespace std;
const int N = 1e5+10;
typedef long long ll;
ll l[N],r[N],ans=-1,tem,a[N],sum[N],lef=0,rig=0;
int main()
{
int n;
sum[0]=0;
scanf("%d",&n);
for(int i = 1 ; i <= n ; i++){
scanf("%lld",&a[i]);
sum[i]=sum[i-1]+a[i];
}
stack<int> s;
for(int i = 1 ; i <= n ; i++){
while(s.size() && a[s.top()] >= a[i]){
s.pop();
}
l[i] = s.empty()?1:s.top()+1;
s.push(i);
}
while(s.size()) s.pop();
for(int i = n ; i >= 1 ; i--){
while(s.size() && a[i] <= a[s.top()]){
s.pop();
}
r[i] = s.empty()?n:s.top()-1;
s.push(i);
}
for(int i = 1 ; i <= n ; i++){
tem = a[i]*(sum[r[i]]-sum[l[i]-1]);
if(tem > ans){
lef=l[i];
rig=r[i];
ans=tem;
}
}
cout << ans << endl << lef << " " << rig << endl;
return 0;
}
所以在写了三道题之后感觉单调栈的基本模板是
stack<int> s;
for(int i = 1 ; i <= n ; i++){
while(s.size() && a[s.top()] ? a[i]){
s.pop();
}
这里是可以添加标记的条件
s.push(i);这个很关键,每一步的最后都要让元素入栈不然就没有元素了。
}
总之要记住入栈与出栈是每个元素都要经历的