[洛谷P4291][HAOI2008]排名系统
题目大意:三种操作:
- $+Name\;Socore:$上传最新得分记录,把以前的记录删除。
- $?Name:$ 查询玩家排名。如果两个玩家的得分相同,则先得到该得分的玩家排在前面。
- $?Index:$ 返回自第$Index$名开始的最多$10$名玩家名字。
题解:平衡树,支持删除,插入,查询第$k$名,查询一个玩家的排名。
卡点:新建节点时忘记赋$size$
C++ Code:
#include <cstdio> #include <map> #include <iostream> #define maxn 250010 std::map<std::string, int> name; int n, namenum; struct node { int v, p; inline node(int __v = 0, int __p = 0) {v = __v, p = __p;} inline friend bool operator > (const node &lhs, const node &rhs) { if (lhs.v == rhs.v) return lhs.p < rhs.p; return lhs.v > rhs.v; } inline friend bool operator == (const node &lhs, const node &rhs) {return lhs.v == rhs.v && lhs.p == rhs.p;} inline friend bool operator >= (const node &lhs, const node &rhs) {return lhs > rhs || lhs == rhs;} }; namespace Treap { int lc[maxn], rc[maxn], num[maxn], sz[maxn]; node val[maxn]; int root, idx; int ta, tb, tmp, res; int seed = 20040826; inline int rand() {return seed *= 48271;} inline int update(int rt) { sz[rt] = sz[lc[rt]] + sz[rc[rt]] + 1; return rt; } inline int nw(node x) { val[++idx] = x; num[idx] = rand(); sz[idx] = 1; return idx; } void split(int rt, node k, int &x, int &y) { if (!rt) x = y = 0; else { if (val[rt] >= k) split(rc[rt], k, rc[rt], y), x = update(rt); else split(lc[rt], k, x, lc[rt]), y = update(rt); } } void split(int rt, int k, int &x, int &y) { if (!rt) x = y = 0; else { if (sz[lc[rt]] < k) split(rc[rt], k - sz[lc[rt]] - 1, rc[rt], y), x = update(rt); else split(lc[rt], k, x, lc[rt]), y = update(rt); } } int merge(int x, int y) { if (!x || !y) return x | y; if (num[x] < num[y]) {rc[x] = merge(rc[x], y); return update(x);} else {lc[y] = merge(x, lc[y]); return update(y);} } inline int gtrnk(node x) { split(root, x, ta, tb); res = sz[ta]; root = merge(ta, tb); return res; } inline node gtkth(int k) { tmp = root; while (true) { if (sz[lc[tmp]] >= k) tmp = lc[tmp]; else { if (sz[lc[tmp]] + 1 == k) return val[tmp]; else k -= sz[lc[tmp]] + 1, tmp = rc[tmp]; } } } void insert(node x) { if (!root) root = nw(x); else { split(root, x, ta, tb); root = merge(merge(ta, nw(x)), tb); } } void erase(node x) { split(root, x, ta, tb); split(ta, sz[ta] - 1, ta, tmp); root = merge(ta, tb); } } int val[maxn]; std::string retname[maxn]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { char op; std::string s; std::cin >> op >> s; if (op == '+') { int x; std::cin >> x; if (name.count(s)) { int pos = name[s]; Treap::erase(node(val[pos], pos)); namenum--; } namenum++; name[s] = i; retname[i] = s; val[i] = x; Treap::insert(node(x, i)); } else if (isdigit(s[0])) { int pos = 0, posend; for (std::string::iterator it = s.begin(); it != s.end(); it++) pos = pos * 10 + (*it & 15); posend = std::min(pos + 9, namenum); for (int i = pos; i <= posend; i++) { std::cout << retname[Treap::gtkth(i).p]; putchar(i == posend ? '\n' : ' '); } } else { int pos = name[s]; std::cout << Treap::gtrnk(node(val[pos], pos)) << std::endl; } } return 0; }