「解题报告」P9334 [JOISC 2023 Day2] Mizuyokan 2
首先大力 DP 就是
考虑分析大段的性质。首先大段有一个显然的必要条件,就是大段的和一定比段的左右两个数大,即
证明很简单,考虑左右两个段
那么考虑设
考虑如何修改。每次修改看起来会改变很多的
那么也就是说只有
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 250005, LOG = 65;
int n, q, a[MAXN];
int nxt[MAXN];
struct SegmentTree {
struct Node {
int l, r;
pair<int, int> a[LOG + 1];
pair<int, int> jmp(pair<int, int> q) {
auto [i, v] = q;
auto p = i <= min(r - l + 1, LOG) ? a[i] : make_pair(i - (r - l + 1), 0);
p.second += v;
return p;
}
Node operator+(Node b) {
Node c; c.l = l, c.r = b.r;
for (int i = 1; i <= min(c.r - c.l + 1, LOG); i++) c.a[i] = b.jmp(jmp(make_pair(i, 0)));
return c;
}
} t[MAXN << 2];
#define lc (i << 1)
#define rc (i << 1 | 1)
void update(int a, int b, int i = 1, int l = 0, int r = n) {
if (l == r) {
t[i].l = t[i].r = l;
t[i].a[1] = { nxt[l] - l, 1 };
return;
}
int mid = (l + r) >> 1;
if (a <= mid) update(a, b, lc, l, mid);
if (b > mid) update(a, b, rc, mid + 1, r);
t[i] = t[lc] + t[rc];
}
Node query(int a, int b, int i = 1, int l = 0, int r = n) {
if (a <= l && r <= b) return t[i];
int mid = (l + r) >> 1;
if (b <= mid) return query(a, b, lc, l, mid);
if (a > mid) return query(a, b, rc, mid + 1, r);
return query(a, b, lc, l, mid) + query(a, b, rc, mid + 1, r);
}
} st;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
a[0] = a[n + 1] = -1;
nxt[n + 1] = n + 1;
int cc = 0;
auto solve = [&](int l, int r) {
for (int i = r; i >= l; i--) {
nxt[i] = nxt[i + 1];
long long sum = 0;
for (int j = i + 2; j <= min(n, i + LOG); j++) {
sum += a[j];
cc++;
if (sum > a[i + 1] && sum > a[j + 1]) {
nxt[i] = min(nxt[i], j);
break;
}
}
}
st.update(l, r);
};
solve(0, n);
scanf("%d", &q);
while (q--) {
{
int x, y; scanf("%d%d", &x, &y);
a[x] = y;
solve(max(0, x - LOG), x);
}
{
int l, r; scanf("%d%d", &l, &r); l++;
int ans = 1;
int pre = r, suf = l;
long long sum = 0;
for (int i = l; i < r; i++) {
sum += a[i];
if (a[i + 1] < sum) {
pre = i;
break;
}
}
sum = 0;
for (int i = r; i > l; i--) {
sum += a[i];
if (a[i - 1] < sum) {
suf = i;
break;
}
}
auto query = [&](int l, int r) {
if (l > r && nxt[l - 1] >= r) return INT_MIN;
return 2 * (st.query(l - 1, r - 1).a[1].second - 1) + 1;
};
ans = max(ans, query(l, r));
ans = max(ans, query(pre + 1, r) + 1);
ans = max(ans, query(l, suf - 1) + 1);
ans = max(ans, query(pre + 1, suf - 1) + 2);
printf("%d\n", ans);
}
}
return 0;
}