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