2019牛客多校第四场C-sequence(单调栈+线段树)

sequence

题目传送门

解题思路

用单调栈求出每个a[i]作为最小值的最大范围。对于每个a[i],我们都要乘以一个以a[i]为区间内最小值的对应的b的区间和s,如果a[i] > 0,则s要尽量大,如果a[i] < 0,则s要尽量小。因为一段区间的和可以利用前缀和c[]相减求出,而以a[i]为最小值的区间和为:c[i~r] - c[l-1~i-1]。 所以用b[i]的前缀和建立线段树,维护其最大最小值。要求最大的s,即为求ir内的最大前缀和与l-1i-1范围内的最小前缀和。求最小的s同理。

代码如下

#include <bits/stdc++.h>
#define INF 5223372036854775807LL
using namespace std;
typedef long long ll;

inline int read(){
    int res = 0, w = 0; char ch = 0;
    while(!isdigit(ch)){
        w |= ch == '-', ch = getchar();
    }
    while(isdigit(ch)){
        res = (res << 3) + (res << 1) + (ch ^ 48);
        ch = getchar();
    }
    return w ? -res : res;
}

const int N = 3000005;

ll a[N], b[N];
ll c[N];
struct T{
    int l, r;
    ll maxx, minn;
}tree[N<<2];

void build(int k, int l, int r)
{
    tree[k].l = l;
    tree[k].r = r;
    if(l == r){
        tree[k].maxx = tree[k].minn = c[l];
        return;
    }
    int mid = (l + r) / 2;
    build(2*k, l, mid);
    build(2*k+1, mid + 1, r);
    tree[k].maxx = max(tree[2*k].maxx, tree[2*k+1].maxx);
    tree[k].minn = min(tree[2*k].minn, tree[2*k+1].minn);
}

ll query_minn(int k, int l, int r)
{
    if(tree[k].l >= l && tree[k].r <= r)
        return tree[k].minn;
    int mid = (tree[k].l + tree[k].r) / 2;
    ll m1 = INF, m2 = INF;
    if(l <= mid)
        m1 = query_minn(2*k, l, r);
    if(r > mid)
        m2 = query_minn(2*k+1, l, r);
    return min(m1, m2);
}

ll query_maxx(int k, int l, int r)
{
    if(tree[k].l >= l && tree[k].r <= r)
        return tree[k].maxx;
    int mid = (tree[k].l + tree[k].r) / 2;
    ll m1 = -INF, m2 = -INF;
    if(l <= mid)
        m1 = query_maxx(2*k, l, r);
    if(r > mid)
        m2 = query_maxx(2*k+1, l, r);
    return max(m1, m2);
}

int l[N], r[N];
int dq[N];

int main()
{
    int n;
    n = read();
    for(int i = 1; i <= n; i ++)
        a[i] = read();
    for(int i = 1; i <= n; i ++)
        b[i] = read();
    for(int i = 1; i <= n; i ++)
        c[i] = c[i - 1] + b[i];
    build(1, 1, n);
    int ql, qr;
    ql = qr = 0;
    for(int i = 1; i <= n; i ++){
        while(ql != qr && a[dq[qr - 1]] >= a[i])
            qr --;
        if(ql != qr)
            l[i] = dq[qr - 1] + 1;
        else
            l[i] = 1;
        dq[qr++] = i;
    }
    ql = qr = 0;
    for(int i = n; i >= 1; i --){
        while(ql != qr && a[dq[qr - 1]] >= a[i])
            qr --;
        if(ql != qr)
            r[i] = dq[qr - 1] - 1;
        else
            r[i] = n;
        dq[qr++] = i;
    }
    ll ans = -INF;
    for(int i = 1; i <= n; i ++){
        if(a[i] < 0){
            ans = max(ans, a[i] * (query_minn(1, i, r[i]) - query_maxx(1, l[i] - 1, i - 1)));
        }
        else if(a[i] > 0){
            ans = max(ans, a[i] * (query_maxx(1, i, r[i]) - query_minn(1, l[i] - 1, i - 1)));
        }
        else
            ans = max(ans, 0LL);
    }
    cout << ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/whisperlzw/p/11262756.html