codevs1985: GameZ游戏排名系统(Treap)
2018-01-22 15:37
246 查看
题目
GameZ为他们最新推出的游戏开通了一个网站。世界各地的玩家都可以将自己的游戏得分上传到网站上。这样就可以看到自己在世界上的排名。得分越高,排名就越靠前。当两个玩家的名次相同时,先上传记录者优先。由于新游戏的火爆,网站服务器已经难堪重负。为此GameZ雇用了你来帮他们重新开发一套新的核心。 排名系统通常要应付三种请求:上传一条新的得分记录、查询某个玩家的当前排名以及返回某个区段内的排名记录。当某个玩家上传自己最新的得分记录时,他原有的得分记录会被删除。为了减轻服务器负担,在返回某个区段内的排名记录时,最多返回10条记录。输入描述
第一行是一个整数n(n>=10)表示请求总数目。接下来n行每行包含了一个请求。请求的具体格式如下:
+Name Score 上传最新得分记录。Name表示玩家名字,由大写英文字母组成,不超过10个字符。Score为不超过无符号32位整型表示范围的非负整数。
?Name 查询玩家排名。该玩家的得分记录必定已经在前面上传。
?Index 返回自第Index名开始的最多10名玩家名字。Index必定合法,即不小于1,也不大于当前有记录的玩家总数。
20%数据满足N<=100
100%数据满足N<=250000
时间限制为2s
输入数据大小不超过2M。
NOTE:用C++的fstream读大规模数据的效率较低。
输出描述
对于每条查询请求,输出相应结果。对于?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
样例输出
2CATHY TOM ADAM BOB
CATHY LEO KAINE WALT MICK GRACE SANDY JACK TOM BOB
WALT MICK GRACE SANDY JACK TOM BOB ADAM DAM
4
分析
题目中共有三种操作, 而n最大可达250000, 所以这三张操作的时间复杂度应不劣于O(logn), 可以考虑用Treap来实现. Treap是什么? Treap时一种平衡树. Treap = Trea + Heap, 顾名思义, Treap把BST(二叉查找树)和Heap结合了起来, 它和BST一样满足许多优美的性质, 而引入堆的目的就是为了维护平衡, 具有简明易懂, 易于编写, 稳定性佳等优点.[1]下图是Treap和其他平衡树的比较:
在这里不赘述Treap的具体实现, 只讨论Treap的应用.
在这道题中, Treap的结点应该保存有名字, 分数, 时间戳, 子树大小这些信息.
对于第一种操作+Name Score, 先删除原有的结点, 再插入新的结点, 这是平衡树的基本操作, 时间复杂度为O(logn).
对于第二种操作?Name, 直接查找, 时间复杂度也为O(logn).
对于第三种操作?Index, 题目说明了最多只需要输出10位玩家的名字, 即查找排名在[index, min(index+9, all] 区间内的玩家. 我们在结点中已经保存了子树大小这一信息, 于是也可以O(logn)完成这一操作.
具体实现看代码.
代码
#include<bits/stdc++.h> #define x first #define y second #define ok puts("ok"); using namespace std; typedef long long ll; typedef vector<int> vi; typedef pair<int, int> pii; typedef pair<ll, ll> pll; const double PI = acos(-1.0); const int INF=0x3f3f3f3f; const ll LINF=0x3f3f3f3f3f3f3f3f; const int N=3e5+9; const int shift=1e3+9; const double Eps=1e-7; int n, tot, timer, score, sco , tim ; char c; string s, r ; map<string, int> m; //Treap结点 struct node { int id, score, timer, fix, size; //字符串映射id, 分数, 时间戳, 修正值, 子树大小 node *left, *right; //左右子树 inline int lsize() {return left?left->size:0;} //求左子树大小 inline int rsize() {return right?right->size:0;} //求右子树大小 }; //左旋 void leftRotate(node *&a) { node *b = a->right; //与BST的左旋操作相似 a->right = b->left; b->left = a; a = b; b = a->left; b->size = b->lsize() + b->rsize() + 1; //修正经过旋转操作后受影响的结点的子树大小 a->size = a->lsize() + a->rsize() + 1; } //右旋 void rightRotate(node *&a) { node *b = a->left; //与BST的右旋操作相似 a->left = b->right; b->right = a; a = b; b = a->right; b->size = b->lsize() + b->rsize() + 1; //修正经过旋转操作后受影响的结点的子树大小 a->size = a->lsize() + a->rsize() + 1; } //插入 void insert(node *&p, int id, int score, int timer) { if(!p) { p = new node; p->id = id; p->score = score; p->timer = timer; p->fix = rand(); //用随机函数生成修正值 p->left = p->right = NULL; p->size = 1; } else if(score <= p->score) { insert(p->left, id, score, timer); if(p->left->fix < p->fix) //维护堆的特性, 从而保证BST的平衡, 该题维护的是最小堆, 换成最大堆也是OK的 rightRotate(p); else p->size = p->lsize() + p->rsize() + 1; } else { insert(p->right, id, score, timer); if(p->right->fix < p->fix) //维护堆的特性, 从而保证BST的平衡 leftRotate(p); else p->size = p->lsize() + p->rsize() + 1; } } //删除 b4a6 void del(node *&p, int score, int timer) { if(p->score == score && p->timer == timer) { //找到了待删除结点 if(!p->left || !p->right) { //假如是叶子结点或者链结点(只有一个儿子的结点), 直接删除 node *t = p; if(!p->right) p=p->left; else p=p->right; delete t; } else { if(p->left->fix < p->right->fix) { //假如左儿子的修正值小于右儿子的修正值, 进行右旋 rightRotate(p); del(p->right, score, timer); p->size = p->lsize() + p->rsize() + 1; } else { //假如左儿子的修正值大于右儿子的修正值, 进行左旋 leftRotate(p); del(p->left, score, timer); p->size = p->lsize() + p->rsize() + 1; } } } else if(score < p->score || (score == p->score && timer > p->timer)) { //待删除结点在p的左子树中 del(p->left, score, timer); p->size = p->lsize() + p->rsize() + 1; } else { //待删除结点在p的右子树中 del(p->right, score, timer); p->size = p->lsize() + p->rsize() + 1; } } //查找排在第k的玩家 int findK(node *&p, int k) { if(k < p->lsize() + 1) return findK(p->left, k); else if(k > p->lsize() + 1) return findK(p->right, k-(p->lsize()+1)); return p->id; } //查找分数为score且时间戳为timer的玩家 int search(node *&p, int score, int timer, int rank) { if(p->score == score && p->timer == timer) return rank; else if(score < p->score || (score == p->score &&timer > p->timer)) return search(p->left, score, timer, rank - p->left->rsize() - 1); else return search(p->right, score, timer, rank + p->right->lsize() + 1); } int main(void) { node *root = NULL; int n; cin >> n; while(n--) { getchar(); c = getchar(); if(c == '+') { cin >> s >> score; if(m[s]) { //假如该玩家之前已上传过分数 int id = m[s]; del(root, sco[id], tim[id]); //先删除 insert(root, id, score, ++timer); //后插入 sco[id] = score, tim[id] = timer; //记录分数和时间戳, 作为查找操作的信息 } else { //假如该玩家首次上传分数 m[s] = ++tot; r[tot] = s; insert(root, tot, score, ++timer); sco[tot] = score, tim[tot] = timer; } } else { cin>>s; if(isdigit(s[0])) { int all = root->lsize() + root->rsize() + 1, t = 0, k = 1; for(int i = s.length()-1; i >= 0; i--) { t += (s[i] - '0') * k; k *= 10; } for(int i = t; i <= min(t+9, all); i++) { int t1 = findK(root, all-i+1); //二叉树中查找排名第1的, 其实是排在倒数第1, 所以需要反过来 if(i == min(t+9, all)) cout << r[t1] << endl; else cout << r[t1] << ' '; } } else { int id = m[s]; int ans = search(root, sco[id], tim[id], root->lsize() + 1); int all = root->lsize() + root->rsize() + 1; cout << all-ans+1 << endl; } } } return 0; }
相关文章推荐
- 1056: [HAOI2008]排名系统&1862: [Zjoi2006]GameZ游戏排名系统&codevs 1985
- BZOJ 1862/1056 ZJOI 2006 GameZ游戏排名系统/ HAOI 2008 排名系统 Treap (双倍经验)
- bzoj1862&&1056 GameZ游戏排名系统 treap+哈希表
- [BZOJ 1056][BZOJ 1862][HAOI 2008][ZJOI 2006]GameZ游戏排名系统(排名系统)(Treap+哈希表)
- Wikioi 1985 GameZ游戏排名系统
- 【BZOJ1056&&1862】【codevs1985】排名系统,Splay+trie树
- bzoj 1056 && 1862: [Zjoi2006]GameZ游戏排名系统(Treap+Hash)
- 【BZOJ】1862: [Zjoi2006]GameZ游戏排名系统 & 1056: [HAOI2008]排名系统(treap+非常小心)
- BZOJ 1862: [Zjoi2006]GameZ游戏排名系统 [treap hash]
- 【pb_ds】bzoj1056 [HAOI2008]排名系统 bzoj1862 [Zjoi2006]GameZ游戏排名系统
- 【BZOJ】【P1862】【P1056】【排名系统】【GameZ游戏排名系统】
- 【bzoj1862】[ZJOI2006]GameZ游戏排名系统
- bzoj1862: [Zjoi2006]GameZ游戏排名系统
- bzoj 1862: [Zjoi2006]GameZ游戏排名系统 & bzoj 1056: [HAOI2008]排名系统
- [题解]bzoj1056/1862 Zjoi2006 GameZ游戏排名系统
- bzoj1862/1056: [Zjoi2006]GameZ游戏排名系统
- [BZOJ1862][ZJOI2006]GameZ游戏排名系统(平衡树splay)
- bzoj 1862 [Zjoi2006]GameZ游戏排名系统
- bzoj 1056 [HAOI2008]排名系统(1862 [Zjoi2006]GameZ游戏排名系统)
- BZOJ 1056: [HAOI2008]排名系统 & BZOJ 1862: [Zjoi2006]GameZ游戏排名系统