题面:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/4f9ab187d097e59cf5443ab3dc4679b0.png)
这题如果a[i] > 0,则是一道经典的单调栈,如果针对a[i]大于0的情况不太清楚的话,可以参考我写的单调栈其他的题目,现在我们重点来讨论a[i] < 0的情况。
如果a[i]小于零,则应该使得包含a[i]的区间和最小,即找到1~i区间上最大的前缀和lmax,和i-n区间上最小的前缀和rmin,然后两者相减得到最小的区间前缀和,很容易联想到用线段树来维护区间前缀的最值,这是比较无脑的算法,但是很好想到:
要注意的是,当左边前缀和的最小值小于0的时候,不用减,因为负数减负数反而会使包含a[i]的最小前缀区间变大
时间复杂度O(nlog(n))
#pragma G++ optimize(2)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<stack>
#include<vector>
#include<iostream>
#include<climits>
#include<queue>
#include<cassert>
#include<iomanip>
#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#define _rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for(int i = (a); i >= (b); --i)
#define _for(i, a, b) for(int i = (a); i <(b); ++i)
#define _rof(i, a, b) for(int i = (a); i >(b); --i)
#define maxn 500009
#define maxm 109
#define ll long long
#define met(a,b) memset((a),(b), sizeof(a))
#define db double
#define oo INT_MAX
#define eps 1e-8
using namespace std;
ll a[maxn], l[maxn], r[maxn], s[maxn], n, sum[maxn], lmax[maxn], rmax[maxn];
struct node
{
int l, r, min, max;
}t[maxn * 4];
void update(int o) {
t[o].min = min(t[o << 1].min, t[o << 1 | 1].min);
t[o].max = max(t[o << 1].max, t[o << 1 | 1].max);
}
void build(int o, int l, int r) {
t[o].l = l, t[o].r = r;
if (l == r) {
t[o].min = t[o].max = sum[l];
return;
}
ll mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
update(o);
}
inline node ask(int o, int l, int r) {
assert(l <= r);
if (t[o].l == l && t[o].r == r)return t[o];
ll mid = (t[o].l + t[o].r) >> 1;
if (l > mid) return ask(o << 1 | 1, l, r);
else if (r <= mid)return ask(o << 1, l, r);
else {
node a, b, c;
a = ask(o << 1, l, mid);
b = ask(o << 1 | 1, mid + 1, r);
c.min = min(a.min, b.min);
c.max = max(a.max, b.max);
return c;
}
}
int main()
{
while (cin >> n) {
_rep(i, 1, n) {
cin >> a[i];
sum[i] = a[i] + sum[i - 1];
}
build(1, 1, n);
int top = 0;
_rep(i, 1, n) {
while (top && a[s[top]] >= a[i]) top--;
l[i] = top ? s[top] + 1 : 1;
s[++top] = i;
}
top = 0;
_rev(i, n, 1) {
while (top && a[s[top]] >= a[i]) top--;
r[i] = top ? s[top] - 1 : n;
s[++top] = i;
}
ll ans = 0;
_rep(i, 1, n) {
if (a[i] > 0) {
ans = max(ans, (ll)a[i] * (sum[r[i]] -
sum[l[i] - 1]));
}
else {
ll lmax = ask(1, 1, i>=2?i - 1: 1).max;
ll rmin = ask(1, i, n).min;
ll c = lmax <= 0 ? rmin : rmin - lmax;
ans = max(ans, c * a[i]);
}
}
cout << ans << endl;
}
}