N个整数组成的数组,定义子数组a[i]…a[j]的宽度为:max(a[i]…a[j]) - min(a[i]…a[j]),求所有子数组的宽度和。
输入
第1行:1个数N,表示数组的长度。(1 <= N <= 50000)
第2 - N + 1行:每行1个数,表示数组中的元素(1 <= A[i] <= 50000)
输出
输出所有子数组的宽度和。
输入样例
5
1
2
3
4
5
输出样例
20
使用单调栈处理出以a[i]为最小值和最大值的左右边界
答案为:sum : (i - Lmax[i]) * (Rmax[i] - i) * a[i] - (i - Lmin[i]) * (Rmin[i] - i) * a[i]
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn];
int Lmin[maxn], Rmin[maxn];
int Lmax[maxn], Rmax[maxn];
stack<int> s;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
a[0] = 0; a[n + 1] = 0;
for (int i = 1; i <= n + 1; i++) {
while (!s.empty() && a[s.top()] >= a[i]) {
Rmin[s.top()] = i;
s.pop();
}
s.push(i);
}
while (!s.empty()) s.pop();
for (int i = n; i >= 0; i--) {
while (!s.empty() && a[s.top()] > a[i]) {
Lmin[s.top()] = i;
s.pop();
}
s.push(i);
}
a[0] = 1e9; a[n + 1] = 1e9;
while (!s.empty()) s.pop();
for (int i = 1; i <= n + 1; i++) {
while (!s.empty() && a[s.top()] <= a[i]) {
Rmax[s.top()] = i;
s.pop();
}
s.push(i);
}
while (!s.empty()) s.pop();
for (int i = n; i >= 0; i--) {
while (!s.empty() && a[s.top()] < a[i]) {
Lmax[s.top()] = i;
s.pop();
}
s.push(i);
}
long long ans = 0;
for (int i = 1; i <= n; i++) {
ans += 1LL * (i - Lmax[i]) * (Rmax[i] - i) * a[i];
ans -= 1LL * (i - Lmin[i]) * (Rmin[i] - i) * a[i];
}
cout << ans << endl;
return 0;
}