P7219 [JOISC2020] 星座 3 題解

Creeper_l發表於2024-06-08

會發現題目的座標其實是平面直角座標系。

我們按 \(y\) 座標從小到大考慮所有的星星,假設當前考慮到了星星 \(i\)。我們先計算出之前所有能夠影響到 \(i\) 的星星的代價和為 \(cost\)(可以用樹狀陣列維護)。然後分類討論。

\(c_i \le cost\),那麼肯定直接將 \(i\) 直接塗黑,因為它更容易影響到後面的星星,並且刪除它的代價更小。

\(cost < c_i\),我們可以用一種類似於反悔貪心的思路。先假設把 \(cost\) 刪除,然後在樹狀陣列中的 \([l,r]\) 區間加上 \(c_i-cost\)\([l,r]\) 表示 \(i\) 能影響到的區間),這樣之後考慮星星 \(j\) 的時候,如果需要刪除星星 \(i\),那麼 \(cost\) 中的一部分的代價也會加回去(但是不一定全部都加回去,因為 \(cost\) 中的一些星星也會影響 \(j\))。

然後就做完了,維護每顆星星的 \([l,r]\) 可以用並查集做。時間複雜度 \(O(n \log n)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair <int,int> pii;
const int MAXN = 2e5 + 10;
int n,a[MAXN],m,x[MAXN],y[MAXN],c[MAXN];
vector <pii> v[MAXN];
vector <int> f[MAXN];  
int tree[MAXN],ans = 0,fal[MAXN],far[MAXN];
inline int Lowbit(int x) {return x & -x;}
inline void Add(int x,int c) {for(;x <= n;x += Lowbit(x)) tree[x] += c;}
inline int Query(int x) {int r = 0;for(;x;x -= Lowbit(x)) r += tree[x];return r;}
inline int Findl(int x) {if(fal[x] == x) return x;return fal[x] = Findl(fal[x]);}
inline int Findr(int x) {if(far[x] == x) return x;return far[x] = Findr(far[x]);}
signed main() {
	cin >> n;
	for(int i = 1;i <= n;i++) cin >> a[i];
	for(int i = 0;i <= n + 1;i++) fal[i] = far[i] = i;
	for(int i = 1;i <= n;i++) f[a[i]].emplace_back(i); 
	cin >> m;
	for(int i = 1;i <= m;i++) 
		cin >> x[i] >> y[i] >> c[i],
		v[y[i]].emplace_back(make_pair(x[i],c[i]));
	for(int i = 1;i <= n;i++) {
		for(pii j : v[i]) {
			int cost = Query(j.first);
			if(j.second <= cost) ans += j.second;
			else ans += cost,
				Add(Findl(j.first) + 1,j.second - cost),
				Add(Findr(j.first),cost - j.second);
		}
		for(int j : f[i]) 
			fal[Findl(j)] = Findl(j - 1),
			far[Findr(j)] = Findr(j + 1);
	} cout << ans; return 0;
}

相關文章