单调栈(区间最值)

单调栈

关于单调栈的模板就不写了,可以参考下面的连接
https://blog.csdn.net/lucky52529/article/details/89155694
https://finixlei.blog.csdn.net/article/details/119065757
https://blog.csdn.net/weixin_42784951/article/details/88963758
简单说一下单调栈分为单调增栈和单调减栈,其中单调增栈从栈顶到栈底递增(1-n递减),单调减栈从顶到底减,(1-n递增),单调栈可以求当前数在某区间内下一个比他小/大的数,单调栈可以把这种问题的复杂度从O(n^2)降到O(n).
然后说一下我debug的历程经验,先是memset(虽然这个代码里面没有)的用法,应该是

int a[maxn];
memset(a,0,sizeof(a);

而不是

memset(a,0,sizeof(int));

后者在编译的时候不会给出错误提示,但是memset不会工作;
然后就是关于int 和long long的选用,题目是5e5数量级,我觉得int够了,只有最后的ans用了long long然后一直WA,其实后面的那个sum也是要用long long的,毕竟想想1e5个1e5的数相加就是1e10int肯定不够所以WA的时候也要看一下是不是int太小注意吧%d改成%lld

题目:

Max answer

Alice has a magic array. She suggests that the value of a interval is equal to the sum of the values in the interval, multiplied by the smallest value in the interval.

Now she is planning to find the max value of the intervals in her array. Can you help her?

Input
First line contains an integer n(1≤n≤5×1e5).
Second line contains n integers represent the array a(−1e5≤ai≤1e5)
Output
One line contains an integer represent the answer of the array.

Sample Input
5
1 2 3 4 5
Sample Output
36
题目出处:2019武昌赛区网络赛(计蒜客2828)
题解

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const long int maxn=1e6+10;
const int INF=0x3f3f3f3f;
struct node{
	ll k,l,r,sum;
	ll nub;
}data[maxn],stack[maxn];
ll top;
ll ans;
int main(){
	int n,i;
	stack[0].nub=-INF;
	data[0].nub=-INF;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%lld",&data[i].nub);
		data[i].k=i;
		data[i].sum=data[i-1].sum+data[i].nub;
	}
	data[i].nub=-INF;
	data[i].k=i;
	for(i=1;i<=n+1;i++)//计算向左横扫的端点
	//这里左右端点必须分开两次循环算,因为有可能有相等的元素,相等的元素用一次循环是不能同时算出左右端点的,会出错 
	//如果确定没有相等元素那么可以在一次循环里同时算出左右端点,右端点就是让栈顶元素弹出的i 
	{
		if(data[i].nub>stack[top].nub)//必须要严格大于栈顶元素才能直接入栈,否则会造成相同元素弹出更新时的错误计算 
			stack[++top]=data[i];
		else{
			while(top!=0&&stack[top].nub>=data[i].nub)//这里栈中的元素是从1-n严格单增的,不存在相等的情况,所以可以更新左端点 
			{
				data[stack[top].k].l=stack[top-1].k+1;
				top--;
			}
			stack[++top]=data[i];
		}
	}
	top=0;
	stack[0].k=n+1;
	for(i=n;i>=0;i--){//计算向右横扫的端点 
		if(data[i].nub>stack[top].nub)//同理 	
			stack[++top]=data[i];
		else{
			while(top!=0&&stack[top].nub>=data[i].nub){//同理更新右端点 
				data[stack[top].k].r=stack[top-1].k-1;
				top--;
			}
			stack[++top]=data[i];
		}
	}
	for(i=1;i<=n;i++){
		if(data[i].nub>=0)
			ans=max(ans,(ll)data[i].nub*(data[data[i].r].sum-data[data[i].l-1].sum));
		else{
			ll minn1=0,minn2=0,sumn=0;
			for(int j=i-1;j>=data[i].l;j--){
				sumn+=data[j].nub;
				minn1=min(minn1,sumn);
			}
			sumn=0;
			for(int j=i+1;j<=data[i].r;j++){
				sumn+=data[j].nub;
				minn2=min(minn2,sumn);
			}
			ans=max(ans,(ll)data[i].nub*(minn1+minn2+data[i].nub));
		}
	}
	printf("%lld\n",ans);
    return 0;
}



2021.7.30

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值