单调栈--

ios::sync_with_stdio(false);

算法学习笔记(67): 单调栈 - 知乎 (zhihu.com)

模板

1.普通应用

 [1,2,3,4,3,2,1]

求左面第一个小于等于a[i](单调递增栈),求右面第一个小于等于a[i](将数组反过来遍历)

for(int i=0;i<n;i++){
	while(!top&&a[s[top]]>a[i])top--;
	int now=s[top];
	last[i]=now;//last为a[i]左面第一个小于等于a[i]的下标 
	s[++top]=i;
}

 二.两元素间所有元素均(不)大/小于这两者问题(让此数和栈顶比较)

for(int i=0;i<n;i++){
		int x=read();
		int cnt=0;
		while(!q.empty()&&q.top().first<=x){
			if(q.top().first==x)
				cnt=q.top().second;
				ans+=q.top().second;
				q.pop();
		}
		if(!q.empty())ans++;
		q.emplace(x,cnt+1);
	}

对于单调递增栈 

1.栈中元素都是单调递增的

2.当栈顶元素出栈时,说明这个新元素栈顶元素向后查找的第一个比其小的元素

3.当出栈后,新栈顶元素出栈元素向前查找第一个比其小的元素 

http://bailian.openjudge.cn/practice/2559?lang=en_US

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#include<stack>
using namespace std;
int a[1000005];
int n,m;
int p[100005];
int r[100005];
int l[100005];

int main(){
	int w;
    while(cin>>n){
    	if(n==0)break;
    	memset(l,0,sizeof(l));
    	memset(r,0,sizeof(r));
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
		}stack<int>q;
		q.push(0);
		a[0]=-1;
		a[n+1]=-1;//注意,a[n]的前后要有判断 
		for(int i=1;i<=n+1;i++){
			while(a[q.top()]>a[i]){//当前高度大于栈顶高度时 
				int temp=q.top();//取出栈顶元素备用 
				q.pop();//出栈 
				r[temp]=i-temp;//刚刚栈顶元素,右面大于a[temp]的个数,包含a[temp] 
			}
			if(a[i]==a[q.top()]){//定于时 
				l[i]=l[q.top()]+i-q.top();
			}
			else{//小于时 
				l[i]=i-q.top()-1;
			}
			q.push(i);
		}
		long long ans=-1;
		for(int i=1;i<=n;i++){
			ans=max(ans,(long long)a[i]*(l[i]+r[i]));
		}
		cout<<ans<<endl;
}
}

https://www.luogu.com.cn/problem/P5788

#include<iostream>
#include<stack>
using namespace std;
const int N=3000005;
int l[N],r[N],a[N],ans[N];
#define IFN 1e9+6;
int main(){
	int n;
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	stack<int>q;
	q.push(0);
	a[0]=IFN;
	a[n+1]=IFN;
	for(int i=1;i<=n;i++){
		while(a[i]>a[q.top()]){
			int temp=q.top();
			q.pop();
			ans[temp]=i;
		}
		q.push(i);
	}
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<' ';
	}
}

记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) (单调栈优化DP)

#include<iostream>
#include<stack>
using namespace std;
const int N=500005;
long long a[N];
long long s[N];
long long dpl[N],dpr[N];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	int top=0;
	for(int i=1;i<=n;i++){
		while(top&&a[s[top]]>a[i])top--;
		int now=s[top];
		dpl[i]=a[i]*(i-now)+dpl[now];
		s[++top]=i;
	}
	while(top)top--;
	s[++top]=n+1;
	for(int i=n;i>0;i--){
		while(top&&a[s[top]]>a[i])top--;
		int now=s[top];
		dpr[i]=a[i]*(now-i)+dpr[now];
		s[++top]=i;
	}
	long long ans=0;
	int p=0;
	for(int i=1;i<=n;i++){
		if(dpr[i]+dpl[i]-a[i]>ans){
			ans=dpr[i]+dpl[i]-a[i];
			p=i;
		}
	}
	int cnt=a[p];
	for(int i=p;i>0;i--){
		if(a[i]>=cnt){
			a[i]=cnt;
		}
		else {
			cnt=a[i];
		}
	}
	cnt=a[p];
	for(int i=p;i<=n;i++){
		if(a[i]>=cnt){
			a[i]=cnt;
		}
		else {
			cnt=a[i];
		}
	}
	for(int i=1;i<=n;i++){
		cout<<a[i]<<' ';
	}
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值