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;
}