双map实现的加强版对顶堆
新功能
维护一个动态数组,支持插入、删除、和查询中位数
传统大小堆的对顶堆维护不了删除
双map对顶堆代码
拜读了@StarSilk的代码,感觉非常牛,于是在博客记录下来
#include <bits/stdc++.h>
#define debug(x) cerr<<#x<<':'<<x<<'\n';
#define ll long long
using namespace std;
//加强版的对顶堆
/*
维护中位数
对顶堆
1. 插入
2. 查询中位数
双map
1. 插入
2. 删除
3. 查询中位数
*/
const ll inf = 1e18;
int n, q, cl, cr;
ll a[200005];
map<ll, int> mpl, mpr;
void solve();
void ins(ll x);
int chkans();
ll lmax();
ll rmin();
void rmv(ll x);
void rmv(ll x) {
if (x <= lmax()) {
mpl[x]--;
cl--;
} else {
mpr[x]--;
cr--;
}
while (cl > cr + 1) {
ll y = lmax();
mpr[y]++;
mpl[y]--;
cr++;
cl--;
}
while (cl < cr) {
ll y = rmin();
mpr[y]--;
mpl[y]++;
cr--;
cl++;
}
}
int chkans() {
ll x = rmin();
return cl - mpl[x];
}
ll lmax() { //查询左map最大值
map<ll, int>::iterator it;
while (1) {
if (mpl.empty())
return -inf;
it = mpl.end();
--it;
if ((*it).second == 0) {
mpl.erase(it);
continue;
}
return (*it).first;
}
return -inf;
}
ll rmin() { //查询右map最小值
map<ll, int>::iterator it;
while (1) {
if (mpr.empty())
return inf;
it = mpr.begin();
if ((*it).second == 0) {
mpr.erase(it);
continue;
}
return (*it).first;
}
return inf;
}
void ins(ll x) {
if (x < lmax()) { //比左map最大值小
cl++;
mpl[x]++;
} else { //否则加入右map
cr++;
mpr[x]++;
}
//维护cl<=cr+1,cl==cr二选一
while (cl > cr + 1) {
ll y = lmax();
mpl[y]--;
mpr[y]++;
cl--;
cr++;
}
while (cl < cr) {
ll y = rmin();
mpr[y]--;
mpl[y]++;
cl++;
cr--;
}
}
void solve() {
cin >> n >> q;
for (int i = 1; i <= n; i++) {
cin >> a[i];
ins(a[i]);
}
for (int i = 1, u; i <= q; i++) {
ll d;
cin >> u >> d;
rmv(a[u]);
a[u] += d;
ins(a[u]);
cout << chkans() << '\n';
}
mpl.clear(), mpr.clear();
cl = cr = 0;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}

浙公网安备 33010602011771号