浅谈单调栈

版权声明:欢迎转载,请注明此博客地址。 https://blog.csdn.net/Ever_glow/article/details/81304759

做某些题的时候可能会发现,维护数列的时候,此数列的元素要么是在递增,要么是在递减,总之需要维护的序列是单调的,这样我们即可在O(n)的时间内完成数列的维护,当需要数列先进先出的时候就可以用队列维护,当需要数列先进后出的时候,栈就可以完成,此文章先根据几个例题,简单理解一下单调栈。

以HDU1506为例

题目要求求出最大面积的矩形,可以发现,求矩形的面积的话,只要知道左边比当前矩形小的矩形位置,右边比此矩形小的位置,最后两边一减*矩形的高就ok,此处的小指的是高<此矩形高。然后观察发现,只需要维护一个递增的序列就可以,以图为例  
 

首先维护一个栈,当新加入的元素大于等于栈顶元素的时候,说明此时左边第一个比他小的元素就是栈顶元素,右边还没出现,此时此元素入栈,记录L_first_min,当新加入的元素小于栈顶元素的时候,说明此时的元素就是栈顶元素右边第一个比他小的元素,那么栈顶元素出栈,一直到栈顶元素大于等于此元素为止,最终可以发现,栈中的元素一直是递增有序的。

数据是7 2 1 4 5 1 3 3,模拟一下。先压入0,作为左边最小元素
1.  2入栈,栈顶元素0<2,此时栈中元素 0,2
2.  1入栈,栈顶元素2>1,找到2右边比他小的,2出栈,1入栈,此时栈中元素0,1
3.  4入栈,栈顶元素1<4,4入栈,此时栈中元素0,1,4
4.  5入栈,栈顶4<5,此时栈中元素0,1,4,5
5.  1入栈,5,4分别出栈,同时记录5,4的R_first_min = 1,此时栈中元素0,1,1
6.  3入栈,栈中元素0,1,1,3
7.  3入栈,栈中元素0,1,1,3,3
8.  最后0入栈,作为右边最小元素的边界

建议数组实现栈,缩短用时。以上就是模拟单调栈的过程,放一下代码。
代码实现:

/*
Look at the star
Look at the shine for U
*/ 

#include<bits/stdc++.h>
#define sl(x) scanf("%lld",&x)
using namespace std;
typedef long long ll;
const int N = 1e6+5;
const ll mod = 1e9+7;
const int INF = 0x3f3f3f3f;
ll s[N],sta[N],top = 0,L[N],R[N];
int main()
{
	ll n,i,j,k,t;
	while(~scanf("%lld",&n) && n)
	{
		top = 0;
		for(i = 1;i <= n;i++) sl(s[i]);s[n+1] = 0;
		sta[top++] = 0;      //压入0作为左起点 
		for(i = 1;i <= n+1;i++)
		{
			while(s[sta[top-1]] > s[i] && top >= 1) top--,R[sta[top]] = i;
			L[i] = sta[top-1];sta[top++] = i;
		}
		
		ll maxx = 0;
		for(i = 1;i <= n;i++) maxx = max(maxx,1ll*(R[i]-L[i]-1)*s[i]);
	    printf("%lld\n",maxx);
	}
}

BZOJ 1113 

别BZOJ吓到,这个题属于简单题吧,水水就过了吧,此题只需要看高度啊,根本和宽度没关系,还有啊,下面画的那个图简直就是误导啊,出题人就是这么坏,维护一个高度递减的序列,每当栈顶元素 == 入栈的元素的时候,ans++,代表高度相同,可以用一个矩形表示,最后n-ans就ok了。

还是放一下代码吧:

/*
Look at the star
Look at the shine for U
*/ 

#include<bits/stdc++.h>
#define sl(x) scanf("%lld",&x)
using namespace std;
typedef long long ll;
const int N = 1e6+5;
const ll mod = 1e9+7;
const int INF = 0x3f3f3f3f;
ll sta[N],top = 0,L[N],R[N];
int main()
{
	ll n,x,y,i,j,k,t;
	sl(n);
	ll ans = 0;
	for(i = 0;i < n;i++)
	{
		sl(x);sl(y);
		
		while(top && sta[top] >= y) {top--;if(sta[top+1] == y) ans++;}
		sta[++top] = y;
	}
	printf("%lld\n",n-ans);
}

初步的单调栈就写到这吧,理解起来蛮简单的,单调队列的思想跟单调栈相同,下一篇博客就直接单调队列的进阶吧,关键是做题的时候能够随机应变。

猜你喜欢

转载自blog.csdn.net/Ever_glow/article/details/81304759