P7560 [JOISC 2021] フードコート题解

P7560 [JOISC 2021] フードコート题解

比较好想的一个题,至少我的做法比较自然。首先常规的想法是按照时间扫一遍维护每个店的信息。但是每次对于区间所有店进行修改维护信息未免显得有点吃操作了,因此一个套路是将店的信息和时间维进行交换,扫一遍每个物品同时动态用数据结构维护时间轴上的信息并处理每个询问,这样的话加入和离开可以差分成两个操作。现在考虑一个时间轴上有一些加入和离开的询问怎么快速处理每个询问。首先我们需要判断当前时刻状态剩余的人数。这个东西实际上就是把该时刻之前的所有信息合并起来。由于人数 \(<0\) 后会自动归零,这是 \((\max,+)\) 广义矩阵乘法可以很好维护的东西,上线段树维护一下转移矩阵乘积每次查询前缀就好。得到这个东西之后相当于我们要找当前存在的所有人里第 \(i\) 个被加入的是谁。维护当前第 \(i\) 个有点难,因为知道当前的人数所以可以转成倒数第 \(i\) 个。注意到由于一定有解,这第 \(i\) 个及之后加入的人一定都没有被删,这是一段都没有被删的后缀因此实际上就是要求时刻 \(t\) 前倒数第 \(i\) 个加入的人是谁而不用考虑删除,这个东西再上一个线段树维护后缀和在上面二分就是对的,那这题就做完了。代码不是很好写但也不难。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2.5e5 + 5, inf = 1e18;
int n, m, q;
struct Que {
	int o, t;
	int l, r, c, k;
} e[N];
int ans[N];

struct Mar {
	int a[2][2];
	Mar() {
		a[0][0] = a[0][1] = a[1][0] = a[1][1] = -inf;
	}
	Mar operator * (const Mar &x) const {
		Mar res;
		res.a[0][0] = max(a[0][0] + x.a[0][0], a[0][1] + x.a[1][0]);
		res.a[0][1] = max(a[0][0] + x.a[0][1], a[0][1] + x.a[1][1]);
		res.a[1][0] = max(a[1][0] + x.a[0][0], a[1][1] + x.a[1][0]);
		res.a[1][1] = max(a[1][0] + x.a[0][1], a[1][1] + x.a[1][1]);
		return res;
	}
} E, B, C;

int cid[N];
int tim[N], tot;
vector<int>vt[N];
vector<array<int, 2>>vin[N], vout[N];


namespace S1 {
	struct Node {
		int l, r;
		Mar w;
	} e[N << 2];
	#define l(i) e[i].l
	#define r(i) e[i].r
	#define w(i) e[i].w
	#define lc (p << 1)
	#define rc (lc | 1)
	inline void build(int p, int l, int r) {
		l(p) = l, r(p) = r, w(p) = E;
		if (l == r) return;
		int mid = (l + r) >> 1;
		build(lc, l, mid);
		build(rc, mid + 1, r);
	}
	inline void update(int p, int x, Mar w) {
		if (l(p) == r(p)) return w(p) = w, void();
		int mid = (l(p) + r(p)) >> 1;
		if (x <= mid) update(lc, x, w);
		else update(rc, x, w);
		w(p) = w(lc) * w(rc);
	}
	inline Mar query(int p, int l, int r) {
		if (l <= l(p) && r(p) <= r) return w(p);
		int mid = (l(p) + r(p)) >> 1;
		if (r <= mid) return query(lc, l, r);
		if (l > mid) return query(rc, l, r);
		return query(lc, l, r) * query(rc, l, r);
	}
	#undef l
	#undef r
}

namespace S2 {
	struct Node {
		int l, r;
		int mx, tg;
	} e[N << 2];
	#define l(i) e[i].l
	#define r(i) e[i].r
	#define mx(i) e[i].mx
	#define tg(i) e[i].tg
	inline void build(int p, int l, int r) {
		l(p) = l, r(p) = r;
		if (l == r) return;
		int mid = (l + r) >> 1;
		build(lc, l, mid);
		build(rc, mid + 1, r);
	}
	inline void tag_down(int p, int x) {
		tg(p) += x, mx(p) += x;
	}
	inline void push_down(int p) {
		if (tg(p)) {
			tag_down(lc, tg(p));
			tag_down(rc, tg(p));
			tg(p) = 0;
		}
	}
	inline void update(int p, int l, int r, int x) {
		if (l > r || l > r(p) || l(p) > r) return;
		if (l <= l(p) && r(p) <= r) return tag_down(p, x);
		push_down(p);
		update(lc, l, r, x), update(rc, l, r, x);
		mx(p) = max(mx(lc), mx(rc));
	}
	inline int query(int p, int x) {
		if (l(p) == r(p)) return mx(p);
		push_down(p);
		int mid = (l(p) + r(p)) >> 1;
		if (x <= mid) return query(lc, x);
		return query(rc, x);
	}
	inline int query(int p, int x, int t) {
		if (l(p) == r(p)) return mx(p) >= t ? l(p) : -1;
		push_down(p);
		int mid = (l(p) + r(p)) >> 1;
		if (x <= mid || mx(rc) < t) return query(lc, x, t);
		int w = query(rc, x, t);
		if (w == -1) return query(lc, x, t);
		return w;
	}
}

signed main() {
	E.a[0][0] = E.a[1][1] = 0, E.a[0][1] = E.a[1][0] = -inf;
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m >> q;
	tot = 1;
	for (int i = 1; i <= q; i++) {
		cin >> e[i].o >> e[i].l >> e[i].r;
		tot += (e[i].o < 3);
		if (e[i].o == 1) cin >> e[i].c >> e[i].k, cid[tot] = e[i].c;
		else if (e[i].o == 2) cin >> e[i].k, e[i].k *= -1;
		e[i].t = i, tim[i] = tot;
	}
	for (int i = 1; i <= q; i++) {
		if (e[i].o < 3) {
			vin[e[i].l].push_back({tim[i], e[i].k});
			vout[e[i].r + 1].push_back({tim[i], -e[i].k});
		}
		else vt[e[i].l].push_back(i);
	}
	B.a[0][1] = -inf, B.a[1][0] = B.a[1][1] = 0;
	C.a[0][0] = C.a[0][1] = C.a[1][0] = C.a[1][1] = 0;
	S1::build(1, 1, tot);
	S2::build(1, 1, tot);
	for (int i = 1; i <= n; i++) {
		for (auto p : vin[i]) {
			B.a[0][0] = p[1], S1::update(1, p[0], B);
			if (p[1] > 0) S2::update(1, 1, p[0], p[1]);
		} 
		for (auto p : vout[i]) {
			S1::update(1, p[0], E);
			if (p[1] < 0) S2::update(1, 1, p[0], p[1]);
		}
		for (int j : vt[i]) {
			Mar w = C * S1::query(1, 1, tim[j]);
			if (w.a[0][0] < e[j].r) ans[j] = 0;
			else {
				int b = w.a[0][0] - e[j].r + 1;
				int t = b + (tim[j] == tot ? 0 : S2::query(1, tim[j] + 1));
				ans[j] = cid[S2::query(1, tim[j], t)];
			}
		}
	}
	for (int i = 1; i <= q; i++)
		if (e[i].o == 3) cout << ans[i] << '\n';
	return 0;
}
posted @ 2026-08-24 21:14  长安19路  阅读(12)  评论(0)    收藏  举报