SP15376 RMID - Running Median

题意

动态维护一个序列,支持插入删除和查询中位数,多测。

解法

可以对顶堆,也可以平衡树。提供平衡树做法。

显然用平衡树的话这题非常容易,只需要插入删除和按排名查找值,比模板还容易。

特别注意的是,需要注意中位数的排名是什么。

我通常会在平衡树建立时插入极大值和极小值,所以排名有些改变。

设目前有 cc 个数在平衡树里(不算初始的最大值和最小值),那么询问的时候:

  • c1(mod2)c \equiv 1 \pmod2,则询问的排名为 c2+2\lfloor \frac{c}{2} \rfloor + 2

  • c0(mod2)c \equiv 0 \pmod2,则询问的排名为 c2+1\lfloor \frac{c}{2} \rfloor + 1

此题一定要用 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;
}
posted @   HappyBobb  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示