D. Imbalanced Array(单调队列(栈))

这题其实比较巧妙

\sum最大值-\sum最小值就是答案

( ) 所以只要求出每个数作为最大(小)值的次数就好了

也就是求每个数左边第一个比自己大的数和右边第一个比自己大的数

中间的区间都满足

可以用单调栈来维护

, 但这里有一个问题,当一个区间的最大值有多个

, 其实只有一个会作为最大值,但在刚才的计算中所有最大数都会作为最大值

这就很巧妙了

我们维护单调队列求解数的左边第一个比自己大的数时要严格比自己大

求解右边第一个比自己大的数时却可以相等

, 那么当一个区间有多个最大值时,只有最右边的数会被算一次

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e6+10;
int n,l[maxn],r[maxn],a[maxn];
int q[maxn],top,ans;
void work()
{
	q[0]=0,top=0;
	for(int i=1;i<=n;i++)
	{
		while( top &&a[ q[top] ]<=a[i] )	top--;
		l[i]=q[top]+1,q[++top]=i;
	}
	q[0]=n+1,top=0;
	for(int i=n;i>=1;i--)
	{
		while( top&&a[ q[top] ]<a[i] )	top--;
		r[i]=q[top]-1,q[++top]=i;
	}
	for(int i=1;i<=n;i++)	ans+=a[i]*( i-l[i]+1 )*(r[i]-i+1);
}
signed main()
{
	cin >> n;
	for(int i=1;i<=n;i++)	cin >> a[i];
	work();
	for(int i=1;i<=n;i++)	a[i]=-a[i];
	work();
	cout << ans;
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/107894218