P4291 [HAOI2008]排名系统
自定义结构体维护平衡树即可,并不需要哈希。
我们对于每个结构体维护名字、分数和插入时的编号。先按分数,后按插入编号重载运算符即可。
根据题意,我们要支持插入,求排名,按照排名求值以及删除操作。因为如果一个人的分数被更新,我们要在平衡树中修改它,即先删除后插入。
由于需要删除操作,所以需要写前驱操作,不过也是平衡树基础操作。
删除操作具体是,把要删除的点转到根,如果这个点的
写的 Splay,常数非常大,不开 O2 会超时
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现