Monotonic stack basics

                                         Monotonic stack

In the past few days, when I finished my winter vacation homework, I learned about the use and function of monotonic stacks and monotonic queues.
Monotonic stack: monotonicity, emphasizing monotonicity. Elements on the stack can be incremented or decremented. The concept is simple.

When I first came into contact with the monotonic stack, I didn't understand the code of others vaguely. When I write monotone stacks, I use array simulation to define an s[maxn] array. The s array is used to record the coordinates of the top of the stack.
Let's take a look at the basic problems of monotonic stacks.

Bad Hair Day  POJ 3250
Feel Good POJ 2796  
Largest Rectangle in a Histogram   POJ 2559 HDU 1506
Here are three very basic topics, suitable for beginners like us who are new to monotonic stacks.
Attach your own AC code below

/*   POJ 3250 */

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<queue>
#include<vector>
#include<stack>
#include<list>
#include<map>
#include<set>
using namespace std;
typedef unsigned long long llu;
const int maxn = 80000 + 5;
llu stc[maxn];
int main()
{
    llu n,ans=0,x;
    long long top=-1;
    scanf("%llu",&n);
    while(n--)
    {
        scanf("%llu",&x);
        while(top>=0&&x>=stc[top]) top--;//维护一个单调递减的栈 如果大于栈顶元素 栈顶出站
        stc[++top]=x;//新元素 入栈
        ans+=top;
    }
    printf("%llu\n",ans);
}


/*   POJ 2796 */

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<queue>
#include<vector>
#include<stack>
#include<list>
#include<map>
#include<set>
using namespace std;
#define manx maxn
const int maxn = 100000 + 5;
int l[manx],r[maxn],stc[maxn];
long long a[maxn],sum[manx];
int main()
{
    int n,i;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        sum[i]=sum[i-1]+a[i];//前缀和
        l[i]=r[i]=i;
    }
    int top=0;
    for(i=1;i<=n+1;i++)//注意n+1  因为下面r[stc[top]]=i-1;  
    {
        while(top&&a[i]<=a[stc[top]])//维护单调递增栈
        {
            r[stc[top]]=i-1;//确定右区间坐标 
            top--;
        }
        l[i]=stc[top];//确定左区间坐标
        stc[++top]=i;
    }
    long long temp,ans=-1,ans1=0,ans2=0;
    for(i=1;i<=n;i++)
    {
        temp=(sum[r[i]]-sum[l[i]])*a[i];//枚举每个区间的值
        if(temp>=ans)
        {
            ans=temp;
            ans1=l[i];
            ans2=r[i];
        }
    }
    printf("%lld\n%lld %lld",ans,ans1+1,ans2);

}


/*   POJ 2559 || HDU 1506 */

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<queue>
#include<vector>
#include<stack>
#include<list>
#include<map>
#include<set>
const int MAXN = 100000 +10;
using namespace std;
int l[MAXN],r[MAXN],s[MAXN];
int main()
{
    long long a[MAXN];
    int n;
    int top;
    while(scanf("%d",&n),n)
    {
        long long ans=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&a[i]);
            l[i]=r[i]=i;
        }
        top=0;
        for(int i=1; i<=n; i++)//确定左坐标 就是i点左边的 低或者等于这个矩形的位置
        {
            while(top&&a[i]<=a[s[top]])//每次我们加入一个点 和这个区间最小的点比较(及栈顶元素)
                top--;
            if(top==0)//栈空
                l[i]=1;
            else l[i]=s[top]+1;
            s[++top]=i;
        }
        top=0;
        for(int i=n; i>=1; i--)//确定右坐标  同上
        {
            while(top&&a[i]<=a[s[top]])//维护一个递增栈
                top--;
            if(top==0)//栈空
                r[i]=n;
            else r[i]=s[top]-1;
            s[++top]=i;
        }
        //for(int i=1;i<=n;i++)
            //cout<<l[i]<<"    "<<r[i]<<"****"<<endl; //可以看相应点的坐标l[i]是记录 i点左边最小的点坐标(含等于) r[i]是最大的(含等于)
        for(int i=1; i<=n; i++)
        {
            long long temp=a[i]*(r[i]-l[i]+1);//枚举每个区间的值
            if(temp>ans)
                ans=temp;
        }
        cout<<ans<<endl;
    }
}
The last question is a picture to help understand better. In short, to emphasize a monotonicity, the monotonic stack has been optimized for different ordinary enumeration times. Of course, it is also possible to use STLstack, but it is slower than the array simulation.
After a while, I am familiar with the DP problem. Let's update the monotonic queue and optimize the DP. Now I see the DP head is big.  


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326318732&siteId=291194637