P4192 旅行规划 题解
\(\text{P4192 旅行规划 题解}\)
还有点意思的题。
题目等价于区间加等差数列,求前缀最大和。这个东西线段树之类的数据结构显然是不好维护的。看到时限 4s,考虑分块,块间的情况是容易处理的,现在考虑如何快速求出块内的最大权值点。
由于是等差数列,那么我们可以轻易知道每个命令块内两个点贡献的差值。对于一个块内两个点 \(j<i\),我们设 \(b_i\) 表示点 \(i\) 原先的贡献,\(\Delta\) 表示在这个块之前加入的总贡献,那么 \(i\) 优于 \(j\) 的条件是:\(b_i+i\times \Delta>b_j+j\times \Delta\),转化一下得到的是:
\[\frac{b_i-b_j}{i-j}>-\Delta
\]
那么块内维护一下凸包就行了。时间复杂度是 \(O(n\sqrt n\log n)\)。
代码写得有些复杂了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5, M = 350, inf = 1e18;
int n, m, T, b[N];
int bel[N];
struct PNT {
int x, y;
bool operator < (const PNT &b) const {
if (x == b.x) return y < b.y;
return x < b.x;
}
PNT operator - (PNT b) {
return {x - b.x, y - b.y};
}
int operator * (PNT b) {
return x * b.y - y * b.x;
}
};
#define pii pair<int, int>
#define mk make_pair
struct Node {
int l, r, dlt, adt;
int b[M];
vector<pii>va;
vector<PNT>v;
} e[M];
PNT stk[N];
int top;
void fuck(vector<PNT>&v) {
top = 0;
sort(v.begin(), v.end());
for (auto i : v) {
while (top > 1 && (i - stk[top]) * (stk[top] - stk[top - 1]) <= 0) --top;
stk[++top] = i;
}
v.clear();
for (int i = 1; i <= top; i++) v.push_back(stk[i]);
}
void update(int x, int y, int k) {
int bl = bel[x], br = bel[y];
for (int i = bl + 1; i < br; i++) {
e[i].va.emplace_back(k, x);
e[i].dlt += k;
e[i].adt += (e[i].l - x) * k;
}
for (int i = e[bl].l; i <= e[bl].r; i++) {
e[bl].b[i - e[bl].l + 1] += e[bl].adt;
for (auto j : e[bl].va)
e[bl].b[i - e[bl].l + 1] += j.first * (i - e[bl].l + 1);
if (x <= i && i <= y) e[bl].b[i - e[bl].l + 1] += k * (i - x + 1);
}
e[bl].dlt = e[bl].adt = 0, e[bl].va.clear(), e[bl].v.clear();
for (int i = e[bl].l; i <= e[bl].r; i++)
e[bl].v.emplace_back((PNT){i, e[bl].b[i - e[bl].l + 1]});
fuck(e[bl].v);
if (bl == br) return;
for (int i = e[br].l; i <= e[br].r; i++) {
e[br].b[i - e[br].l + 1] += e[br].adt;
for (auto j : e[br].va)
e[br].b[i - e[br].l + 1] += j.first * (i - e[br].l + 1);
if (x <= i && i <= y) e[br].b[i - e[br].l + 1] += k * (i - x + 1);
}
e[br].dlt = e[br].adt = 0, e[br].va.clear(), e[br].v.clear();
for (int i = e[br].l; i <= e[br].r; i++)
e[br].v.emplace_back((PNT){i, e[br].b[i - e[br].l + 1]});
fuck(e[br].v);
}
void rebut(int x, int k) {
if (x > n) return;
int bl = bel[x];
for (int i = bl + 1; i <= m; i++) e[i].adt += k;
for (int i = e[bl].l; i <= e[bl].r; i++) {
e[bl].b[i - e[bl].l + 1] += e[bl].adt;
for (auto j : e[bl].va)
e[bl].b[i - e[bl].l + 1] += j.first * (i - e[bl].l + 1);
if (x <= i) e[bl].b[i - e[bl].l + 1] += k;
}
e[bl].dlt = e[bl].adt = 0, e[bl].va.clear(), e[bl].v.clear();
for (int i = e[bl].l; i <= e[bl].r; i++)
e[bl].v.emplace_back((PNT){i, e[bl].b[i - e[bl].l + 1]});
fuck(e[bl].v);
}
int query(int x, int y) {
int res = -inf, bl = bel[x], br = bel[y];
for (int i = bl + 1; i < br; i++) {
int l = 1, r = e[i].v.size() - 1, ans = 0, mid = 0;
while (l <= r) {
mid = (l + r) >> 1;
if (e[i].v[mid].y - e[i].v[mid - 1].y >= -e[i].dlt * (e[i].v[mid].x - e[i].v[mid - 1].x))
ans = mid, l = mid + 1;
else r = mid - 1;
}
ans = e[i].v[ans].x;
res = max(res, e[i].b[ans - e[i].l + 1] + e[i].dlt * (ans - e[i].l + 1) + e[i].adt);
}
for (int i = e[bl].l; i <= e[bl].r; i++)
if (x <= i && i <= y)
res = max(res, e[bl].b[i - e[bl].l + 1] + e[bl].dlt * (i - e[bl].l + 1) + e[bl].adt);
for (int i = e[br].l; i <= e[br].r; i++)
if (x <= i && i <= y)
res = max(res, e[br].b[i - e[br].l + 1] + e[br].dlt * (i - e[br].l + 1) + e[br].adt);
return res;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n;
m = sqrt(n);
for (int i = 1; i <= n; i++) cin >> b[i], b[i] += b[i - 1];
for (int i = 1; i <= m; i++) {
e[i].l = e[i - 1].r + 1;
e[i].r = e[i].l + m - 1;
}
if (e[m].r < n) {
++m;
e[m].l = e[m - 1].r + 1;
e[m].r = n;
}
for (int i = 1; i <= m; i++)
for (int j = e[i].l; j <= e[i].r; j++)
bel[j] = i;
for (int i = 1; i <= m; i++) {
for (int j = e[i].l; j <= e[i].r; j++) {
e[i].b[j - e[i].l + 1] = b[j];
e[i].v.emplace_back((PNT){j, b[j]});
}
fuck(e[i].v);
}
cin >> T;
while (T--) {
int op, x, y;
cin >> op >> x >> y;
if (!op) {
int k;
cin >> k;
update(x, y, k);
rebut(y + 1, (y - x + 1) * k);
}
else cout << query(x, y) << '\n';
}
return 0;
}

浙公网安备 33010602011771号