G - Merchant Takahashi

atcoder abc G - Merchant Takahashi

线段树维护 dp

分析

  • 就, d p i dp_i dpi 可以由 d p [ 1 , i − 1 ] dp_{[1, i - 1]} dp[1,i1] 转移过来,那线段树维护 [ 1 , i − 1 ] [1, i - 1] [1,i1] 的最大值即可(这里的 i i i 于城镇编号无关,仅阐述基础 d p dp dp)。
  • 难点在于 C × ∣ i − j ∣ C \times |i-j| C×ij ,对于当前城镇 T T T
    • 1.有城镇 M ≥ T M \ge T MT ,那么 d p T = d p M + C × ( M − T ) dp_T=dp_M + C \times (M - T) dpT=dpM+C×(MT)
    • 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×(TM)

思路

  • 考虑建立两个线段树
    • s e g 1 seg_1 seg1 维护 d p i − C × i dp_i - C \times i dpiC×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 MT ,那么就在 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.maxC×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;
}

//
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Heredy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值