CF817D Solution
题解
⭐:单调栈可以维护\([1,i]\)中大于或小于\(a_i\)的元素。
由于数据范围枚举左右端点并不现实,因此想到求出每个元素对于答案的贡献。设\([1,i)\)中最后一个\(>a_i\)的数为\(l\),\((i,n]\)中第一个\(>a_i\)的数为\(r\),\((r,l)\)即为\(a_i\)作为最大值的最大区间,其中\(l,r\)可用单调栈求出。利用乘法原理可知\(a_i\)作为最大值的区间数\(=(i-l)(r-i)\),而对答案的贡献为区间数\(\times a_i\)。 最小值同理,最终答案即为最大值贡献和\(-\)最小值贡献和。
AC代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int a[N],st[N],lg[N],rg[N],ll[N],rl[N],top;
//ll/lr[i]:a[i]作为最大值的最大区间左/右端点,lg/rg[i]:a[i]作为最小值的最大区间左/右端点
signed main()
{
int n,sum1=0,sum2=0;//sum1:最大值贡献和,sum2:最小值贡献和
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
{
while(top && a[st[top]]>=a[i]) top--;
lg[i]=i-st[top]; st[++top]=i;
}
top=0,st[0]=n+1;
for(int i=n;i>=1;i--)
{
while(top && a[st[top]]>a[i]) top--;
rg[i]=st[top]-i; st[++top]=i;
}
top=0,st[0]=0;
for(int i=1;i<=n;i++)
{
while(top && a[st[top]]<=a[i]) top--;
ll[i]=i-st[top]; st[++top]=i;
}
top=0,st[0]=n+1;
for(int i=n;i>=1;i--)
{
while(top && a[st[top]]<a[i]) top--;
rl[i]=st[top]-i; st[++top]=i;
}
for(int i=1;i<=n;i++) {sum1+=ll[i]*rl[i]*a[i]; sum2+=lg[i]*rg[i]*a[i];}
printf("%lld",sum1-sum2);
return 0;
}