【LOJ3277】「JOISC 2020 Day3」星座 3

題目鏈接

點擊打開鏈接

題目解法

將問題轉化爲保留權值和儘可能大的星。

對於一個區域,考慮其中最高的樓房 ii ,顯然,我們至多可以保留一顆高於 hih_i 的星。
若我們沒有保留任意一顆高於 hih_i 的星,則區域會被樓房 ii 分爲獨立的兩塊;
否則,令所保留的星的橫座標爲 xx ,則區域會被分成 xx 左側的若干塊和右側的若干塊。

這兩種情況中,所新產生的區域都能夠由 “樓房 ii 到其左 / 右側第一幢更高的樓房之間的區域” 來表示,因此,我們只需要在這樣 O(N)O(N) 個區域上進行動態規劃。

顯然有 O(N)O(N) 轉移,並且,通過單調棧建出 “左 / 右側第一幢更高的樓房” 形成的樹形關係,可以簡單地利用 DFS 序 ++ 樹狀數組對動態規劃進行部分和優化。

時間複雜度 O((N+M)LogN)O((N+M)LogN)

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章