JOISC 2022 D4T2 鱼 2

发布时间 2023-09-11 17:20:31作者: zltzlt

洛谷传送门

LOJ 传送门

为了方便,设 \(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;
}