[BZOJ1056][BZOJ1862][HAOI2008][Zjoi2006]排名系统
[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; }