单调栈+线段树
Posted ccut-ry
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单调栈+线段树相关的知识,希望对你有一定的参考价值。
Alice has a magic array. She suggests that the value of a interval is equal to the sum of the values in the interval, multiplied by the smallest value in the interval.
Now she is planning to find the max value of the intervals in her array. Can you help her?
Input
First line contains an integer n(1 \le n \le 5 \times 10 ^5n(1≤n≤5×105).
Second line contains nn integers represent the array a (-10^5 \le a_i \le 10^5)a(−105≤ai?≤105).
Output
One line contains an integer represent the answer of the array.
样例输入
5 1 2 3 4 5
样例输出
36
陈你
题意 : 给你 n 个元素,有正有负,要求你去寻找一个区间,要求区间中最小的元素乘以此元素所在的一段区间的和要最大,输出最大值
思路分析:
若元素全为正,显然就是单调栈的入门题了,但是现在元素有负的,因此需要换个角度去考虑
借助单调栈,我们可以找到每个元素作为最小值所在的区间
假设现在选取的一个元素是负的,那么我们是不就要找一段负的区间的和最小,乘起来才会使最大
那么这个时候就可以借助前缀和,该位置右边的最小值减去左边的最大值即可,若左边最大值小于0,此时就不要减去
用线段树去维护
一直有个地方写错,就是单调栈找每个元素所在区间的地方
代码示例:
#define ll long long const ll maxn = 5e5+5; const ll mod = 1e9+7; const double eps = 1e-9; const double pi = acos(-1.0); const ll inf = 0x3f3f3f3f; ll n; ll a[maxn]; ll lf[maxn], rf[maxn]; struct pp { ll num, id; }; struct pp sta[maxn]; struct node { ll l, r; ll mm, mi; }t[maxn<<2]; #define lson k<<1 #define rson k<<1|1 ll sum[maxn]; void init(){ ll top = 0; a[n+1] = -999999999; for(ll i = 1; i <= n+1; i++){ while(top > 0 && sta[top].num > a[i]){ rf[sta[top].id] = i-1; top--; } sta[++top] = {a[i], i}; } top = 0; for(ll i = 1; i <= n+1; i++){ ll pos = i; while(top > 0 && sta[top].num > a[i]){ pos = sta[top].id; top--; } sta[++top] = {a[i], pos}; lf[i] = pos; } } void build(ll l, ll r, ll k){ t[k].l = l, t[k].r = r; if (l == r){ t[k].mm = t[k].mi = sum[l]; return; } ll mid = (l+r)>>1; build(l, mid, lson); build(mid+1, r, rson); t[k].mm = max(t[lson].mm, t[rson].mm); t[k].mi = min(t[lson].mi, t[rson].mi); } ll qmax(ll l, ll r, ll k){ ll ans = -1e18; if (l <= t[k].l && t[k].r <= r) { return t[k].mm; } ll mid = (t[k].l+t[k].r)>>1; if (l <= mid) ans = max(ans, qmax(l, r, lson)); if (r > mid) ans = max(ans, qmax(l, r, rson)); return ans; } ll qmin(ll l, ll r, ll k){ ll ans = 1e18; if (l <= t[k].l && t[k].r <= r) { return t[k].mi; } ll mid = (t[k].l+t[k].r)>>1; if (l <= mid) ans = min(ans, qmin(l, r, lson)); if (r > mid) ans = min(ans, qmin(l, r, rson)); return ans; } void solve(){ for(ll i = 1; i <= n; i++){ sum[i] = sum[i-1]+a[i]; } ll ans = 0; build(1, n, 1); for(ll i = 1; i <= n; i++){ if (a[i]>0) ans = max(ans, (sum[rf[i]]-sum[lf[i]-1])*a[i]); else { ans = max(ans, a[i]*(qmin(i, rf[i], 1ll)-max(qmax(lf[i], i, 1ll), 0ll))); } } printf("%lld\n", ans); } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); cin >> n; for(ll i = 1; i <= n; i++){ scanf("%lld", &a[i]); } init(); solve(); return 0; }
以上是关于单调栈+线段树的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 780G Andryusha and Nervous Barriers 线段树套set || 线段树套单调栈