萌萌的单调栈 : poj2796 , poj2559 ,


性质:

1、若是单调递增栈,则从栈顶到栈底的元素是严格递增的。若是单调递减栈,则从栈顶到栈底的元素是严格递减的。

2、越靠近栈顶的元素越后进栈。(栈的基本性质)


操作:

和栈一样单调栈一样,入栈和出栈.

入栈前对入栈元素进行检测:

如 4,5,3,7,7,9

                                                           9
    ->  5  ->    ->      ->  7   ->     -> 7 ->  7
 4      4      4      3        3       3      3      3
(1)    (2)    (3)    (4)      (5)     (6)    (7)    (8)


(1)栈为空,4入栈

(2)4<5成立,5入栈

(3)5<3不成立,5出栈

    (3)4<3不成立,4入栈

(4)栈为空,3入栈

(5)3<7成立,7(first)入栈

(6)7(first)<7(second)不成立,7(first)出栈

(7)3<7(second)成立,7(second)入栈

(8)7<9成立,9入栈


应用:

根据性质1,

求区间最大(最小)值:

每次入栈的都是严格递增(递减).

入栈不成功,顶部元素弹出,维护区间(就是栈里的加上栈顶的区间因为比他大所以栈里元素依旧是维护后区间最小值,同理,要入栈的元素也加上该区间)

所以每次入栈都维护区间就能求出区间的最值.

最后剩下的元素也是一堆区间.

所以时间复杂度为O(n)到O(2n)


poj 2796 Feel Good

这道题就是维护区间的时候求出最大值(上述原理).

坑就坑在写成  int  m结果爆了(捂脸)..

#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
const int maxn = (int)1e6+5;

LL sum[maxn]={0};

struct node
{
    int l,r,n;
}stk[maxn];
int tp;

node mn(int a,int b,int c)
{
    node t;
    t.n=a;
    t.l=b;
    t.r=c;
    return t;
}

LL calc(node a)
{
    //printf("%lld\n",(sum[a.r]-sum[a.l-1])*(LL)a.n);
    return (sum[a.r]-sum[a.l-1])*(LL)a.n;
}

LL an=0,f;
int al,ar;
inline void ck(node a)
{
    LL m=calc(a);
    if(an<=m)
    {
        an=m;
        al=a.l;
        ar=a.r;
    }
}

int main()
{
    //freopen("a.in","r",stdin);
    //freopen("a.out1","w",stdout);
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        an=0;
        tp=0;
        stk[0]=mn(0,0,0);
        sum[0]=0;
        for(int i=1;i<=n;i++)
        {
            int in;
            scanf("%d",&in);
            node t=mn(in,i,i);
            sum[i]=sum[i-1]+in;
            while(tp&&t.n<=stk[tp].n)
            {
                t.l=stk[tp].l;
                stk[tp-1].r=stk[tp].r;
                ck(stk[tp]);
                tp--;
            }
            stk[++tp]=t;
        }
        while(tp)
        {
            stk[tp-1].r=stk[tp].r;
            ck(stk[tp]);
            tp--;
        }
        //printf("%d\n",sum[0]);
        printf("%lld\n%d %d\n",an,al,ar);
    }
    return 0;
}


POJ 2559 Largest Rectangle in a Histogram

这道题比上道题feel good更加简单..注意别爆了啊..

#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;

struct node
{
    int h;
    int l,r;
}stk[100005];
int top;
LL ans;

LL calc(node t)
{
    return (LL)t.h*(t.r-t.l+1);
}

void insert(node &t)
{

    while(top&&stk[top-1].h>=t.h)
    {
        top--;
        stk[top-1].r=stk[top].r;            ///入栈检测,维护区间
        t.l=stk[top].l;
        ans=max(calc(stk[top]),ans);
    }
    stk[top++]=t;
}

int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
    {
        ans = top = 0;
        node t;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&t.h);
            t.l=t.r=i;
            insert(t);
        }

        while(top--)                        ///pop 剩下的
        {
            stk[top-1].r=stk[top].r;
            ans=max(calc(stk[top]),ans);
        }
        printf("%lld\n",ans);
    }
    return 0;
}


你可能感兴趣的:(数据结构,ACM,单调栈)