[BZOJ1056][BZOJ1862][HAOI2008][Zjoi2006]排名系统
试题描述
排名系统通常要应付三种请求:上传一条新的得分记录、查询某个玩家的当前排名以及返回某个区段内的排名记录。当某个玩家上传自己最新的得分记录时,他原有的得分记录会被删除。为了减轻服务器负担,在返回某个区段内的排名记录时,最多返回10条记录。
输入
第一行是一个整数n(n>=10)表示请求总数目。接下来n行,每行包含了一个请求。请求的具体格式如下: +Name Score 上传最新得分记录。Name表示玩家名字,由大写英文字母组成,不超过10个字符。Score为最多8位的正整数。 ?Name 查询玩家排名。该玩家的得分记录必定已经在前面上传。 ?Index 返回自第Index名开始的最多10名玩家名字。Index必定合法,即不小于1,也不大于当前有记录的玩家总数。
输出
对于?Name格式的请求,应输出一个整数表示该玩家当前的排名。对于?Index格式的请求,应在一行中依次输出从第Index名开始的最多10名玩家姓名,用一个空格分隔。
输入示例
20 +ADAM 1000000 +BOB 1000000 +TOM 2000000 +CATHY 10000000 ?TOM ?1 +DAM 100000 +BOB 1200000 +ADAM 900000 +FRANK 12340000 +LEO 9000000 +KAINE 9000000 +GRACE 8000000 +WALT 9000000 +SANDY 8000000 +MICK 9000000 +JACK 7320000 ?2 ?5 ?KAINE
输出示例
2 CATHY TOM ADAM BOB CATHY LEO WALT MICK KAINE GRACE SANDY JACK TOM BOB MICK KAINE GRACE SANDY JACK TOM BOB ADAM DAM 6
数据规模及约定
N<=250000
题解
用颗 trie 维护一下每个串对应的信息,用 treap 维护排名等等乱七八糟的东西。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
#define maxn 250010
#define maxa 26
int son[maxa][maxn], id[maxn], sc[maxn], qaq;
void insert(int j, char* s) {
int u = 0, l = strlen(s);
for(int i = 0; i < l; i++) {
if(!son[s[i]-'A'][u]) son[s[i]-'A'][u] = ++qaq;
u = son[s[i]-'A'][u];
}
id[u] = j;
return ;
}
int getid(char* s) {
int u = 0, l = strlen(s);
for(int i = 0; i < l; i++) {
if(!son[s[i]-'A'][u]) return 0;
u = son[s[i]-'A'][u];
}
return id[u];
}
struct Node {
char name[15];
int v, r, siz;
Node() {}
Node(int _1, int _2, char* _3): v(_1), r(_2) {
memcpy(name, _3, sizeof(name));
}
bool operator < (Node t) {
return v != t.v ? v > t.v : getid(name) < getid(t.name);
}
bool operator == (Node t) const {
return v == t.v && !strcmp(name, t.name);
}
} ns[maxn];
int ToT, rt, fa[maxn], ch[2][maxn];
void maintain(int o) {
ns[o].siz = 1;
for(int i = 0; i < 2; i++) if(ch[i][o])
ns[o].siz += ns[ch[i][o]].siz;
return ;
}
void rotate(int u) {
int y = fa[u], z = fa[y], l = 0, r = 1;
if(z) ch[ch[1][z]==y][z] = u;
if(ch[1][y] == u) swap(l, r);
fa[u] = z; fa[y] = u; fa[ch[r][u]] = y;
ch[l][y] = ch[r][u]; ch[r][u] = y;
maintain(y); maintain(u);
return ;
}
void insert(int& o, int v, char* s) {
if(!o) {
ns[o = ++ToT] = Node(v, rand(), s);
return maintain(o);
}
bool d = ns[o] < Node(v, -1, s);
insert(ch[d][o], v, s); fa[ch[d][o]] = o;
if(ns[ch[d][o]].r > ns[o].r) {
int t = ch[d][o];
rotate(t); o = t;
}
return maintain(o);
}
void del(int& o, int v, char* s) {
if(ns[o] == Node(v, -1, s)) {
if(!ch[0][o] && !ch[1][o]) o = 0;
else if(!ch[0][o]) {
int t = ch[1][o]; fa[t] = fa[o]; o = t;
}
else if(!ch[1][o]) {
int t = ch[0][o]; fa[t] = fa[o]; o = t;
}
else {
bool d = ns[ch[1][o]].r > ns[ch[0][o]].r;
int t = ch[d][o]; rotate(t); o = t;
del(ch[d^1][o], v, s);
}
}
else {
bool d = ns[o] < Node(v, -1, s);
del(ch[d][o], v, s);
}
return maintain(o);
}
Node qkth(int o, int k) {
if(!o) return Node(-1, -1, "233");
int ls = ch[0][o] ? ns[ch[0][o]].siz : 0;
if(k == ls + 1) return ns[o];
if(k > ls + 1) return qkth(ch[1][o], k - ls - 1);
return qkth(ch[0][o], k);
}
int Find(int o, int v, char* s, int k) {
if(!o) return -1;
int ls = (ch[0][o] ? ns[ch[0][o]].siz : 0);
if(ns[o] == Node(v, -1, s)) return k + ls + 1;
bool d = ns[o] < Node(v, -1, s);
return Find(ch[d][o], v, s, k + (ls + 1) * d);
}
int main() {
int q = read(), cnts = 0;
while(q--) {
char s[15]; scanf("%s", s);
if(s[0] == '+') {
int tmp = getid(s + 1);
if(tmp) del(rt, sc[tmp], s + 1);
insert(++cnts, s + 1), tmp = cnts;
sc[tmp] = read();
insert(rt, sc[tmp], s + 1);
}
if(s[0] == '?') {
if(isalpha(s[1])) printf("%d\n", Find(rt, sc[getid(s+1)], s + 1, 0));
else {
int l = strlen(s + 1), x = 0;
for(int i = 1; i <= l; i++) x = x * 10 + s[i] - '0';
int mxi = min(x + 9, ns[rt].siz);
for(int i = x; i <= mxi; i++) {
Node t = qkth(rt, i);
printf("%s%c", t.name, i < mxi ? ' ' : '\n');
}
}
}
}
return 0;
}