P16858 [GKS 2021 #F] Festival 题解
Solution
思路
我们可以使用扫描线的思想来解决。存储在第 \(i\) 天开始的活动和结束的活动。
我们注意到 \(D \le 3 \times 10^5\) 所以不用离散化。可以扫描每一天的开始的活动和结束的活动,并维护前 \(K\) 大的快乐值之和。考虑使用对顶堆:通过一个大根堆 \(q_1\) 和小根堆 \(q_2\) 可以维护前 \(K\) 大和剩余的部分,稍加改装,维护一个 \(size\) 和 \(sum\),在加入时顺便更新,就可以维护总和。
可是堆的任意删除是 \(O(n)\) 复杂度的,所以我们可以引入懒标记。注意到 \(h_i\) 可以重复,所以 \(lsy_{h_i}\) 标记的应该是 \(h_i\) 要删除的个数。
我们注意到删除时需要优先删除下面那个堆,所以要分类讨论。
if(h >= q2.top()) {
if(q2.top() == h && (q1.empty() ? 1 : q1.top() < h)) q2sz--, q2cnt -= h, lsy2[h]++;
else if(q2.top() == h && q1.top() == h) q1sz--, q1cnt -= h, lsy1[h]++;
else if(q2.top() < h) q2sz--, q2cnt -= h, lsy2[h]++;
}
else q1sz--, q1cnt -= h, lsy1[h]++;
为了不删错堆,可以分成两个懒标记数组,分别存上面的堆和下面的堆。然后就可以统计了。
注意:记得开long long。
我也不知道我怎么过去的,有更好的写法在评论区指正。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 3e5 + 5;
ll lsy1[N], lsy2[N];
priority_queue<ll> q1;
priority_queue<ll, vector<ll>, greater<ll>> q2;
ll q1sz, q2sz, q1cnt, q2cnt;
ll d, n, k;
void ph() {
while(q2sz != k) {
if(q2sz < k) {
while(!q1.empty() && lsy1[q1.top()]) lsy1[q1.top()]--, q1.pop();
if(!q1.empty()) {
q2.push(q1.top());
q2cnt += q1.top(), q1cnt -= q1.top();
q1.pop();
q2sz++, q1sz--;
}
}
if(q2sz > k) {
while(!q2.empty() && lsy2[q2.top()]) lsy2[q2.top()]--, q2.pop();
if(!q2.empty()) {
q1.push(q2.top());
q2cnt -= q2.top(), q1cnt += q2.top();
q2.pop();
q1sz++, q2sz--;
}
}
if(q1sz == 0 && q2sz <= k) break;
}
}
void add(ll h) {
q2.push(h), q2sz++, q2cnt += h;
ph();
}
void del(ll h) {
while(!q1.empty() && lsy1[q1.top()]) lsy1[q1.top()]--, q1.pop();
while(!q2.empty() && lsy2[q2.top()]) lsy2[q2.top()]--, q2.pop();
if(h >= q2.top()) {
if(q2.top() == h && (q1.empty() ? 1 : q1.top() < h)) q2sz--, q2cnt -= h, lsy2[h]++;
else if(q2.top() == h && q1.top() == h) q1sz--, q1cnt -= h, lsy1[h]++;
else if(q2.top() < h) q2sz--, q2cnt -= h, lsy2[h]++;
}
else q1sz--, q1cnt -= h, lsy1[h]++;
ph();
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
ll T; cin >> T;
for(ll t = 1; t <= T; t++) {
memset(lsy1, 0, sizeof(lsy1));
memset(lsy2, 0, sizeof(lsy2));
q1 = priority_queue<ll>();
q2 = priority_queue<ll, vector<ll>, greater<ll>>();
q1sz = q2sz = q1cnt = q2cnt = 0;
cin >> d >> n >> k;
vector<vector<ll>> p(d + 2), q(d + 2);
ll ans = 0;
for(ll i = 1, s, e, h; i <= n && cin >> h >> s >> e; i++) {
p[s].push_back(h), q[e + 1].push_back(h);
}
for(ll i = 1; i <= d; i++) {
for(auto h : p[i]) add(h);
for(auto h : q[i]) del(h);
ans = max(ans, q2cnt);
}
cout << "Case #" << t << ": " << ans << "\n";
}
return 0;
}

浙公网安备 33010602011771号