P4291 [HAOI2008]排名系统

自定义结构体维护平衡树即可,并不需要哈希。

我们对于每个结构体维护名字、分数和插入时的编号。先按分数,后按插入编号重载运算符即可。

根据题意,我们要支持插入,求排名,按照排名求值以及删除操作。因为如果一个人的分数被更新,我们要在平衡树中修改它,即先删除后插入。

由于需要删除操作,所以需要写前驱操作,不过也是平衡树基础操作。

删除操作具体是,把要删除的点转到根,如果这个点的 cnt>1cnt > 1,那么就 cntcnt1cnt \leftarrow cnt - 1,否则合并两个子树。合并时把左子树的最大值转到根,然后将右子树接上根的右儿子即可。

写的 Splay,常数非常大,不开 O2 会超时 22 个点。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <climits>
#include <map>
using namespace std;

const int N = 3e5 + 5;

int n;

struct User
{
	string name;
	long long score;
	int id;
	User(){}
	User(string _n, long long _s, int _i): name(_n), score(_s), id(_i){}
	bool operator==(const User& g) const
	{
		return name == g.name && score == g.score && id == g.id;
	}
	bool operator<(const User& g) const
	{
		if (score ^ g.score) return score > g.score;
		return id < g.id;
	}
	bool operator>(const User& g) const
	{
		if (score ^ g.score) return score < g.score;
		return id > g.id;
	}
};

class Splay
{
public:
	int idx, rt;
	struct Node
	{
		int fa, son[2], sz, cnt;
		User val;
	}tr[N];
	int get(int x)
	{
		return x == tr[tr[x].fa].son[1];
	}
	void pushup(int u)
	{
		tr[u].sz = tr[tr[u].son[0]].sz + tr[tr[u].son[1]].sz + tr[u].cnt;
	}
	void rotate(int x)
	{
		int y = tr[x].fa, z = tr[y].fa;
		int chkx = get(x), chky = get(y);
		tr[y].son[chkx] = tr[x].son[chkx ^ 1];
		if (tr[x].son[chkx ^ 1]) tr[tr[x].son[chkx ^ 1]].fa = y;
		tr[x].son[chkx ^ 1] = y;
		tr[y].fa = x;
		tr[x].fa = z;
		if (z) tr[z].son[chky] = x;
		pushup(y);
		pushup(x);
	}
	void splay(int u)
	{
		for (int f = tr[u].fa; f = tr[u].fa, f; rotate(u))
		{
			if (tr[f].fa) rotate(get(f) == get(u) ? f : u);
		}
		rt = u;
	}
	void ins(User g)
	{
		if (!rt)
		{
			rt = ++idx;
			tr[rt].val = g;
			tr[rt].cnt = 1;
			pushup(rt);
			return;
		}
		int u = rt, f, last;
		while (true)
		{
			if (tr[u].val == g)
			{
				tr[u].cnt++;
				pushup(u);
				pushup(f);
				splay(u);
				return;
			}
			if (!u)
			{
				u = ++idx;
				tr[u].cnt = 1;
				tr[u].val = g;
				tr[u].fa = f;
				tr[f].son[last] = u;
				pushup(u);
				pushup(f);
				splay(u);
				return;
			}
			f = u;
			last = g > tr[u].val;
			u = tr[u].son[last];
		}
	}
	int rank(User x)
	{
		int res = 0, u = rt;
		while (true)
		{
			if (tr[u].val == x)
			{
				res += tr[tr[u].son[0]].sz;
				splay(u);
				return res + 1;
			}
			if (tr[u].val > x)
			{
				u = tr[u].son[0];
			}
			else
			{
				res += tr[tr[u].son[0]].sz + tr[u].cnt;
				u = tr[u].son[1];
			}
		}
	}
	User kth(int k)
	{
		int u = rt;
		while (true)
		{
			if (tr[tr[u].son[0]].sz >= k)
			{
				u = tr[u].son[0];
			}
			else if (tr[tr[u].son[0]].sz + 1 == k)
			{
				splay(u);
				return tr[u].val;
			}
			else
			{
				k -= tr[tr[u].son[0]].sz + tr[u].cnt;
				u = tr[u].son[1];
			}
		}
	}
	void CLEAR(int u)
	{
		tr[u].cnt = tr[u].fa = tr[u].son[0] = tr[u].son[1] = tr[u].sz = 0;
		tr[u].val.id = tr[u].val.score = 0;
		tr[u].val.name = "";
	}
	User pre()
	{
		int u = tr[rt].son[0];
		if (!u) return User("", 0LL, 0);
		while (tr[u].son[1]) u = tr[u].son[1];
		splay(u);
		return tr[u].val;
	}
	void del(User p)
	{
		rank(p);
		int u = rt;
		if (tr[u].cnt > 1)
		{
			tr[u].cnt--;
			pushup(u);
			return;
		}
		if (!tr[u].son[0])
		{
			rt = tr[u].son[1];
			tr[rt].fa = 0;
			CLEAR(u);
			return;
		}
		if (!tr[u].son[1])
		{
			rt = tr[u].son[0];
			tr[rt].fa = 0;
			CLEAR(u);
			return;
		}
		pre();
		tr[rt].son[1] = tr[u].son[1];
		tr[tr[u].son[1]].fa = rt;
		pushup(rt);
		CLEAR(u);
	}
}tr;

map<string, User> st;

int main()
{
	cin >> n;
	tr.ins(User("PPPPP", INT_MIN, INT_MIN));
	tr.ins(User("PPPPP", INT_MAX, INT_MAX));
	for (int i = 1; i <= n; i++)
	{
		char c;
		cin >> c;
		if (c == '+')
		{
			string name;
			long long score;
			cin >> name >> score;
			if (st.count(name))
			{
				tr.del(st[name]);
			}
			st[name] = User(name, score, i);
			tr.ins(st[name]);
		}
		else if (c == '?')
		{
			string s;
			cin >> s;
			bool flag = 1;
			for (auto i : s)
			{
				if (!(i >= '0' && i <= '9'))
				{
					flag = 0;
					break;
				}
			}
			if (flag)
			{
				int x = stoi(s);
				for (int i = 1; i <= 10; i++)
				{
					User g = tr.kth(x + i);
					if (g.name == "PPPPP")
					{
						break;
					}
					cout << g.name << " ";
				}
				cout << "\n";
			}
			else
			{
				cout << tr.rank(st[s]) - 1 << "\n";
			}
		}
	}
	return 0;
}
posted @   HappyBobb  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示