QOJ6815

原题链接

时间这么长,但是走完一圈之后它的速度就不变了。

那么就直接模拟走第一圈就行,后面就是一个周期性问题了。

考虑走第一圈的情况,起点记作 \(s\),那么到点 \(t\) 的速度的分母就是 \(\max\limits_{i = s} ^ t a_i\),走到点 \(t\) 的总时间就是 \(\sum\limits_{i = s} ^ t a_i \max\limits_{j = s} ^ i a_j\),前缀 \(\max\),可以想到单调栈。

现在就是需要使用一种方式加速模拟,模拟单调栈不难想到楼房重建的经典套路,对前缀进行分治。

现在就考虑查询,就是在楼房重建线段树上查询从 \(s\) 开始走 \(t\) 时间走到的最远的点,不难想到二分,因为 \(s\)\(x\) 的时间是单调递增的,可以二分,朴素的二分搭配线段树查询 \([l, r]\) 的时间,复杂度是 \(\mathcal{O}(n \log ^ 3 n)\) 的。不过线段树这个很好的结构可以直接在它上面二分,复杂度就降到了 \(\mathcal{O}(n \log ^ 2 n)\),可以通过。

下面加上修改,根据查询的方法,可以知道需要的值就是走完 \([l, r]\) 这一段的时间,然后区间加的话总时间就变成了 \(\sum\limits_{i = l} ^ r (a_i + d) \max\limits_{j = l} ^ i (a_j + d)\),就等于 \(\sum\limits_{i = l} ^ r a_i \max\limits_{j = l} ^ i a_j + d \max\limits_{j = l} ^ i a_j + a_i \times d + d ^ 2\),再线段树额外维护区间和与区间速度和即可实现加。区间赋值就比较简单了。注意一下转移顺序就完了。

代码细节比较多

#include <bits/stdc++.h>

using i64 = long long;
using pll = std::pair<long long, long long>;

const int N = 4E5 + 5;
const int inf = 1E9;

int n, q, a[N];
i64 sum[N];

struct Node {
	int id;
	i64 time, v;
	Node(int _id = 0, i64 _time = 0, i64 _v = 0) :
		id(_id), time(_time), v(_v) {}
};

struct SegmentTree {
	i64 sum[N << 2], sumv[N << 2], mx[N << 2], ans[N << 2];
	i64 tag[N << 2], ass[N << 2];

	#define ls(u) u << 1
	#define rs(u) u << 1 | 1

	void PushDown(int u, int l, int r) {
		int mid = l + r >> 1;
		if (ass[u]) {
			sum[ls(u)] = (mid - l + 1) * ass[u], sum[rs(u)] = (r - mid) * ass[u];
			sumv[ls(u)] = (mid - l + 1) * ass[u], sumv[rs(u)] = (r - mid) * ass[u];
			ans[ls(u)] = sum[ls(u)] * ass[u], ans[rs(u)] = sum[rs(u)] * ass[u];
			mx[ls(u)] = mx[rs(u)] = ass[u];
			tag[ls(u)] = tag[rs(u)] = 0;
			ass[ls(u)] = ass[rs(u)] = ass[u];
			ass[u] = 0;
		}

		if (tag[u]) {
			mx[ls(u)] += tag[u], mx[rs(u)] += tag[u];
			ans[ls(u)] += sumv[ls(u)] * tag[u] + sum[ls(u)] * tag[u] + (mid - l + 1) * tag[u] * tag[u];
			ans[rs(u)] += sumv[rs(u)] * tag[u] + sum[rs(u)] * tag[u] + (r - mid) * tag[u] * tag[u];
			sum[ls(u)] += tag[u] * (mid - l + 1), sum[rs(u)] += (r - mid) * tag[u];
			sumv[ls(u)] += tag[u] * (mid - l + 1), sumv[rs(u)] += tag[u] * (r - mid);
			tag[ls(u)] += tag[u], tag[rs(u)] += tag[u];
			tag[u] = 0;
		}
	}

	pll Get(int u, int l, int r, i64 v) {
		if (l == r) return std::make_pair(std::max(v, mx[u]) * sum[u], std::max(v, mx[u]));
		PushDown(u, l, r);
		if (mx[u] <= v) return std::make_pair(v * sum[u], v * (r - l + 1));
		int mid = l + r >> 1;
		if (mx[ls(u)] < v) {
			pll res = Get(rs(u), mid + 1, r, v);
			return std::make_pair(sum[ls(u)] * v + res.first, v * (mid - l + 1) + res.second);
		} else {
			pll res = Get(ls(u), l, mid, v);
			return std::make_pair(res.first + ans[u] - ans[ls(u)], res.second + sumv[u] - sumv[ls(u)]);
		}
	}

	void PushUp(int u, int l, int r) {
		int mid = l + r >> 1;
		sum[u] = sum[ls(u)] + sum[rs(u)];
		mx[u] = std::max(mx[ls(u)], mx[rs(u)]);
		assert(mx[ls(u)] >= 0);
		pll res = Get(rs(u), mid + 1, r, mx[ls(u)]);
		ans[u] = ans[ls(u)] + res.first;
		sumv[u] = sumv[ls(u)] + res.second;
	}

	void build(int u, int l, int r) {
		if (l == r) {
			sum[u] = mx[u] = sumv[u] = a[l];
			ans[u] = 1ll * a[l] * a[l];
			return;
		}

		int mid = l + r >> 1;

		build(ls(u), l, mid), build(rs(u), mid + 1, r);

		PushUp(u, l, r);
	}

	void modify1(int u, int l, int r, int ql, int qr, i64 val) {
		if (ql <= l && r <= qr) {
			ans[u] += sum[u] * val + sumv[u] * val + (r - l + 1) * val * val;
			sum[u] += (r - l + 1) * val, sumv[u] += val * (r - l + 1);
			mx[u] += val, tag[u] += val;
			return;
		}

		PushDown(u, l, r);

		int mid = l + r >> 1;
		
		if (ql <= mid) modify1(ls(u), l, mid, ql, qr, val);
		if (qr > mid) modify1(rs(u), mid + 1, r, ql, qr, val);

		PushUp(u, l, r);
	}

	void modify2(int u, int l, int r, int ql, int qr, i64 val) {
		if (ql <= l && r <= qr) {
			sum[u] = (r - l + 1) * val, sumv[u] = (r - l + 1) * val;
			mx[u] = val, ans[u] = sum[u] * val;
			tag[u] = 0, ass[u] = val;
			return;
		}

		PushDown(u, l, r);

		int mid = l + r >> 1;

		if (ql <= mid) modify2(ls(u), l, mid, ql, qr, val);
		if (qr > mid) modify2(rs(u), mid + 1, r, ql, qr, val);

		PushUp(u, l, r);
	}

	Node query(int u, int l, int r, int s, i64 t, i64 v) {
		if (l == r) return Node(l, std::max(v, mx[u]) * sum[u], std::max(v, mx[u]));

		PushDown(u, l, r);

		int mid = l + r >> 1;

		if (s <= l) {
			pll res = Get(ls(u), l, mid, v);
			if (res.first <= t) {
				Node x = query(rs(u), mid + 1, r, mid + 1, t - res.first, std::max(v, mx[ls(u)]));
				x.time += res.first;
				return x;
			} else {
				return query(ls(u), l, mid, l, t, v);
			}
		}
		
		if (s <= mid) {
			Node res = query(ls(u), l, mid, s, t, v);
			if (res.id == mid && res.time <= t) {
				Node x = query(rs(u), mid + 1, r, mid + 1, t - res.time, res.v);
				x.time += res.time;
				return x;
			} else {
				return res;
			}
		} else {
			return query(rs(u), mid + 1, r, s, t, v);
		}
	}

	#undef ls
	#undef rs
}t;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	std::cin >> n >> q;
	int m = n << 1;

	for (int i = 1; i <= n; i++) {
		std::cin >> a[i];
		a[i + n] = a[i];
	}

	t.build(1, 1, m);

	for (int i = 1; i <= q; i++) {
		char op;
		std::cin >> op;
		if (op == 'Q') {
			int s; i64 time;
			std::cin >> s >> time;
			++s;
			Node res = t.query(1, 1, m, s, time, 0);
			time -= res.time;
			if (res.id == m && time >= 0) {
				i64 p = t.mx[1] * t.sum[1];
				time %= p;
				res = t.query(1, 1, m, 1, time, t.mx[1]);
			}
			if (res.id > n) res.id -= n;
			std::cout << res.id - 1 << "\n";
		} else if (op == 'P') {
			int l, r, d;
			std::cin >> l >> r >> d;
			l++, r++;
			if (l > r) {
				t.modify1(1, 1, m, l, r + n, d);
				t.modify1(1, 1, m, 1, r, d);
				t.modify1(1, 1, m, l + n, m, d);
			} else {
				t.modify1(1, 1, m, l, r, d);
				t.modify1(1, 1, m, l + n, r + n, d);
			}
		} else {
			int l, r, d;
			std::cin >> l >> r >> d;
			l++, r++;
			if (l > r) {
				t.modify2(1, 1, m, l, r + n, d);
				t.modify2(1, 1, m, 1, r, d);
				t.modify2(1, 1, m, l + n, m, d);
			} else {
				t.modify2(1, 1, m, l, r, d);
				t.modify2(1, 1, m, l + n, r + n, d);
			}
		}
	}

	std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "\n";
	return 0;
}

posted @ 2025-04-11 14:54  Z_drj  阅读(30)  评论(0)    收藏  举报