数组的宽度 单调栈

Posted cindy-chan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组的宽度 单调栈相关的知识,希望对你有一定的参考价值。

N个整数组成的数组,定义子数组a[i]..a[j]的宽度为:max(a[i]..a[j]) - min(a[i]..a[j]),求所有子数组的宽度和。

分析:

我们只要统计每个数做为最小的数和最大的数所在区间有多少个。这样求当前数作为最大的数左右范围,这个用单调栈维护下,同理最小的也是
然后左区间大小乘右区间大小就是这个数作为最大的出现的区间数;

以1 5 4 2 3为例,逐个入栈计算每个数的右边界:

1入栈 => 1

5入栈,前面所有比5小的出栈,并将右边界设为5 => 5 (确定了1的右边界是5,对应下标为1)

4入栈,前面所有比4小的出栈,并将右边界设为4 => 5 4

2入栈,前面所有比2小的出栈,并将右边界设为2 => 5 4 2

3入栈,前面所有比3小的出栈,并将右边界设为3 => 5 4 3(确定了2的右边界是3,对应下标为4)

最后所有数出栈,将5 4 3这3个数的右边界的下标设为5。

这样可以确认,每个数字最多进一次栈出一次栈,所有复杂度是O(n)的。

代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int M=50007,inf=0x3f3f3f3f;
int read()
    int ans=0,f=1,c=getchar();
    while(c<0||c>9)if(c==-) f=-1; c=getchar();
    while(c>=0&&c<=9)ans=ans*10+(c-0); c=getchar();
    return ans*f;

int n,w1[M],w2[M];
int sk1[M],tp1,sk2[M],tp2;
LL mx,mn;
int main()

    n=read();
    for(int i=1;i<=n;i++) w1[i]=w2[i]=read();
    n++; w1[n]=inf; w2[n]=-1;
    for(int i=1;i<=n;i++)
    while(tp1&&w1[i]>=w1[sk1[tp1]]) mx+=1LL*w1[sk1[tp1]]*(i-sk1[tp1])*(sk1[tp1]-sk1[tp1-1]),tp1--;
        while(tp2&&w2[i]<=w2[sk2[tp2]]) mn+=1LL*w2[sk2[tp2]]*(i-sk2[tp2])*(sk2[tp2]-sk2[tp2-1]),tp2--;
        sk1[++tp1]=sk2[++tp2]=i;
    
    printf("%lld\n",mx-mn);
    return 0;

 

 
 

以上是关于数组的宽度 单调栈的主要内容,如果未能解决你的问题,请参考以下文章

51nod 1215 单调栈/迭代

LeetCode单调栈合集

用数组模拟栈 队列 以及单调栈 单调队列应用

用数组模拟栈 队列 以及单调栈 单调队列应用

[单调栈] aw3780. 构造数组(递推+单调栈+枚举+aw周赛009_3)

51nod 1279 单调栈