Description

GameZ为他们最新推出的游戏开通了一个网站。世界各地的玩家都可以将自己的游戏得分上传到网站上。这样就可以看到自己在世界上的排名。得分越高,排名就越靠前。当两个玩家的名次相同时,先上传记录者优先。由于新游戏的火爆,网站服务器已经难堪重负。为此GameZ雇用了你来帮他们重新开发一套新的核心。排名系统通常要应付三种请求:上传一条新的得分记录、查询某个玩家的当前排名以及返回某个区段内的排名记录。当某个玩家上传自己最新的得分记录时,他原有的得分记录会被删除。为了减轻服务器负担,在返回某个区段内的排名记录时,最多返回10条记录。

Input

第一行是一个整数n(n>=10)表示请求总数目。接下来n行每行包含了一个请求。请求的具体格式如下: +Name Score 上传最新得分记录。Name表示玩家名字,由大写英文字母组成,不超过10个字符。Score为最多8位的正整数。 ?Name 查询玩家排名。该玩家的得分记录必定已经在前面上传。 ?Index 返回自第Index名开始的最多10名玩家名字。Index必定合法,即不小于1,也不大于当前有记录的玩家总数。输入文件总大小不超过2M。 NOTE:用C++的fstream读大规模数据的效率较低

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的排名

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

算法分析

主要涉及到三种操作,我们可以用Treap或者Splay实现。由于Splay实现相对复杂,我们用Treap实现。存储我们这里采用二叉链。

  1. 查询名字,我们可以通过hash生成名字与id的映射,同时由于我们建树是把分数作为关键字,并且先插入的数字比较大,因此我们可以把分数乘以一个很大的树,然后减去当前插入的数作为id。这里我们图省事儿直接用了STL的map。
  2. 查询排名,这个我们可以理解为:BST中只要一直沿着右子树下降那么最右边的肯定是第一名,因为他最大,同时我们把每个节点绑定一个size,这个size代表节点包含子节点的总数目(包括自己),那么我们很明显知道节点的右子节点的size+1就是排名;如果沿着左子树去查找了,那么我们需要把要找的节点的size加右子树的size+1,这样我们就递归的找到了。
  3. 查询邻近的10个排名
  • 先解决查询第k名的问题,这个就是问题2的逆过程:

    • BST中只要一直沿着右子树下降那么最右边的肯定是第一名,因为他最大,同时我们把每个节点绑定一个size,这个size代表节点包含子节点的总数目(包括自己),那么我们很明显知道节点的右子节点的size+1就是排名;如果沿着左子树去查找了,那么我们需要把要找的排名k减掉前几名再去找,这个前几名也就是右子树的size+1,这样我们就递归的找到了。
  • 再解决k到k+9区间问题。这个用Splay的话很好实现,我们先找到第k名和第k+9(当然不能越界),然后把第k+9旋转到k的右边,遍历子树就可以了。对于Treap树的话相对复杂一点,就是需要逐个去找k到k+9排名的同学,稍微复杂一点。

C++源码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <map>
#include <string>
#include <iostream>typedef long long int LL;
using namespace std;//二叉链表示Treap树的节点
struct Node
{int size;  //4字节LL score;  //id就是score,8字节string name;  //假设不超过10,需要10字节int priority;  //4字节Node *left;  //4字节Node *right; //4字节
};Node *root;   //根节点
map<string,LL>mp; //名字与id的map//修改节点包含的节点总数目
void push_up(Node *rt){int lsize = rt->left ? rt->left->size : 0 ;int rsize = rt->right ? rt->right->size : 0;rt->size = lsize + rsize + 1;
}void zig(Node * &node){ //右旋Node *x = node->left;node->left = x->right;x->right = node;x->size = node->size;  //父节点总数不变push_up(node);   //子节点总数需要从新计算,因为左子树变了node = x;
}void zag(Node* &node){ //左旋Node *x = node->right;node->right = x->left;x->left = node;x->size = node->size;push_up(node);  //右子树变了重新计算node = x;
}//插入节点,并记录size大小
void t_insert(Node* &root, string name, LL score){if(root == NULL){Node *node = new Node;node->name = name;node->score = score;node->priority = rand();node->left = node->right = NULL;node->size = 1;root = node;return;}root->size++;if(score < root->score){t_insert(root->left, name, score);if(root->left->priority < root->priority)zig(root); //右旋}else{ //我们在插入的时候避免了score相同,不会出现重复t_insert(root->right, name, score);if(root->right->priority < root->priority)zag(root); //左旋}
}void _insert(string name, LL score){t_insert(root,name,score);
}//求id为score的节点
Node* queryNode(Node*root,LL score){if(root->left && root->left->score > score) return queryNode(root->left,score);else if(root->right && root->right->score < score) return queryNode(root->right,score);else return root;
}//获取右节点的排名(注意不是每个节点是这样获取排名,这里使用的多所以单独写出来了)
int getNodeRank(Node *node){return node->right ? node->right->size + 1:1;
}//获取id为score的节点的排名
int queryRank(Node*root,LL score){if(!root)   //这里说明没找到,我们这里没处理,只是返回0return 0;if(score == root->score) return getNodeRank(root);if(score > root->score) return queryRank(root->right,score);return queryRank(root->left,score) + getNodeRank(root);
}//根据名字映射的scoreid求排名
int _queryRank(LL score){return queryRank(root,score);
}//求排名第k的节点
Node* findRank(Node * root,int k){if(k > root->size || k < 1) {  //排名越界,最少是第1,最多是第根节点的大小return NULL;}int s = root->right ? root->right->size : 0;if(s+1 == k) return root;else if(k<s+1) return findRank(root->right,k);return findRank(root->left, k-s-1);
}//查找从第k名开始的10名同学
void _find10Rank(int k){for(int i=k;i<k+10;i++){Node *t = findRank(root,i);if(t)cout<<t->name<<" ";}cout<<endl;
}void t_delete(Node *&root, LL score){if(root !=NULL){if(score < root->score){root->size--;t_delete(root->left, score);}else if(root->score < score){root->size--;t_delete(root->right, score);}else{ //找到节点if(root->left == NULL)root = root->right;  //只有右孩子,直接把右孩子替换就可删除else if(root->right == NULL)root = root->left;else{if(root->left->priority < root->right->priority)zig(root);else zag(root);if(root != NULL)t_delete(root,score);else{delete root->left;root->left = NULL;}}}   }
}void _delete(LL score){t_delete(root,score);
}//遍历节点,此处无用
void in_order_traverse(Node *root){if(root != NULL){in_order_traverse(root->left);cout<<root->name<<root->score<<endl;in_order_traverse(root->right);}
}int main()
{mp.clear();int n;cin>>n;string s,ss;int sc;for (int i=1;i<=n;i++){cin>>s;ss="";for(int i=1;i<s.size();i++) ss+=s[i];if(s[0]=='+'){cin>>sc;if(mp[ss]!=0) _delete(mp[ss]);mp[ss]=(LL)sc*1000000-i;   //保证先插入的一定排名考前_insert(ss,mp[ss]);}else {if('0'<=ss[0]&&ss[0]<='9'){sc=0;for(int j=0;j<ss.size();j++) sc=(sc<<3)+(sc<<1)+ss[j]-'0';_find10Rank(sc);}else{cout<<_queryRank(mp[ss])<<endl;}}   }
}
复制代码

算法分析

Treap的平均时间复杂度是O(logN),对于这三个操作基本都是O(logN)的时间复杂度。N为插入的总记录数。

在32位操作系统上,空间的话由于引入了map,一般而言map的空间代价略大于2N*18字节(假设名字小于10字节),节点采用二叉链存储总共需要N *30字节,一共大约需要44 *N字节。

Treap树应用-bzoj 1862 GameZ游戏排名系统问题相关推荐

  1. HYSBZ 1862 GameZ游戏排名系统

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1862 将相等的值放到左子树下 自然就维护了先上传排名高的条件 维护名字可以用hash 这里为了 ...

  2. 【BZOJ 1862】 [Zjoi2006]GameZ游戏排名系统

    1862: [Zjoi2006]GameZ游戏排名系统 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 695  Solved: 265 [Submit] ...

  3. bzoj 1862 [Zjoi2006]GameZ游戏排名系统

    1862: [Zjoi2006]GameZ游戏排名系统 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1134  Solved: 429 [Submit ...

  4. BZOJ 1862: [Zjoi2006]GameZ游戏排名系统 Splay

    Splay的基本操作,比较繁琐..... 有个一坑点,sorce会超int 1862: [Zjoi2006]GameZ游戏排名系统 Time Limit: 5 Sec  Memory Limit: 6 ...

  5. BZOJ1862[Zjoi2006]GameZ游戏排名系统【splay+hash】

    [Zjoi2006]GameZ游戏排名系统[Zjoi2006]GameZ游戏排名系统[Zjoi2006]GameZ游戏排名系统 Description: GameZ为他们最新推出的游戏开通了一个网站. ...

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

    luogu P2584 [ZJOI2006]GameZ游戏排名系统 Splay 实在不想调了QAQ... Code: #include <cstdio> #include <algo ...

  7. bzoj 1056 1862: [Zjoi2006]GameZ游戏排名系统(Treap+Hash)

    1056: [HAOI2008]排名系统 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 2783  Solved: 790 [Submit][Sta ...

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

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

  9. codevs1985: GameZ游戏排名系统(Treap)

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

  10. 1862: [Zjoi2006]GameZ游戏排名系统(Splay)

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

最新文章

  1. 新装myeclispse8.6GA、@Override出错
  2. 今天,向 6 女性程序员先驱致敬
  3. linux编译安装memcached
  4. 【学术相关】现阶段硕士的困境:读博没信心,不读还闹心
  5. zookeeper的名词复盘-数据模型
  6. Windows7系统技巧:常用的10个快捷键
  7. java canvas画圆圈_java – 在视图上绘制一个圆圈(android)
  8. 毕业两年的我--奋斗中的程序员
  9. Mybatis源码分析之(五)mapper如何将数据库数据转换成java对象的
  10. CCCF译文 | 从计算思维到计算行动*
  11. java密码校验_java强密码校验
  12. 基于知识图谱的推荐系统综述
  13. Node.js视频教程
  14. 硬盘分区表错误与解决办法
  15. 在ARM板上的linux系统中查看进程实际使用物理内存
  16. CSS优先级权重练习
  17. MyBatis详细笔记
  18. java 配置全局过滤器,如何为Spring Cloud Gateway加上全局过滤器
  19. 性能测试之性能测试需求分析
  20. 27、用户操作srv、web服务实现

热门文章

  1. PV操作解决哲学家进餐问题(图文详解)
  2. Oracle中表pagesize,Oracle使用pagesize命令
  3. java 线程 假死_JVM假死问题如何定位?
  4. PS制作或编辑gif动态图
  5. 学生抗疫HTML网页设计作品 学生疫情网页模板 大学生抗疫感动专题网页设计作业 HTML学生抗疫网站作业设计
  6. 云服务器搭建个人博客
  7. excel两个指标相关性分析_如何在Excel中计算两个变量之间的相关系数?
  8. word文档分节后 如何删除某一节的页码
  9. LaTeX插入参考文献手把手教学 | BibTeX教程
  10. win10分辨率设置正确但屏幕却被拉伸了,如何处理