BZOJ 1056: [HAOI2008]排名系统 && 1862: [Zjoi2006]GameZ游戏排名系统 Splay
1056: [HAOI2008]排名系统
Description
排名系统通常要应付三种请求:上传一条新的得分记录、查询某个玩家的当前排名以及返回某个区段内的排名
记录。当某个玩家上传自己最新的得分记录时,他原有的得分记录会被删除。为了减轻服务器负担,在返回某个区
段内的排名记录时,最多返回10条记录。
Input
第一行是一个整数n(n>=10)表示请求总数目。接下来n行,每行包含了一个请求。请求的具体格式如下: +Na
me Score 上传最新得分记录。Name表示玩家名字,由大写英文字母组成,不超过10个字符。Score为最多8位的正
整数。 ?Name 查询玩家排名。该玩家的得分记录必定已经在前面上传。 ?Index 返回自第Index名开始的最多10名
玩家名字。Index必定合法,即不小于1,也不大于当前有记录的玩家总数。
Output
对于?Name格式的请求,应输出一个整数表示该玩家当前的排名。对于?Index格式的请求,应在一行中依次输
出从第Index名开始的最多10名玩家姓名,用一个空格分隔。
Sample Input
20
+ADAM 1000000 加入ADAM的得分记录
+BOB 1000000 加入BOB的得分记录
+TOM 2000000 加入TOM的得分记录
+CATHY 10000000 加入CATHY的得分记录
?TOM 输出TOM目前排名
?1 目前有记录的玩家总数为4,因此应输出第1名到第4名。
+DAM 100000 加入DAM的得分记录
+BOB 1200000 更新BOB的得分记录
+ADAM 900000 更新ADAM的得分记录(即使比原来的差)
+FRANK 12340000 加入FRANK的得分记录
+LEO 9000000 加入LEO的得分记录
+KAINE 9000000 加入KAINE的得分记录
+GRACE 8000000 加入GRACE的得分记录
+WALT 9000000 加入WALT的得分记录
+SANDY 8000000 加入SANDY的得分记录
+MICK 9000000 加入MICK的得分记录
+JACK 7320000 加入JACK的得分记录
?2 目前有记录的玩家总数为12,因此应输出第2名到第11名。
?5 输出第5名到第13名。
?KAINE 输出KAINE的排名
+ADAM 1000000 加入ADAM的得分记录
+BOB 1000000 加入BOB的得分记录
+TOM 2000000 加入TOM的得分记录
+CATHY 10000000 加入CATHY的得分记录
?TOM 输出TOM目前排名
?1 目前有记录的玩家总数为4,因此应输出第1名到第4名。
+DAM 100000 加入DAM的得分记录
+BOB 1200000 更新BOB的得分记录
+ADAM 900000 更新ADAM的得分记录(即使比原来的差)
+FRANK 12340000 加入FRANK的得分记录
+LEO 9000000 加入LEO的得分记录
+KAINE 9000000 加入KAINE的得分记录
+GRACE 8000000 加入GRACE的得分记录
+WALT 9000000 加入WALT的得分记录
+SANDY 8000000 加入SANDY的得分记录
+MICK 9000000 加入MICK的得分记录
+JACK 7320000 加入JACK的得分记录
?2 目前有记录的玩家总数为12,因此应输出第2名到第11名。
?5 输出第5名到第13名。
?KAINE 输出KAINE的排名
Sample Output
2
CATHY TOM ADAM BOB
CATHY LEO KAINE WALT MICK GRACE SANDY JACK TOM BOB
WALT MICK GRACE SANDY JACK TOM BOB ADAM DAM
4
思路:
splay板子题,不好调, 但是没什么思维难度 :名字用两个map互相对应就好了, 另外数据不符合题面, 最大的数可以达到$10^{10}$
#include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <string> using namespace std; #define int long long map<string, int>id; map<int, string>nam; #define ls ch[p][0] #define rs ch[p][1] const int N = 251000; const int inf = 100000000000000; int ch[N][2], siz[N], f[N], root, cnt; long long val[N]; #define get(x) (ch[f[x]][1]==x) inline void up(int p) { if(p) siz[p] = siz[ls]+siz[rs]+1; } void rotate(int x) { int y=f[x], z=f[y], k=get(x); ch[y][k] = ch[x][k^1]; f[ch[y][k]] = y; ch[x][k^1] = y; f[y]=x, f[x] = z; if(z) ch[z][ch[z][1]==y]=x; up(y), up(x); if(y==root) root=x; } void splay(int x, int y) { for(int fa;(fa=f[x])!=y;rotate(x)) { if(f[fa]!=y) rotate(get(x)==get(fa)?fa:x); } } void insert(int x, long long c) { int p = root; int l, r; while(p) { if(val[p]>=c) r=p, p=ls; else l=p, p=rs; } splay(l, 0);splay(r, root); ch[r][0] = x, f[x] = r;val[x] = c, siz[x] = 1;up(r), up(l); } void del(int x) { splay(x, 0); int l = ch[x][0], r=ch[x][1]; while(ch[l][1]) l =ch[l][1];while(ch[r][0])r=ch[r][0]; splay(l, 0); splay(r, root); ch[r][0]=0; f[x] = 0, siz[x] = 1; up(r), up(l); } void print(int p) { if(rs) print(rs); printf("%s ", nam[p].c_str()); if(ls) print(ls); } int find(int x) { int p =root; while(1) { if(x<=siz[ls])p=ls; else { x-=siz[ls]+1; if(!x) return p; p=rs; } } } void qrk(int l, int r) { l=cnt-l-1, r=cnt-r-1; swap(l, r); l=find(l), r=find(r+2); splay(l, 0); splay(r, root); print(ch[r][0]); puts(""); } #undef int int main() { #define int long long int n; val[1] = -inf, val[2] = inf; ch[1][1] = 2;f[2] =1;root=1;siz[1]=2, siz[2] = 1;cnt=2; scanf("%lld", &n); while(n--) { char c = getchar(); while(c!='+'&&c!='?') c=getchar(); char name[20];long long num; scanf("%s", name); if(c=='+') { scanf("%lld", &num); if(id.count(name)) { int x = id[name]; del(x); insert(x, num); } else { cnt++; insert(cnt, num); id[name] = cnt; nam[cnt] = name; } } else { if(isdigit(name[0])) { int rk; sscanf(name, "%lld", &rk); qrk(rk, min(rk+9, cnt-2)); } else { int x = id[name]; splay(x, 0); printf("%lld\n", cnt-siz[ch[x][0]]-1); } } } }