题解 CF817D 【Imbalanced Array】
题意简述
给你一个长度为
转化题意
如果直接暴力统计,时间复杂度为
所以我们需要对计算方法进行优化。
我们可以考虑对于每个
这里以最大值为例。
显然,对于每一个
我们可以看到,对于节点
其左端点的极左点为在该数左边且从后往前数第一个大于
其右端点的极有点为在该数右边且从前往后数第一个大于
而且我们可以看到,对于每一个数,由于左右端点每个可以各选一个。由乘法原理可得每个
最后求出每一个数对答案的贡献并求和。
单调栈优化
前面讲到了如何利用左右端点求出所有的贡献,但暴力求
所以我们要祭出一个好东西:单调栈
单调栈,可以简单理解为不会从队头出只会从队尾出的单调队列,但只能从队尾取出。
也就是说我们可以省略掉
以
但由于要取
详细过程:
最开始将
对于每次查询,如果
否则从将栈中的元素一一弹出,直到
将
一些提示
- 答案会爆
longlong - 注意,求
r_i 时栈顶必须大于等于r_i 而不是大于 - 记得求
\max 时将a_0 和a_{n+1} 赋值为无穷大
Code
#include<bits/stdc++.h>
using namespace std;
int sta[1000002],a[1000002],n,mxl[1000001],mxr[1000001],mil[1000001],mir[1000001],h;
long long ans;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
sta[1]=0;h=1;
for(int i=1;i<=n;i++)
{
if(a[i]>a[sta[h]])sta[++h]=i,mil[i]=i-1;
else
{
while(a[i]<a[sta[h]])h--;
mil[i]=sta[h];
sta[++h]=i;
}
}
sta[1]=n+1;h=1;
for(int i=n;i>=1;i--)
{
if(a[i]>a[sta[h]])sta[++h]=i,mir[i]=i+1;
else
{
while(a[i]<=a[sta[h]])h--;
mir[i]=sta[h];
sta[++h]=i;
}
}
a[0]=a[n+1]=0x7fffffff;
sta[1]=0;h=1;
for(int i=1;i<=n;i++)
{
if(a[i]<a[sta[h]])sta[++h]=i,mxl[i]=i-1;
else
{
while(a[i]>a[sta[h]])h--;
mxl[i]=sta[h];
sta[++h]=i;
}
}
sta[1]=n+1;h=1;
for(int i=n;i>=1;i--)
{
if(a[i]<a[sta[h]])sta[++h]=i,mxr[i]=i+1;
else
{
while(a[i]>=a[sta[h]])h--;
mxr[i]=sta[h];
sta[++h]=i;
}
}
//for(int i=1;i<=n;i++)
//cout<<mil[i]<<' '<<mir[i]<<' '<<mxl[i]<<' '<<mxr[i]<<endl;
for(int i=1;i<=n;i++)
ans+=1ll*a[i]*(1ll*(i-mxl[i])*(mxr[i]-i)-1ll*(i-mil[i])*(mir[i]-i));
cout<<ans;
}