# Description
Luogu 传送门
# Solution
挺板子的平衡树。
题目要求我们支持三个操作:
- 插入 / 更新 一个点的值。
- 查询一个点的排名。
- 查询从第 名开始后面最多 10 名玩家的名字。
这些操作看着就很板子。。
唯一比较恶心的是要 一下,所以开个 存一下编号。
小技巧,存每个人的得分时存负数,这样 时的边界要稍微好调一点。
传参数一定要写对啊,千万不要像我一样打错了调半天 QwQ
#include <bits/stdc++.h> | |
#define pb push_back | |
#define ll long long | |
using namespace std; | |
namespace IO{ | |
inline int read(){ | |
int x = 0; | |
char ch = getchar(); | |
while(!isdigit(ch)) ch = getchar(); | |
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); | |
return x; | |
} | |
template <typename T> inline void write(T x){ | |
if(x < 0) putchar('-'), x = -x; | |
if(x > 9) write(x / 10); | |
putchar(x % 10 + '0'); | |
} | |
} | |
using namespace IO; | |
const int N = 1e6 + 10; | |
int n, root, tot; | |
int siz[N], val[N], ch[N][2], fa[N], wei[N]; | |
#define ls(x) ch[x][0] | |
#define rs(x) ch[x][1] | |
inline void pushup(int x){ | |
if(ls(x)) fa[ls(x)] = x; | |
if(rs(x)) fa[rs(x)] = x; | |
siz[x] = siz[ls(x)] + siz[rs(x)] + 1; | |
} | |
inline void split_val(int x, int k, int &a, int &b){ | |
if(!x) return a = b = 0, void(); | |
if(val[x] <= k) a = x, split_val(rs(x), k, rs(x), b); | |
else b = x, split_val(ls(x), k, a, ls(x)); | |
pushup(x); | |
} | |
inline void split_siz(int x, int k, int &a, int &b){ | |
if(!x) return a = b = 0, void(); | |
fa[x] = 0; | |
if(siz[ls(x)] + 1 <= k) a = x, split_siz(rs(x), k - siz[ls(x)] - 1, rs(x), b); | |
else b = x, split_siz(ls(x), k, a, ls(x)); | |
pushup(x); | |
} | |
inline int merge(int x, int y){ | |
if(!x || !y) return x | y; | |
if(wei[x] < wei[y]){ | |
rs(x) = merge(rs(x), y); | |
return pushup(x), x; | |
}else{ | |
ls(y) = merge(x, ls(y)); | |
return pushup(y), y; | |
} | |
} | |
inline int get_rk(int x){ | |
int res = siz[ls(x)] + 1; | |
while(fa[x]){ | |
if(rs(fa[x]) == x) res += siz[ls(fa[x])] + 1; | |
x = fa[x]; | |
} | |
return res; | |
} | |
map <string, int> mp; | |
string s, name[N]; | |
inline int newnode(int k){ | |
mp[s] = ++tot, siz[tot] = 1, wei[tot] = rand(), name[tot] = s, val[tot] = -k; | |
return tot; | |
} | |
inline void update(int k){ | |
int a = 0, b = 0, c = 0; | |
if(mp[s]){ | |
int rk = get_rk(mp[s]); | |
split_siz(root, rk, a, b); | |
split_siz(a, rk - 1, a, c); | |
val[c] = -k; | |
root = merge(a, b); | |
split_val(root, -k, a, b); | |
root = merge(merge(a, c), b); | |
}else{ | |
split_val(root, -k, a, b); | |
root = merge(merge(a, newnode(k)), b); | |
} | |
} | |
inline int calc(string s){ | |
int res = 0, len = s.length(); | |
for(int i = 0; i < len; ++i) res = res * 10 + s[i] - '0'; | |
return res; | |
} | |
inline void print(int x){ | |
if(ls(x)) print(ls(x)); | |
cout << name[x] << " "; | |
if(rs(x)) print(rs(x)); | |
} | |
inline void query(){ | |
int a, b, c; | |
if(isdigit(s[0])){ | |
int k = calc(s); | |
split_siz(root, k + 9, a, b); | |
split_siz(a, k - 1, a, c); | |
print(c); | |
root = merge(merge(a, c), b); | |
}else write(get_rk(mp[s])); | |
} | |
signed main(){ | |
n = read(); | |
for(int i = 1; i <= n; ++i){ | |
char ch = getchar(); | |
while(ch != '+' && ch != '?') ch = getchar(); | |
cin >> s; | |
if(ch == '+') update(read()); | |
else query(), puts(""); | |
} | |
return 0; | |
} | |
// X.K. |