題目鏈接
題目解法
將問題轉化爲保留權值和儘可能大的星。
對於一個區域,考慮其中最高的樓房 ,顯然,我們至多可以保留一顆高於 的星。
若我們沒有保留任意一顆高於 的星,則區域會被樓房 分爲獨立的兩塊;
否則,令所保留的星的橫座標爲 ,則區域會被分成 左側的若干塊和右側的若干塊。
這兩種情況中,所新產生的區域都能夠由 “樓房 到其左 / 右側第一幢更高的樓房之間的區域” 來表示,因此,我們只需要在這樣 個區域上進行動態規劃。
顯然有 轉移,並且,通過單調棧建出 “左 / 右側第一幢更高的樓房” 形成的樹形關係,可以簡單地利用 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;
}