SP15376 RMID - Running Median
题意
动态维护一个序列,支持插入删除和查询中位数,多测。
解法
可以对顶堆,也可以平衡树。提供平衡树做法。
显然用平衡树的话这题非常容易,只需要插入删除和按排名查找值,比模板还容易。
特别注意的是,需要注意中位数的排名是什么。
我通常会在平衡树建立时插入极大值和极小值,所以排名有些改变。
设目前有
-
若
,则询问的排名为 。 -
若
,则询问的排名为 。
此题一定要用 C++98 提交:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5, INF = 2147483647;
int t;
class Treap
{
public:
int idx, root;
struct Node
{
int l, r, key, val;
int sz, cnt;
}tr[N];
void pushup(int u)
{
tr[u].sz = tr[tr[u].l].sz + tr[tr[u].r].sz + tr[u].cnt;
}
void clear()
{
for (int i = 0; i <= idx; i++)
{
tr[i].l = tr[i].r = tr[i].key = tr[i].val = tr[i].sz = tr[i].cnt = 0;
}
idx = 0;
root = 0;
}
int get_node(int x)
{
tr[++idx].key = x;
tr[idx].val = rand();
tr[idx].sz = tr[idx].cnt = 1;
return idx;
}
void zig(int& x)
{
int q = tr[x].l;
tr[x].l = tr[q].r, tr[q].r = x, x = q;
pushup(tr[x].r), pushup(x);
}
void zag(int& x)
{
int q = tr[x].r;
tr[x].r = tr[q].l, tr[q].l = x, x = q;
pushup(tr[x].l), pushup(x);
}
void build()
{
get_node(-INF), get_node(INF);
root = 1, tr[1].r = 2;
if (tr[1].val < tr[2].val) zag(root);
}
void insert(int& x, int key)
{
if (!x) x = get_node(key);
else if (tr[x].key == key) tr[x].cnt++;
else if (tr[x].key > key)
{
insert(tr[x].l, key);
if (tr[tr[x].l].val > tr[x].val) zig(x);
}
else
{
insert(tr[x].r, key);
if (tr[tr[x].r].val > tr[x].val) zag(x);
}
pushup(x);
}
void del(int& x, int key)
{
if (!x) return;
if (tr[x].key == key)
{
if (tr[x].cnt > 1) tr[x].cnt--;
else if (tr[x].l || tr[x].r)
{
if (!tr[x].r || tr[tr[x].l].val > tr[tr[x].r].val)
{
zig(x), del(tr[x].r, key);
}
else
{
zag(x), del(tr[x].l, key);
}
}
else
{
tr[x].cnt--, tr[x].sz--, x = 0;
}
}
else if (tr[x].key > key)
{
del(tr[x].l, key);
}
else del(tr[x].r, key);
pushup(x);
}
int get_key(int x, int rank)
{
if (!x) return INF;
if (tr[tr[x].l].sz >= rank) return get_key(tr[x].l, rank);
else if (tr[tr[x].l].sz + tr[x].cnt >= rank) return tr[x].key;
return get_key(tr[x].r, rank - tr[tr[x].l].sz - tr[x].cnt);
}
};
Treap tp;
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
tp.clear();
tp.build();
int n, cnt = 0;
while (cin >> n)
{
if (n == 0)
{
tp.clear();
tp.build();
cout << "\n";
cnt = 0;
}
else if (n == -1)
{
int g;
if (cnt % 2 == 0)
{
g = tp.get_key(tp.root, (cnt >> 1) + 1);
}
else g = tp.get_key(tp.root, (cnt >> 1) + 2);
cout << g << "\n";
tp.del(tp.root, g);
cnt--;
}
else
{
tp.insert(tp.root, n);
cnt++;
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现