题目链接
题目解法
将问题转化为保留权值和尽可能大的星。
对于一个区域,考虑其中最高的楼房
,显然,我们至多可以保留一颗高于
的星。
若我们没有保留任意一颗高于
的星,则区域会被楼房
分为独立的两块;
否则,令所保留的星的横坐标为
,则区域会被分成
左侧的若干块和右侧的若干块。
这两种情况中,所新产生的区域都能够由 “楼房 到其左 / 右侧第一幢更高的楼房之间的区域” 来表示,因此,我们只需要在这样 个区域上进行动态规划。
显然有 转移,并且,通过单调栈建出 “左 / 右侧第一幢更高的楼房” 形成的树形关系,可以简单地利用 DFS 序 树状数组对动态规划进行部分和优化。
时间复杂度 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
struct BinaryIndexTree {
int n; ll a[MAXN];
void init(int x) {
n = x;
memset(a, 0, sizeof(a));
}
void modify(int x, ll d) {
for (int i = x; i <= n; i += i & -i)
a[i] += d;
}
void modify(int l, int r, ll d) {
modify(l, d);
modify(r + 1, -d);
}
ll query(int x) {
ll ans = 0;
for (int i = x; i >= 1; i -= i & -i)
ans += a[i];
return ans;
}
} BIT[2];
namespace rmq {
const int MAXN = 2e5 + 5;
const int MAXLOG = 19;
pair <int, int> Max[MAXN][MAXLOG]; int Log[MAXN];
pair <int, int> query(int l, int r) {
int len = r - l + 1, tmp = Log[len];
return max(Max[l][tmp], Max[r - (1 << tmp) + 1][tmp]);
}
void init(int *a, int n) {
for (int i = 1; i <= n; i++) {
Max[i][0] = make_pair(a[i], i);
Log[i] = Log[i - 1];
if ((1 << (Log[i] + 1)) <= i) Log[i]++;
}
for (int t = 1; t < MAXLOG; t++)
for (int i = 1, j = (1 << (t - 1)) + 1; j <= n; i++, j++)
Max[i][t] = max(Max[i][t - 1], Max[j][t - 1]);
}
}
ll dp[MAXN][2];
vector <int> trans[MAXN][2], qry[MAXN];
int m, x[MAXN], y[MAXN], c[MAXN];
int n, h[MAXN], l[MAXN], r[MAXN];
vector <int> al[MAXN], ar[MAXN];
int timerl, dfnl[MAXN], ritl[MAXN];
int timerr, dfnr[MAXN], ritr[MAXN];
void dfsl(int pos) {
dfnl[pos] = ++timerl;
for (auto x : al[pos]) dfsl(x);
ritl[pos] = timerl;
}
void dfsr(int pos) {
dfnr[pos] = ++timerr;
for (auto x : ar[pos]) dfsr(x);
ritr[pos] = timerr;
}
void init() {
static int q[MAXN];
int top = 1; q[top] = 0;
for (int i = 1; i <= n + 1; i++) {
while (h[q[top]] < h[i]) top--;
for (auto x : qry[i]) {
int ql = 1, qr = top;
while (ql < qr) {
int mid = (ql + qr + 1) / 2;
if (h[q[mid]] >= y[x]) ql = mid;
else qr = mid - 1;
}
trans[q[ql]][0].push_back(x);
}
l[i] = q[top], q[++top] = i;
}
q[top = 1] = n + 1;
for (int i = n; i >= 0; i--) {
while (h[q[top]] < h[i]) top--;
for (auto x : qry[i]) {
int ql = 1, qr = top;
while (ql < qr) {
int mid = (ql + qr + 1) / 2;
if (h[q[mid]] >= y[x]) ql = mid;
else qr = mid - 1;
}
trans[q[ql]][1].push_back(x);
}
r[i] = q[top], q[++top] = i;
}
BIT[0].init(n + 2);
BIT[1].init(n + 2);
for (int i = 1; i <= n + 1; i++)
al[l[i]].push_back(i);
for (int i = 0; i <= n; i++)
ar[r[i]].push_back(i);
dfsl(0), dfsr(n + 1);
}
void updatel(int ql) {
ll &ans = dp[ql][0]; ans = 0;
int qr = r[ql]; ql++, qr--;
if (ql > qr) return;
int Max = rmq :: query(ql, qr).first;
int pos = rmq :: query(ql, qr).second;
ans += dp[pos][1] + dp[pos][0];
while (pos > ql && rmq :: query(ql, pos - 1).first == Max) {
pos = rmq :: query(ql, pos - 1).second;
ans += dp[pos][1];
}
for (auto p : trans[ql - 1][0]) {
if (y[p] > Max) {
ll cur = c[p];
cur += BIT[1].query(dfnl[x[p]]) - BIT[1].query(dfnl[ql - 1]);
cur += BIT[0].query(dfnr[x[p]]) - BIT[0].query(dfnr[qr + 1]);
chkmax(ans, cur);
}
}
BIT[0].modify(dfnr[ql - 1], ritr[ql - 1], ans);
}
void updater(int qr) {
ll &ans = dp[qr][1]; ans = 0;
int ql = l[qr]; ql++, qr--;
if (ql > qr) return;
int Max = rmq :: query(ql, qr).first;
int pos = rmq :: query(ql, qr).second;
ans += dp[pos][1] + dp[pos][0];
while (pos > ql && rmq :: query(ql, pos - 1).first == Max) {
pos = rmq :: query(ql, pos - 1).second;
ans += dp[pos][1];
}
for (auto p : trans[qr + 1][1]) {
if (y[p] > Max) {
ll cur = c[p];
cur += BIT[1].query(dfnl[x[p]]) - BIT[1].query(dfnl[ql - 1]);
cur += BIT[0].query(dfnr[x[p]]) - BIT[0].query(dfnr[qr + 1]);
chkmax(ans, cur);
}
}
BIT[1].modify(dfnl[qr + 1], ritl[qr + 1], ans);
}
int main() {
read(n), h[0] = h[n + 1] = n;
for (int i = 1; i <= n; i++)
read(h[i]);
rmq :: init(h, n);
read(m);
for (int i = 1; i <= m; i++) {
read(x[i]), read(y[i]), read(c[i]);
qry[x[i]].push_back(i);
}
init();
static int p[MAXN];
for (int i = 0; i <= n + 1; i++)
p[i] = i;
sort(p, p + n + 2, [&] (int x, int y) {return h[x] < h[y]; });
for (int i = 0; i <= n + 1; i++) {
int pos = p[i];
if (pos != n + 1) updatel(pos);
if (pos != 0) updater(pos);
}
ll ans = 0;
for (int i = 1; i <= m; i++)
ans += c[i];
for (int i = 0; i != n + 1; i = r[i])
ans -= dp[i][0];
cout << ans << endl;
return 0;
}