学习笔记——单调栈

比较简单的数据结构。

单调栈满足栈的性质的同时,保持内部的单调性。

运用这一数据结构,可以以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;
}
posted @ 2020-10-30 23:00  Entropyw  阅读(73)  评论(0)    收藏  举报