codeforces#round 795 D

D. Max GEQ Sum


要求所有的区间都满足最大值大于区间和

思路:

考虑每一个数字在他的区间里面的贡献,假设x在L到R中是最大值,那么要求l到r的最大子段和小于等于x就可以满足条件,x左右第一个大于x的数可以使用单调栈求解,区间最大子段和使用线段树

代码:

#include <bits/stdc++.h>
#define int long long
int _ = 0, Case = 1;
using namespace std;
#define all(v) begin(v),end(v)
#define nline '\n'

#define ls(x) x<<1
#define rs(x) x<<1 |1
#define N 500010
int a[N];
int life[N << 2];
struct tree {
    int l, r;
    int sum, lmax, rmax, smax;
} tr[N << 2];
void pushup(tree &p, tree &l, tree &r) {
    p.sum = l.sum + r.sum;
    p.lmax = max(l.lmax, l.sum + r.lmax);
    p.rmax = max(r.rmax, r.sum + l.rmax);
    p.smax = max({l.smax, r.smax, l.rmax + r.lmax});
}
void pushup(int p) {
    pushup(tr[p], tr[ls(p)], tr[rs(p)]);
}
void build(int p, int l, int r) {
    if (l == r) {
        tr[p] = {l, r, a[l], a[l], a[l], a[l]};
        life[l] = p;
    }
    else {
        tr[p] = {l, r};
        int mid = l + r >> 1;
        build(ls(p), l, mid);
        build(rs(p), mid + 1, r);
        pushup(p);
    }
}

void modify(int x, int y) {
    int t = x;
    x = life[x];
    tr[x] = {t, t, y, y, y, y};
    for (x >>= 1; x; x >>= 1) pushup(x);
}
tree query(int p, int l, int r) {
    if (tr[p].l >= l and tr[p].r <= r) return tr[p];
    int mid = tr[p].l + tr[p].r >> 1;
    if (r <= mid) return query(ls(p), l, r);
    else if (l > mid) return query(rs(p), l, r);
    else {
        tree ret;
        auto left = query(ls(p), l, r);
        auto right = query(rs(p), l, r);
        pushup(ret, left, right);
        return ret;
    }
}
int l[N], r[N], n;
void cal() {
    stack<int> stk;
    a[0] = 1e18;
    stk.push(0);
    for (int i = 1; i <= n; i++) {
        while (stk.size() and a[i] >= a[stk.top()]) stk.pop();
        l[i] = stk.top();
        stk.push(i);
    }
}
void cal1() {
    stack<int> stk;
    stk.push(n + 1);
    a[n + 1] = 1e18;
    for (int i = n; i >= 1; i--) {
        while (stk.size() and a[i] >= a[stk.top()]) stk.pop();
        r[i] = stk.top();
        stk.push(i);
    }
}
void solve(int Case) {
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
        l[i] = r[i] = 0;
    }
    build(1, 1, n);
    cal(), cal1();
    bool ok = true;
    for (int i = 1; i <= n; i++) {
        int L = l[i], R = r[i];
        L++, R--;
        if (a[i] < query(1, L, R).smax) ok = false;
    }
    if (ok) puts("Yes");
    else puts("No");




}

signed main() {
    for (scanf("%lld", &_), Case = 1; Case <= _; Case++)
        solve(Case);

    return 0;
}
posted @ 2022-06-05 17:29  指引盗寇入太行  阅读(44)  评论(0编辑  收藏  举报