[ Z j o i 2006 ] G a m e Z 游 戏 排 名 系 统 [Zjoi2006]GameZ游戏排名系统 [Zjoi2006]GameZ游戏排名系统
Description:
- GameZ为他们最新推出的游戏开通了一个网站。世界各地的玩家都可以将自己的游戏得分上传到网站上。这样就可以看到自己在世界上的排名。得分越高,排名就越靠前。当两个玩家的名次相同时,先上传记录者优先。由于新游戏的火爆,网站服务器已经难堪重负。为此GameZ雇用了你来帮他们重新开发一套新的核心。排名系统通常要应付三种请求:上传一条新的得分记录、查询某个玩家的当前排名以及返回某个区段内的排名记录。当某个玩家上传自己最新的得分记录时,他原有的得分记录会被删除。为了减轻服务器负担,在返回某个区段内的排名记录时,最多返回10条记录。
Input Format:
- 第一行是一个整数n(n>=10)表示请求总数目。接下来n行每行包含了一个请求。请求的具体格式如下: +Name Score 上传最新得分记录。Name表示玩家名字,由大写英文字母组成,不超过10个字符。Score为最多8位的正整数。 ?Name 查询玩家排名。该玩家的得分记录必定已经在前面上传。 ?Index 返回自第Index名开始的最多10名玩家名字。Index必定合法,即不小于1,也不大于当前有记录的玩家总数。输入文件总大小不超过2M。 NOTE:用C++的fstream读大规模数据的效率较低
Output Format:
- 对于每条查询请求,输出相应结果。对于?Name格式的请求,应输出一个整数表示该玩家当前的排名。对于?Index格式的请求,应在一行中依次输出从第Index名开始的最多10名玩家姓名,用一个空格分隔。
Sample Input:
- 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
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
TJ:
首先显然能看出来是个平衡树的题目,那就用Splay搞他。
如何判断一个人的分数是否已经登记过了,那就用一个哈希表来存(这里使用了map来存),键为人名,值由分数和登记时间组成。
Splay中的各个值大小就根据每个人的得分和登记时间来比较。
1.当更新一个人的分数时,如果这个人已经更新过分数,那就在哈希表中更新这个人的分数,并且在平衡树中删去他之前的分数,然后再加入他更新之后的分数。如果没有更新过分数,那就直接在哈希表和平衡树中加入就行了。
2.查询一个人的排名,就在平衡树中查找人名对应的分数和登记时间的排名就行了。
3.查询排名为k及之后最多十个的人,先找出排名为k的人,把这个点旋转到根,然后它的右子节点以下的都是排名在它之后的,进行一次中序遍历找出9个(根节点已经是一个了)最小的就好了。
T a l k i s c h e a p , s h o w y o u t h e c o d e ! Talk\ is\ cheap,show\ you\ the\ code! Talk is cheap,show you the code!
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5+7;
struct pii{
int x,y;
bool operator>(const pii &o)const{
return x==o.x?y>o.y:x<o.x;
}
bool operator==(const pii &o)const{
return x==o.x&&y==o.y;
}
bool operator<(const pii &o)const{
return x==o.x?y<o.y:x>o.x;
}
};
int n;
unordered_map<string,pii> mp;
struct Splay{
#define root ch[0][1]
int ch[MAXN][2],fa[MAXN],sz[MAXN],tot;
pii val[MAXN];
string name[MAXN];
int chk(int rt){ return rt==ch[fa[rt]][1]; }
void push_up(int rt){ sz[rt] = sz[ch[rt][0]]+sz[ch[rt][1]]+1; }
void rorate(int rt){
int f=fa[rt],gf=fa[f],d=chk(rt);
ch[gf][chk(f)]=rt; fa[rt]=gf;
ch[f][d]=ch[rt][d^1];fa[ch[rt][d^1]]=f;
ch[rt][d^1]=f;fa[f]=rt;
push_up(f); push_up(rt);
}
void splay(int rt,int to){
to = fa[to];
while(fa[rt]!=to){
int f=fa[rt],gf=fa[f];
if(gf==to){
rorate(rt);
return;
}
if(chk(rt)==chk(f)) rorate(f);
else rorate(rt);
rorate(rt);
}
}
int CreateNode(pii v,int f,string& Name){
tot++;
val[tot] = v;
fa[tot] = f;
name[tot] = Name;
sz[tot] = 1;
return tot;
}
int find(pii x){
int rt = root;
while(rt){
if(val[rt]==x) return rt;
else if(val[rt]<x) rt = ch[rt][1];
else rt = ch[rt][0];
}
return 0;
}
int rank(pii x){
splay(find(x),root);
return sz[ch[root][0]]+1;
}
void Insert(pii x,string &Name){
if(!root){
root = CreateNode(x,0,Name);
return;
}
int rt = root;
while(true){
sz[rt]++;
if(val[rt]>x){
if(!ch[rt][0]){
ch[rt][0] = CreateNode(x,rt,Name);
splay(ch[rt][0],root);
return;
}
rt = ch[rt][0];
}
else {
if(!ch[rt][1]){
ch[rt][1] = CreateNode(x,rt,Name);
splay(ch[rt][1],root);
return;
}
rt = ch[rt][1];
}
}
}
void Delete(pii x){
splay(find(x),root);
if(!ch[root][0]){
root = ch[root][1];
fa[root] = 0;
return;
}
if(!ch[root][1]){
root = ch[root][0];
fa[root] = 0;
return;
}
int rt = ch[root][0];
while(ch[rt][1]) rt = ch[rt][1];
splay(rt,ch[root][0]);
ch[rt][1]=ch[root][1]; fa[ch[root][1]]=rt;
root=ch[root][0]; fa[root]=0;
push_up(root);
}
int At(int rk){
int rt = root;
while(rt){
if(rk==sz[ch[rt][0]]+1) return rt;
else if(rk<=sz[ch[rt][0]]) rt = ch[rt][0];
else{
rk-=sz[ch[rt][0]]+1;
rt = ch[rt][1];
}
}
return 0;
}
void show(int rk){
splay(At(rk),root);
cout<<name[root]<<' ';
int cnt = 1;
sw(cnt,ch[root][1]);
cout<<endl;
}
void sw(int &cnt,int rt){
if(!rt) return;
sw(cnt,ch[rt][0]);
if(cnt>=10) return;
cnt++;
cout<<name[rt]<<' ';
sw(cnt,ch[rt][1]);
}
#undef root
}SPT;
int main(){
//#define ONLINE_JUDGE
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
ios_base::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin>>n;
string q;
for(int i=1;i<=n;i++){
cin>>q;
if(q[0]=='+'){
string name = q.substr(1,q.size()-1);
int score;
cin>>score;
if(!mp.count(name)){
mp.insert(pair<string,pii>(name,(pii){score,i}));
SPT.Insert((pii){score,i},name);
}
else{
SPT.Delete(mp[name]);
SPT.Insert((pii){score,i},name);
mp[name] = (pii){score,i};
}
}
else if(q[0]=='?'){
if(isdigit(q[1])){
int rk = 0;
for(int j=1;j<(int)q.length();j++) rk = rk*10+q[j]-'0';
SPT.show(rk);
}
else{
string name = q.substr(1,q.size()-1);
cout<<SPT.rank(mp[name])<<endl;
}
}
}
return 0;
}