[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);
}
}