Loading

LOJ#4148. 「JOISC 2024 Day1」鱼 3

称投喂饲料 A 的逆操作,即「选定一条鱼,使其智力值减少 \(D\)」为操作 \(A_R\)

注意到仅通过投喂饲料 B 得到的序列一定是不降的,问题转化为求通过多少次操作 \(A_R\) 能使得序列不降。

若存在 \(C_{i+1} - C_i < D\),则若 \(C_{i + 1}\) 减小,\(C_i\) 也一定随之减小,可以把它们俩看成一块,称为一个 连续段

离线询问,扫描右端点,线段树维护 \(-D\) 的系数,并查集维护连续段左右端点并支持合并。

每修改 \(k\) 个连续段,就会有 \(k - 1\) 个连续段合并成一个,势能分析法,时间复杂度 \(\mathcal O(n \log n)\),常数大。

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

constexpr int N = 3e5 + 10;

int n, q;
ll D, c[N], ans[N];

vector<pii> qry[N];

namespace DSU {
	int fa[N], l[N], r[N];
	inline void init(int n) {iota(fa + 1, fa + n + 1, 1), iota(l + 1, l + n + 1, 1), iota(r + 1, r + n + 1, 1);}
	inline int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
	inline int getl(int x) {return l[find(x)];}
	inline void merge(int x, int y) {
		x = find(x), y = find(y);
		if (x != y) fa[y] = x, l[x] = min(l[x], l[y]), r[x] = max(r[x], r[y]);
	}
}

namespace SGT {
	#define lson pos << 1
	#define rson pos << 1 | 1

	ll w[N << 2], lazy[N << 2];

	inline void fix(int pos, int l, int r, ll c) {w[pos] += (r - l + 1) * c, lazy[pos] += c;}

	inline void pu(int pos) {w[pos] = w[lson] + w[rson];}

	inline void pd(int pos, int l, int r) {
		if (!lazy[pos]) return;
		int mid = (l + r) >> 1;
		fix(lson, l, mid, lazy[pos]), fix(rson, mid + 1, r, lazy[pos]);
		lazy[pos] = 0;
	}

	void upd(int pos, int l, int r, int x, int y, ll c) {
		if (x <= l && r <= y) return fix(pos, l, r, c);
		pd(pos, l, r); int mid = (l + r) >> 1;
		if (x <= mid) upd(lson, l, mid, x, y, c);
		if (y > mid) upd(rson, mid + 1, r, x, y, c);
		pu(pos);
	}

	ll qry(int pos, int l, int r, int x, int y) {
		if (x <= l && r <= y) return w[pos];
		pd(pos, l, r); int mid = (l + r) >> 1;
		if (y <= mid) return qry(lson, l, mid, x, y);
		if (x > mid) return qry(rson, mid + 1, r, x, y);
		return qry(lson, l, mid, x, y) + qry(rson, mid + 1, r, x, y);
	}
}

inline ll getc(int i) {return c[i] - D * SGT::qry(1, 1, n, i, i);}

int main() {
	ios_base::sync_with_stdio(0); cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> D;
	for (int i = 1; i <= n; i++) cin >> c[i];
	cin >> q;
	for (int i = 1, l, r; i <= q; i++) cin >> l >> r, qry[r].emplace_back(l, i);
	DSU::init(n);
	for (int i = 2; i <= n; i++) {
		if (c[i - 1] > c[i]) {
			for (int r = i - 1, l; r; r = l - 1) {
				l = DSU::getl(r);
				ll cl = getc(r), cr = getc(r + 1);
				if (cl <= cr) break;
				SGT::upd(1, 1, n, l, r, (cl - cr + D - 1) / D);
				DSU::merge(r, r + 1);
			}
		}
		for (auto qi : qry[i]) {
			if (getc(qi.first) < 0) ans[qi.second] = -1;
			else ans[qi.second] = SGT::qry(1, 1, n, qi.first, i);
		}
	}
	for (int i = 1; i <= q; i++) cout << ans[i] << '\n';
	return 0;
}
posted @ 2024-05-24 15:40  Chy12321  阅读(20)  评论(0编辑  收藏  举报