[CF1483C] Skyline Photo - dp,线段树,单调栈

Description

\(n\) 栋楼房,每栋楼有一个高度 \(a_i\) 和美丽值 \(b_i\)
现在,你需要把这 \(n\) 栋楼房划分成若干个连续段,每一个连续段的美丽值为该段中最矮的楼房的美丽值。总的划分美丽值为每个连续段的美丽值之和。

你需要求出最大可能的总划分美丽值。

Solution

分段问题,设 \(f[i]\) 表示处理了前 \(i\) 个位置的最大答案,则 \(f[i]=\max_{j<i} (f[j]+g(j+1,i))\)

整个东西可以用以 j 为下标的线段树维护,更新 f 的时候单点修改,更新 g 的时候是区间修改,需要用一个单调栈辅助

#include <bits/stdc++.h>
using namespace std;

#define int long long

int val[1220005], tag[1220005];

struct SegmentTree
{
    int n;
    SegmentTree(int n) : n(n)
    {
    }
    void pushup(int p)
    {
        val[p] = max(val[p * 2], val[p * 2 + 1]);
    }
    void put(int p, int v)
    {
        val[p] += v;
        tag[p] += v;
    }
    void pushdown(int p, int l, int r)
    {
        if (tag[p])
        {
            put(p * 2, tag[p]);
            put(p * 2 + 1, tag[p]);
            tag[p] = 0;
        }
    }
    void modify(int p, int l, int r, int ql, int qr, int v)
    {
        if (l > qr || r < ql)
            return;
        if (l >= ql && r <= qr)
        {
            put(p, v);
            return;
        }
        pushdown(p, l, r);
        modify(p * 2, l, (l + r) / 2, ql, qr, v);
        modify(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr, v);
        pushup(p);
    }
    void Modify(int ql, int qr, int v)
    {
        modify(1, 1, n, ql + 1, qr + 1, v);
    }
    int query(int p, int l, int r, int ql, int qr)
    {
        if (l > qr || r < ql)
            return -1e18;
        if (l >= ql && r <= qr)
            return val[p];
        pushdown(p, l, r);
        return max(query(p * 2, l, (l + r) / 2, ql, qr), query(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr));
    }
    int Query(int ql, int qr)
    {
        return query(1, 1, n, ql + 1, qr + 1);
    }
};

signed main()
{
    int n;
    cin >> n;
    SegmentTree seg(n + 2);
    vector<int> h(n + 2), b(n + 2);
    for (int i = 1; i <= n; i++)
        cin >> h[i];
    for (int i = 1; i <= n; i++)
        cin >> b[i];
    stack<int> sta;
    sta.push(0);
    seg.Modify(0, 0, -1e18);
    for (int i = 1; i <= n; i++)
    {
        while (h[sta.top()] > h[i])
        {
            int statop = sta.top();
            sta.pop();
            int subtop = sta.top();
            seg.Modify(subtop + 1, statop, -b[statop]);
        }
        int subtop = sta.top();
        sta.push(i);
        int statop = sta.top();
        seg.Modify(subtop + 1, statop, b[statop]);
        int f = seg.Query(0, i);
        if (i == n)
            cout << f << endl;
        seg.Modify(i + 1, i + 1, f);
    }
}

相关文章: