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

[ 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值