给你
n
个数字,求所有子区间的最大数减最小数的和
我们考虑单独计算对于每个数字
i
能产生的贡献,即计算哪些子区间[l, r]
满足l<=i<=r
,且a[i]
作为区间最大值或者作为区间最小值时的贡献显然,最大值和最小值可以分开计算
对于
a[i]
我们找左边第一个大于a[i]
的位置+1,计作l
,找i
右边第一个大于a[i]
的位置-1,计作r
则
a[i]
作为最大值时的贡献应该是+ a[i]*(i-l+1)*(r-i+1)
但是由于存在相同的元素,所以就会重复计算某些区间的答案
比如:
5 5 5 5
,对于每个5都会找到l=1,r=4
,这样会重复计算答案为了避免这个情况,我们找
r
的时候可以找第一个大于等于a[i]
的位置-1作为r
,这样对于a[i]
找到的区间,最后一个等于a[i]
的位置一定是i
对于最小值的计算方法也一样
那如何快速地求位置
l
或者r
呢,我们可以用st
表+二分答案的方法来实现
过了以后才发现这个题正解是单调栈
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
typedef pair <int,int> pii;
#define MAX 500000 + 50
int n, m, k, x;
ll a, b;
int tr[MAX];
int lg[MAX];
int minx[MAX][22];
int maxn[MAX][22];
void init(){
for(int i = 2; i <= n; ++i){
lg[i] = lg[i / 2] + 1;
}
for(int i = 1; i <= n; ++i)minx[i][0] = maxn[i][0] = tr[i];
for(int j = 1; j <= lg[n]; ++j){
for(int i = 1; i + (1<<j) - 1 <= n; ++i){
maxn[i][j] = max(maxn[i][j-1], maxn[i + (1<<(j-1))][j-1]);
minx[i][j] = min(minx[i][j-1], minx[i + (1<<(j-1))][j-1]);
}
}
}
int cal_max(int l, int r){
int d = lg[r-l+1];
return max(maxn[l][d], maxn[r-(1<<d)+1][d]);
}
int cal_min(int l, int r){
int d = lg[r-l+1];
return min(minx[l][d], minx[r-(1<<d)+1][d]);
}
void work(){
cin >> n;
for(int i = 1; i <= n; ++i){
cin >> tr[i];
}
init();
ll ans = 0;
for(int i = 1; i <= n; ++i){
int l = 1, r = i;
while(l <= r){
int mid = (l + r) / 2;
if(cal_max(mid, i) == tr[i])r = mid - 1;
else l = mid + 1;
}
a = l;
l = i; r = n;
while(l <= r){
int mid = (l + r) / 2;
if(cal_max(i, mid) == tr[i])l = mid + 1;
else r = mid - 1;
}
b = l - 1;
ans += (b - a + 1) * tr[i];
l = 1; r = i;
while(l <= r){
int mid = (l + r) / 2;
if(cal_min(mid, i) == tr[i])r = mid - 1;
else l = mid + 1;
}
a = l;
l = i; r = n;
while(l <= r){
int mid = (l + r) / 2;
if(cal_min(i, mid) == tr[i])l = mid + 1;
else r = mid - 1;
}
b = l - 1;
ans -= (b - a + 1) * tr[i];
}
cout << ans << endl;
}
int main(){
io;
work();
return 0;
}