【洛谷P2584】【ZJOI2006】GameZ游戏排名系统题解

题目链接

题意:

GameZ为他们最新推出的游戏开通了一个网站。世界各地的玩家都可以将自己的游戏得分上传到网站上。这样就可以看到自己在世界上的排名。得分越高,排名就越靠前。当两个玩家的名次相同时,先上传记录者优先。由于新游戏的火爆,网站服务器已经难堪重负。为此GameZ雇用了你来帮他们重新开发一套新的核心。

排名系统通常要应付三种请求:上传一条新的得分记录、查询某个玩家的当前排名以及返回某个区段内的排名记录。当某个玩家上传自己最新的得分记录时,他原有的得分记录会被删除。为了减轻服务器负担,在返回某个区段内的排名记录时,最多返回10条记录。

输入格式:

第一行是一个整数n(n>=10)表示请求总数目。

接下来n行每行包含了一个请求。请求的具体格式如下:

+Name Score 上传最新得分记录。Name表示玩家名字,由大写英文字母组成,不超过10个字符。Score为最多10位的正整数。

?Name 查询玩家排名。该玩家的得分记录必定已经在前面上传。

?Index 返回自第Index名开始的最多10名玩家名字。Index必定合法,即不小于1,也不大于当前有记录的玩家总数。输入文件总大小不超过2M。

NOTE:用C++的fstream读大规模数据的效率较低

输出格式:

对于每条查询请求,输出相应结果。

对于?Name格式的请求,应输出一个整数表示该玩家当前的排名。

对于?Index格式的请求,应在一行中依次输出从第Index名开始的最多10名玩家姓名,用一个空格分隔。

样例输入:

+ADAM
+BOB
+TOM
+CATHY
?TOM
?
+DAM
+BOB
+ADAM
+FRANK
+LEO
+KAINE
+GRACE
+WALT
+SANDY
+MICK
+JACK
?
?
?KAINE

样例输出:

CATHY TOM ADAM BOB
CATHY LEO KAINE WALT MICK GRACE SANDY JACK TOM BOB
WALT MICK GRACE SANDY JACK TOM BOB ADAM DAM

时空限制:

每个测试点1s,128MB

数据范围:

n≥10

输入文本大小≤2MB

得分Score是最多十位的正整数

名字字符串最多十位

题解:

明显是一道Splay的题,不过还是需要一些技巧。

2MB文本太大怎么读入?题目已经提示用fstream很慢,所以我们在读入整数时用快读,读入字符串时一个一个getchar而不是用C++的string。

怎么知道字符串对应的节点?用map!

怎么知道节点对应的字符串?我们可以把字符串的Hash值存入节点中,注意这里Hash不用取模,因为字符串最多10位,而且取模后从Hash值还原成字符串是一件十分困难的事。

Splay一定要用双旋!一定要用双旋!一定要用双旋!不然会被极端数据(能够把Splay退化成链的)卡掉。

除此之外,还需要一些卡常技巧(如把i++改成++i,自己定义min和max代替algorithm中的,在函数前加inline)。

参考代码如下:

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define max(a,b) ((a)>(b)?a:b)
#define min(a,b) ((a)<(b)?a:b)
#define ll long long
#define maxid 250005
using namespace std;
struct Splay{
int ch[],fa,times,size;
ll score,hash;
Splay(){
ch[]=ch[]=fa=times=size=score=hash=;
}
Splay(int f,ll has,ll scr,int tms){//新建节点的构造函数
ch[]=ch[]=;
fa=f;
times=tms;
size=;
score=scr;
hash=has;
}
}node[maxid];
map<ll,int>tono;//Hash映射到Splay节点的编号
int splayid=,super;//super是Splay大根的下标
inline void maintain(int p){
node[p].size=node[node[p].ch[]].size+node[node[p].ch[]].size+;
}
inline void rot(int&p,int lr){//0:左旋 1:右旋
int faa=node[p].fa;
int k=node[p].ch[lr^];
node[p].ch[lr^]=node[k].ch[lr];
node[node[p].ch[lr^]].fa=p;
maintain(p);
node[p].fa=k;
node[k].ch[lr]=p;
maintain(k);
node[k].fa=faa;
p=k;
}
inline void ins(int&p,int fa,ll hash,ll score,int times){//插入节点
if(!p){//新建节点
node[p=++splayid]=Splay(fa,hash,score,times);
return;
}
if(node[p].score!=score?node[p].score<score:node[p].times>times)ins(node[p].ch[],p,hash,score,times);
else ins(node[p].ch[],p,hash,score,times);
maintain(p);
}
inline int qrank(int p){//查询节点p的排名
int ans=node[node[p].ch[]].size+;
int fa=node[p].fa;
while(fa){
if(p==node[fa].ch[])ans+=node[node[fa].ch[]].size+;
p=fa;
fa=node[p].fa;
}
return ans;
}
inline int qid(int p,int rank){//查询排名为rank的节点
if(rank<=node[node[p].ch[]].size)return qid(node[p].ch[],rank);
else if(rank==node[node[p].ch[]].size+)return p;
else return qid(node[p].ch[],rank-node[node[p].ch[]].size-);
}
inline void splay(int p){//将p旋到根
int fa=node[p].fa;
while(fa){//还没到根节点
int ga=node[fa].fa;//爷爷
if(ga&&((node[ga].ch[]==fa&&node[fa].ch[]==p)||(node[ga].ch[]==fa&&node[fa].ch[]==p))){//一字型,双旋
int&pt=node[ga].fa?(node[node[ga].fa].ch[]==ga?node[node[ga].fa].ch[]:node[node[ga].fa].ch[]):super;
if(node[ga].ch[]==fa){
rot(pt,);
rot(pt,);
}else{
rot(pt,);
rot(pt,);
}
p=pt;
fa=node[p].fa;
}else{//普通单旋
int&pt=ga?(node[ga].ch[]==fa?node[ga].ch[]:node[ga].ch[]):super;
if(p==node[fa].ch[])rot(pt,);
else rot(pt,);
p=pt;
fa=node[p].fa;
}
}
}
bool toright;//是否到达了右哨兵
inline void pt(ll hash){//打印字符串
if(!hash){
toright=;
return;
}
char s[];
s[]=;
int pos=;
while(hash){
s[--pos]=hash%-+'A';
hash/=;
}
printf("%s ",s+pos);
}
inline void print(int&p,int rank){//打印字符串
if(rank<=node[node[p].ch[]].size)print(node[p].ch[],rank);
else if(rank>+node[node[p].ch[]].size)print(node[p].ch[],rank-node[node[p].ch[]].size-);
else pt(node[p].hash);
}
inline ll rd(){//快读
ll ans=;
char c=;
while(c<''||c>'')c=getchar();
while(c>=''&&c<=''){
ans=ans*10LL+c-'';
c=getchar();
}
return ans;
}
int main(){
int n=rd();
ins(super,,,1000000000000000000LL,);//左(前)哨兵
ins(super,,,-1000000000000000000LL,);//右(后)哨兵
for(int times=;times<=n;++times){//时间顺序
char tp=;
while(tp!='+'&&tp!='?')tp=getchar();
if(tp=='+'){
ll hash=;
char ch=getchar();
while(ch>='A'&&ch<='Z'){
hash=hash*+ch-'A'+;//将字符串Hash,不用取模,因为最多只有10位字母
ch=getchar();
}
ll score=rd();
if(tono[hash]){//存在,需要先删除原来的节点
int rnk=qrank(tono[hash]);
splay(qid(super,rnk-));
splay(qid(super,rnk+));
if(node[node[super].ch[]].ch[]){
node[node[super].ch[]].ch[]=;
maintain(node[super].ch[]);
maintain(super);
}else{
int pre=node[node[super].ch[]].ch[];
node[super].ch[]=pre;
node[pre].fa=super;
maintain(super);
}
}
ins(super,,hash,score,times);
tono[hash]=splayid;
splay(splayid);
}else{
char ch=getchar();
if(ch>=''&&ch<=''){//查10个人名
int num=;
while(ch>=''&&ch<=''){
num=num*+ch-'';
ch=getchar();
}
toright=;
for(int i=;i<=;++i){
print(super,num+i);
if(toright)break;
splay(qid(super,num+i));
}
putchar('\n');
}else{//查排名
ll hash=;
while(ch>='A'&&ch<='Z'){
hash=hash*+ch-'A'+;
ch=getchar();
}
int ans=qrank(tono[hash]);
splay(tono[hash]);
printf("%d\n",ans-);//有左哨兵,所以要-1
}
}
}
return ;
}

【洛谷P2584】【ZJOI2006】GameZ游戏排名系统题解的更多相关文章

  1. [洛谷P2584][ZJOI2006]GameZ游戏排名系统

    题目大意:同[洛谷P4291][HAOI2008]排名系统(双倍经验) 题解:略 卡点:无 C++ Code: #include <cstdio> #include <map> ...

  2. luogu P2584 [ZJOI2006]GameZ游戏排名系统 Splay

    实在不想调了QAQ... Code: #include <cstdio> #include <algorithm> #include <cstring> #incl ...

  3. BZOJ 1862: [Zjoi2006]GameZ游戏排名系统 [treap hash]

    1862: [Zjoi2006]GameZ游戏排名系统 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1318  Solved: 498[Submit][ ...

  4. BZOJ_1862_[Zjoi2006]GameZ游戏排名系统&&BZOJ_1056_[HAOI2008]排名系统_Splay

    BZOJ_1862_[Zjoi2006]GameZ游戏排名系统&&BZOJ_1056_[HAOI2008]排名系统_Splay Description 排名系统通常要应付三种请求:上传 ...

  5. 1056/1862. [ZJOI2006]GameZ游戏排名系统【平衡树-splay】

    Description GameZ为他们最新推出的游戏开通了一个网站.世界各地的玩家都可以将自己的游戏得分上传到网站上.这样就可以看到自己在世界上的排名.得分越高,排名就越靠前.当两个玩家的名次相同时 ...

  6. bzoj1862: [Zjoi2006]GameZ游戏排名系统

    Description GameZ为他们最新推出的游戏开通了一个网站.世界各地的玩家都可以将自己的游戏得分上传到网站上.这样就可以看到自己在世界上的排名.得分越高,排名就越靠前.当两个玩家的名次相同时 ...

  7. [ZJOI2006]GameZ游戏排名系统

    Description GameZ为他们最新推出的游戏开通了一个网站.世界各地的玩家都可以将自己的游戏得分上传到网站上.这样就可以看到自己在世界上的排名.得分越高,排名就越靠前.当两个玩家的名次相同时 ...

  8. 【BZOJ】1862: [Zjoi2006]GameZ游戏排名系统 & 1056: [HAOI2008]排名系统(treap+非常小心)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1862 http://www.lydsy.com/JudgeOnline/problem.php?id ...

  9. bzoj 1056 [HAOI2008]排名系统(1862 [Zjoi2006]GameZ游戏排名系统)

    1056: [HAOI2008]排名系统 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1854  Solved: 502[Submit][Statu ...

随机推荐

  1. 复杂JSON对象的查询与合并

    一个表里存放了全国各地地区.省.市.县区的数据,为了提高加载速度我保存成了本地的JSON文件 结构大致如下: [{ "text": "中华人民共和国", &qu ...

  2. Java框架spring Boot学习笔记(八):@PropertySource,@Value注解

    获取配置文件 忽略配置文件不存在时报错

  3. oracle 按表数据新增一行

    在功能实现时,能尽量用一个sql语句直接实现业务逻辑的话,就不要去写C#代码,便于维护. 以下sql的逻辑是:给明细表新增一条数据,前提是传入的债券代码存在与债券表,否则不新增.此sql返回受影响行数 ...

  4. node重新加载模块

    delete require.cache[require.resolve('module name')]; var my_module = require('module name');

  5. Tomcat开启本地库(Apache Tomcat Native Library)支持

    操作系统环境:Ubuntu 17 amd64位 软件环境:Tomcat 9 tomcat安装位置:/opt/tomcat JDK:1.8.144 64位  安装步骤: 1:编译安装 cd /opt/t ...

  6. Python集合框架

  7. sed awk

    sed -n 's/,*$//g;s/,\+/,/g;/,/p' test.csv 去除行尾逗号,将多个连续逗号合并,过滤没有逗号的行 awk -F, 'NF>5 split($1,a,&quo ...

  8. 输入ip和端口号python脚本py文件

    1.利用.py文件进行打开URL,编辑以下文件代码保存文件为login.py: # _*_ coding: cp936 _*__all_ = ['ip','port','root_id']ip='10 ...

  9. Python_格式化字符

    %% 百分号标记 #就是输出一个%%c 字符及其ASCII码%s 字符串 %r 是不管是什么打印出来%d 有符号整数(十进制)%u 无符号整数(十进制)%o 无符号整数(八进制)%x 无符号整数(十六 ...

  10. C++ STL库的总结以及实现原理

    STL的容器可以分为以下几个大类:一:序列容器, 有vector, list, deque, string. 二 : 关联容器,     有set, multiset, map, mulmap has ...