atcoder abc G - Merchant Takahashi
线段树维护 dp
分析
- 就, d p i dp_i dpi 可以由 d p [ 1 , i − 1 ] dp_{[1, i - 1]} dp[1,i−1] 转移过来,那线段树维护 [ 1 , i − 1 ] [1, i - 1] [1,i−1] 的最大值即可(这里的 i i i 于城镇编号无关,仅阐述基础 d p dp dp)。
- 难点在于 C × ∣ i − j ∣ C \times |i-j| C×∣i−j∣ ,对于当前城镇 T T T
-
- 1.有城镇 M ≥ T M \ge T M≥T ,那么 d p T = d p M + C × ( M − T ) dp_T=dp_M + C \times (M - T) dpT=dpM+C×(M−T)
-
- 2.有城镇 M < T M < T M<T ,那么 d p T = d p M + C × ( T − M ) dp_T=dp_M + C \times (T - M) dpT=dpM+C×(T−M)
思路
- 考虑建立两个线段树
-
- s e g 1 seg_1 seg1 维护 d p i − C × i dp_i - C \times i dpi−C×i
-
- s e g 2 seg_2 seg2 维护 d p i + C × i dp_i + C \times i dpi+C×i
- d p dp dp 转移时,对于当前城镇 T T T
-
- 1.有城镇 M ≥ T M \ge T M≥T ,那么就在 s e g 2 seg_2 seg2 里去查询,那么 r e s = s e g 2 . m a x − C × T res = seg_2.max - C \times T res=seg2.max−C×T
-
- 2.有城镇 M < T M < T M<T ,那么就在 s e g 1 seg_1 seg1 里去查询,那么 r e s = s e g 1 . m a x + C × T res = seg_1.max + C \times T res=seg1.max+C×T
//道可道非常道,名可名非常名
#include <bits/stdc++.h>
using ll = long long;
template<class Info>
struct SegmentTree {
#define ls i << 1
#define rs i << 1 | 1
const int N;
std::vector<Info> seg;
SegmentTree(int _) : N(_), seg(_ << 4) {}
SegmentTree(std::vector<int> a) : SegmentTree(int(a.size())) {
std::function<void(int, int, int)> build = [&](int i, int l, int r) {
seg[i] = {l, r, ll(-1e18), ll(-1e18)};
if (l == r) {
return ;
}
int mid = (l + r) / 2;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(i);
};
build(1, 1, N);
}
void pushup(int i) {
seg[i] = seg[ls] + seg[rs];
}
void modify(int i, int ind, ll v) {
if (seg[i].l == seg[i].r) {
seg[i].max = std::max(seg[i].max, v);
return ;
}
if (ind <= seg[ls].r) {
modify(ls, ind, v);
} else {
modify(rs, ind, v);
}
pushup(i);
}
ll query(int i, int l, int r) {
if (l > r) {
return 0;
}
if (l <= seg[i].l and seg[i].r <= r) {
return seg[i].max;
}
ll res = -1e18;
if (l <= seg[ls].r) {
res = std::max(res, query(ls, l, r));
}
if (r >= seg[rs].l) {
res = std::max(res, query(rs, l, r));
}
return res;
}
};
struct Info {
int l, r;
ll sum, max;
};
Info operator + (const Info &u, const Info &v) {
Info res = {};
res.l = u.l;
res.r = v.r;
res.sum = u.sum + v.sum;
res.max = std::max(u.max, v.max);
return res;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, c, m;
std::cin >> n >> c >> m;
std::vector<std::pair<int, ll>> a(m);
for (auto &[u, v] : a) {
std::cin >> u >> v;
}
std::vector<int> A(n + 1);
SegmentTree<Info> segup(A);
SegmentTree<Info> segdown(A);
segdown.modify(1, 1, 1ll * c);
segup.modify(1, 1, -1ll * c);
ll ans = 0;
for (auto [t, p] : a) {
ll res_down = segdown.query(1, 1, t), res_up = segup.query(1, t, n);
res_down = res_down - 1ll * c * t + p;
res_up = res_up + 1ll * c * t + p;
res_up = std::max(res_down, res_up);
segup.modify(1, t, res_up - 1ll * c * t);
segdown.modify(1, t, res_up + 1ll * c * t);
ans = std::max(ans, res_up);
}
std::cout << ans;
return 0;
}
//