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
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.