LOJ#4148. 「JOISC 2024 Day1」魚 3

Chy12321發表於2024-05-24

稱投餵飼料 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;
}