题目大意:
然后就i是输入一个整数n,然后输入n个整数,然后求这个区间的子区间的最大值最小值的差值的和;
基本思路:
转化为用单调栈求每一个值作为最大值和最小值能管到的区间范围,然后求每一个以该值为最大值的区间的个数然后乘以这个最大值加到res上,在求出以该值为最小值的区间个数乘以这个值,然后res减去这个值,最终就等效于求出了所有子区间最大值与最小值的差值的和;
代码如下:
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<list>
#include<stack>
#include<map>
#include<set>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1000000+10;
typedef long long ll;
int ans[maxn],lmax[maxn],rmax[maxn],lmin[maxn],rmin[maxn];
int main()
{
stack<int>s1,s2,s3,s4;
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&ans[i]);
for(int i=1;i<=n;i++)
{
while(!s1.empty()&&ans[s1.top()]>=ans[i]) s1.pop();
if(s1.empty()) lmin[i]=1;
else lmin[i]=s1.top()+1;
s1.push(i);
}
for(int i=n;i>=1;i--)
{
while(!s2.empty()&&ans[s2.top()]>ans[i]) s2.pop();//注意这里是大于而不是大于等于,你想,如果是等于的话,就会求出许多重复的区间,因为有最大值可能相等的情况
//然后这样的话分别对这两个相同的值求左右能管到的范围是一样的,即求出了相同的区间,然后就有了重复;
if(s2.empty()) rmin[i]=n;
else rmin[i]=s2.top()-1;
s2.push(i);
}
for(int i=1;i<=n;i++)
{
while(!s3.empty()&&ans[s3.top()]<=ans[i]) s3.pop();
if(s3.empty()) lmax[i]=1;
else lmax[i]=s3.top()+1;
s3.push(i);
}
for(int i=n;i>=1;i--)
{
while(!s4.empty()&&ans[s4.top()]<ans[i]) s4.pop();
if(s4.empty()) rmax[i]=n;
else rmax[i]=s4.top()-1;
s4.push(i);
}
ll res=0,t;
for(int i=1;i<=n;i++)
{
t=(ll)(rmax[i]-i+1)*(i-lmax[i]+1)-(ll)(rmin[i]-i+1)*(i-lmin[i]+1);
res+=(t*(ll)ans[i]);
}
printf("%I64d\n",res);
return 0;
}