JOISC 2022 D4T2 鱼 2
为了方便,设 \(a_0 = a_{n + 1} = \infty\)。
考虑拎出来所有区间 \([l, r]\) 使得 \(\sum\limits_{i = l}^r a_i < \min(a_{l - 1}, a_{r + 1})\)。那么 \([l, r]\) 中的所有鱼都不能吃到 \([l, r]\) 外面的鱼。那么 \([1, n]\) 中能吃掉所有鱼的鱼,一定不被除了 \([1, n]\) 之外的区间包含。
考虑从 \([i, i]\) 开始,通过线段树上二分得到包含它的最小的区间 \([l, r]\) 使得 \(\sum\limits_{i = l}^r a_i < \min(a_{l - 1}, a_{r + 1})\)。每次跳出去区间和至少加倍,所以至多跳 \(\log V\) 次。所以这样的区间有 \(O(n \log V)\) 种。加上线段树上二分的 \(\log n\),找出所有这样的区间的复杂度为 \(O(n \log n \log V)\)。
先考虑没有修改:因为不能往 \([l, r]\) 外面吃了,所以可能会导致 \([l, r]\) 的一个前缀和后缀不能吃完 \([l, r]\) 了。我们用上面的方法可以找到这样的前缀和后缀。我们把不能往外面吃的鱼的区间拎出来,给它们区间加 \(1\),查询即查询 \([l, r]\) 最小值个数(因为还有一些大区间 \(L \le l \le r \le R\) 完全包含 \([l, r]\))。
有修改的话,我们找出所有包含 \(x - 1, x, x + 1\) 的区间(要 \(\pm 1\) 是因为修改 \(x\) 可能会影响所有 \(r = x - 1\) 或者 \(l = x + 1\) 的区间),把它们删除,修改后重新加入即可。
所以总复杂度就是 \(O((n + q) \log n \log V)\)。
代码写起来有点臭。
code
// Problem: P9530 [JOISC 2022 Day4] 鱼 2
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P9530
// Memory Limit: 1 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<int, int> pii;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline int read() {
char c = getchar();
int x = 0;
for (; !isdigit(c); c = getchar()) ;
for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x;
}
const int maxn = 100100;
ll n, m, a[maxn];
namespace BIT {
ll c[maxn];
inline void update(ll x, ll d) {
for (int i = x; i <= n; i += (i & (-i))) {
c[i] += d;
}
}
inline ll query(ll x) {
ll res = 0;
for (int i = x; i; i -= (i & (-i))) {
res += c[i];
}
return res;
}
inline ll query(int l, int r) {
return query(r) - query(l - 1);
}
}
namespace SGT {
ll mx[maxn << 2];
inline void pushup(int x) {
mx[x] = max(mx[x << 1], mx[x << 1 | 1]);
}
void build(int rt, int l, int r) {
if (l == r) {
mx[rt] = a[l];
return;
}
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
pushup(rt);
}
void update(int rt, int l, int r, int x, ll y) {
if (l == r) {
mx[rt] = y;
return;
}
int mid = (l + r) >> 1;
(x <= mid) ? update(rt << 1, l, mid, x, y) : update(rt << 1 | 1, mid + 1, r, x, y);
pushup(rt);
}
ll query(int rt, int l, int r, int x) {
if (l == r) {
return mx[rt];
}
int mid = (l + r) >> 1;
return (x <= mid) ? query(rt << 1, l, mid, x) : query(rt << 1 | 1, mid + 1, r, x);
}
int findl(int rt, int l, int r, ll x) {
if (mx[rt] < x) {
return -1;
}
if (l == r) {
return l;
}
int mid = (l + r) >> 1;
if (mx[rt << 1] >= x) {
return findl(rt << 1, l, mid, x);
} else {
return findl(rt << 1 | 1, mid + 1, r, x);
}
}
int findr(int rt, int l, int r, ll x) {
if (mx[rt] < x) {
return -1;
}
if (l == r) {
return l;
}
int mid = (l + r) >> 1;
if (mx[rt << 1 | 1] >= x) {
return findr(rt << 1 | 1, mid + 1, r, x);
} else {
return findr(rt << 1, l, mid, x);
}
}
int findl(int rt, int l, int r, int ql, int qr, ll x) {
if (ql > qr || mx[rt] < x) {
return -1;
}
if (ql <= l && r <= qr) {
return findl(rt, l, r, x);
}
int mid = (l + r) >> 1;
if (ql <= mid) {
int t = findl(rt << 1, l, mid, ql, qr, x);
if (t != -1) {
return t;
}
}
if (qr > mid) {
int t = findl(rt << 1 | 1, mid + 1, r, ql, qr, x);
if (t != -1) {
return t;
}
}
return -1;
}
int findr(int rt, int l, int r, int ql, int qr, ll x) {
if (ql > qr || mx[rt] < x) {
return -1;
}
if (ql <= l && r <= qr) {
return findr(rt, l, r, x);
}
int mid = (l + r) >> 1;
if (qr > mid) {
int t = findr(rt << 1 | 1, mid + 1, r, ql, qr, x);
if (t != -1) {
return t;
}
}
if (ql <= mid) {
int t = findr(rt << 1, l, mid, ql, qr, x);
if (t != -1) {
return t;
}
}
return -1;
}
}
namespace SGT2 {
pii mn[maxn << 2];
int tag[maxn << 2];
inline pii operator + (const pii &a, const pii &b) {
int t = min(a.fst, b.fst);
return mkp(t, (a.fst == t ? a.scd : 0) + (b.fst == t ? b.scd : 0));
}
inline void pushup(int x) {
mn[x] = mn[x << 1] + mn[x << 1 | 1];
}
inline void pushdown(int x) {
if (!tag[x]) {
return;
}
mn[x << 1].fst += tag[x];
mn[x << 1 | 1].fst += tag[x];
tag[x << 1] += tag[x];
tag[x << 1 | 1] += tag[x];
tag[x] = 0;
}
void build(int rt, int l, int r) {
mn[rt] = mkp(0, r - l + 1);
if (l == r) {
return;
}
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
}
void update(int rt, int l, int r, int ql, int qr, int x) {
if (ql > qr) {
return;
}
if (ql <= l && r <= qr) {
mn[rt].fst += x;
tag[rt] += x;
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
if (ql <= mid) {
update(rt << 1, l, mid, ql, qr, x);
}
if (qr > mid) {
update(rt << 1 | 1, mid + 1, r, ql, qr, x);
}
pushup(rt);
}
pii query(int rt, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return mn[rt];
}
pushdown(rt);
int mid = (l + r) >> 1;
pii res = mkp(1e9, 0);
if (ql <= mid) {
res = res + query(rt << 1, l, mid, ql, qr);
}
if (qr > mid) {
res = res + query(rt << 1 | 1, mid + 1, r, ql, qr);
}
return res;
}
}
vector<pii> vc;
inline void find(int x) {
if (x < 1 || x > n) {
return;
}
int l = x, r = x;
ll s = a[x];
while (1 <= l && r <= n) {
int pl = SGT::findr(1, 0, n + 1, 0, l - 1, s + 1), pr = SGT::findl(1, 0, n + 1, r + 1, n + 1, s + 1);
l = pl + 1;
r = pr - 1;
s = BIT::query(l, r);
if (min(a[pl], a[pr]) > s) {
vc.pb(l, r);
if (a[pl] <= a[pr]) {
s += a[--l];
} else {
s += a[++r];
}
}
}
}
const int mod = 114514191;
struct HashTable {
int head[mod + 3], len, nxt[maxn * 100];
pii val[maxn * 100];
bool sta[maxn * 100];
inline bool add(pii p) {
int x = (1LL * p.fst * n + p.scd) % mod;
for (int i = head[x]; i; i = nxt[i]) {
if (val[i] == p) {
if (sta[i]) {
return 0;
} else {
sta[i] = 1;
return 1;
}
}
}
val[++len] = p;
nxt[len] = head[x];
sta[len] = 1;
head[x] = len;
return 1;
}
inline bool del(pii p) {
int x = (1LL * p.fst * n + p.scd) % mod;
for (int i = head[x]; i; i = nxt[i]) {
if (val[i] == p) {
if (sta[i]) {
sta[i] = 0;
return 1;
} else {
return 0;
}
}
}
return 0;
}
} S;
void solve() {
n = read();
a[0] = a[n + 1] = 1e18;
for (int i = 1; i <= n; ++i) {
a[i] = read();
BIT::update(i, a[i]);
}
m = read();
SGT::build(1, 0, n + 1);
SGT2::build(1, 1, n);
for (int i = 1; i <= n; ++i) {
vector<pii>().swap(vc);
find(i);
for (pii p : vc) {
if (S.add(p)) {
SGT2::update(1, 1, n, p.fst, p.scd, 1);
}
}
}
while (m--) {
ll op, x, y;
op = read();
x = read();
y = read();
if (op == 1) {
vector<pii>().swap(vc);
find(x - 1);
find(x);
find(x + 1);
for (pii p : vc) {
if (S.del(p)) {
SGT2::update(1, 1, n, p.fst, p.scd, -1);
}
}
BIT::update(x, y - a[x]);
SGT::update(1, 0, n + 1, x, y);
a[x] = y;
vector<pii>().swap(vc);
find(x - 1);
find(x);
find(x + 1);
for (pii p : vc) {
if (S.add(p)) {
SGT2::update(1, 1, n, p.fst, p.scd, 1);
}
}
} else {
int p = x, pl = x - 1, pr = y + 1;
ll s = a[x];
while (1) {
p = SGT::findl(1, 0, n + 1, p + 1, y, s + 1);
if (p == -1) {
break;
}
s = BIT::query(x, p);
if (a[p] > s - a[p]) {
pl = p - 1;
}
}
p = y;
s = a[y];
while (1) {
p = SGT::findr(1, 0, n + 1, x, p - 1, s + 1);
if (p == -1) {
break;
}
s = BIT::query(p, y);
if (a[p] > s - a[p]) {
pr = p + 1;
}
}
SGT2::update(1, 1, n, x, pl, 1);
SGT2::update(1, 1, n, pr, y, 1);
printf("%d\n", SGT2::query(1, 1, n, x, y).scd);
SGT2::update(1, 1, n, x, pl, -1);
SGT2::update(1, 1, n, pr, y, -1);
}
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}