学习笔记——单调栈
比较简单的数据结构。
单调栈满足栈的性质的同时,保持内部的单调性。
运用这一数据结构,可以以O(n)的平均复杂度维护一些东东。
经典运用:
1西红柿的日常I
by Vareal.
当前数如果比栈顶小,入栈,否则持续弹出栈中比它小的数,同时把比它小的数的答案更新为它。由于栈一直是单调递减的,所以可以保证当前数一定为第一个比弹出数小的数。这样便可以省去大量时间(一下子就求出了一大堆数的答案)。
code
#include<iostream>
#include<cstdio>
using namespace std;
inline void read(int &x){
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-48;
ch=getchar();
}
x*=f;
}
struct node{
int data,next,num;
}a[10000001],b[10000001];
int main(){
int n;
read(n);
int head=1;
b[head].data=0;
for(int i=1;i<=n;i++){
read(a[i].data);
a[i].num=i;
a[i].next=-1;
if(a[i].data >= b[head].data){
b[++head]=a[i];
}else{
while(a[i].data<b[head].data&&head>1){
a[b[head].num].next=a[i].data;
head--;
}
b[++head]=a[i];
}
}
for(int i=1;i<=n;i++){
cout<<a[i].next<<" ";
}
return 0;
}
2 最大矩形
本题可用单调栈维护。
比栈顶高的矩形全部入栈,遇到了比栈顶低的矩形,先统计前面的高度,更新最大值,每统计一次弹出一个,宽度加上栈顶宽度。最后,将宽为更新后当前的宽度,高为读入矩形的高度的矩形入栈,相当于将比它高的矩形全部削平。
这样,就一直保持了栈的单调性。由于遇到低的后,考虑到如果最大面积覆盖了它,那么高的矩形无用武之地,于是先统计,然后排除,这样便省去了大量时间,实际上运用了贪心的思想。
code
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
template<class T>inline void read(T &x)
{
x = 0;
T f = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-')
{
f = -1;
}ch = getchar();
}
while(ch>='0' && ch<='9')
{
x = x*10+ch-48;
ch = getchar();
}
x *= f;
}
struct rect{
ll h, w;
}st[1000001];
ll a[100001];
ll ans, n;
void work()
{
a[n+1] = 0;
memset(st, 0, sizeof(st));
ans = 0;
int top = 0;
for(int i = 1; i <= n+1; i++)
{
if(a[i] > st[top].h)
{
rect x;
x.h = a[i];
x.w = 1;
st[++top] = x;
}else{
ll width = 0;
while(a[i] < st[top].h && top > 0)
{
width += st[top].w;
ans = max(ans, width * st[top].h);
top--;
}
rect x;
x.h = a[i];
x.w = width + 1;
st[++top]=x;
}
}
cout << ans <<endl;
}
int main()
{
while(1)
{
read(n);
if(!n) break;
for(int i = 1; i <= n; i++)
{
read(a[i]);
}
work();
}
return 0;
}

浙公网安备 33010602011771号