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

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

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

这两题一模一样啊。。。。

首先这是一道十分恶心的数据结构题。

一定要注意:

首先平衡树内关键字是重复的,那么我们需要用第二关键字来确认位置,即插入时间。

那么就一定要弄清楚顺序。

!!!

因为这个插入顺序和排名有关

所以插入顺序一定要遵循堆的性质

在本题里,插入顺序是左小右大,和平衡树一样。

还有,本题的size是不论key是否相同的。因为有一定的序,所以答案就一定。

 

本题我用map来索引名字,来找到它的信息,从而在平衡树里删去。

treap有很多细节,我就不说了,在以前的博文里说过。

那么这题就是码农题了。

 

#include <cstdio>

#include <cstring>

#include <cmath>

#include <string>

#include <iostream>

#include <algorithm>

#include <map>

#include <string>

using namespace std;

#define rep(i, n) for(int i=0; i<(n); ++i)

#define for1(i,a,n) for(int i=(a);i<=(n);++i)

#define for2(i,a,n) for(int i=(a);i<(n);++i)

#define for3(i,a,n) for(int i=(a);i>=(n);--i)

#define for4(i,a,n) for(int i=(a);i>(n);--i)

#define CC(i,a) memset(i,a,sizeof(i))

#define read(a) a=getint()

#define print(a) printf("%d", a)

#define dbg(x) cout << #x << " = " << x << endl

#define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; }

inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }

inline const int max(const int &a, const int &b) { return a>b?a:b; }

inline const int min(const int &a, const int &b) { return a<b?a:b; }

const int N=250020, oo=~0u>>1;

map<string, pair<int, int> > rk;

int cnt=0, tot=0;

string nam;



struct node* null;

struct node {

	int key, id;

	string name;

	int size, wei;

	node* ch[2];

	node(int _k=0, int _id=0, string _n="", int _s=1) : key(_k), id(_id), name(_n), size(_s) {

		ch[0]=ch[1]=null; wei=rand();

	}

	inline void pushup() { size=ch[0]->size+ch[1]->size+1; }

}*root;

inline void rot(node* &r, const bool d) {

	node* t=r->ch[!d]; r->ch[!d]=t->ch[d]; t->ch[d]=r;

	r->pushup(); t->pushup();

	if(root==r) root=t;

	r=t;

}

inline void insert(node* &r, const int &key, const int &id) {

	if(r==null) { r=new node(key, id, nam); return; }

	bool d=key>r->key;

	insert(r->ch[d], key, id);

	if(r->ch[d]->wei < r->wei) rot(r, !d);

	else r->pushup();

}

inline void del(node* &r, const int &key, const int &id) {

	if(r==null) return;

	bool d=key>r->key;

	if(key==r->key) {

		if(id==r->id) {

			d=r->ch[0]->wei > r->ch[1]->wei;

			if(r->ch[d]==null) {

				delete(r);

				r=null;

				return;

			}

			rot(r, !d);

			del(r->ch[!d], key, id);

		}

		else del(r->ch[id<r->id], key, id);

	}

	else del(r->ch[d], key, id);

	r->pushup();

}

int getrank(node* r, const int &key, const int &id) {

	if(r==null) return 0;

	if(key==r->key) {

		if(id>r->id) return r->ch[1]->size+getrank(r->ch[0], key, id)+1;

		else if(id<r->id) return getrank(r->ch[1], key, id);

		else return r->ch[1]->size+1;

	}

	if(key>r->key) return getrank(r->ch[1], key, id);

	else return getrank(r->ch[0], key, id)+r->ch[1]->size+1;

}

node* select(node* r, const int k) {

	if(r==null) return null;

	int s=r->ch[1]->size+1;

	if(s==k) return r;

	if(s>k) return select(r->ch[1], k);

	else return select(r->ch[0], k-s);

}

void ins(char *nm) {

	int key;

	string str(nm+1);

	read(key);

	if(rk.count(str)!=0) {

		del(root, rk[str].second, rk[str].first);

		rk.erase(str);

		--tot;

	}

	++cnt; ++tot;

	rk[str]=pair<int, int> (cnt, key);

	nam=str;

	insert(root, key, cnt);

}

void ask1(char *nm) {

	string str(nm+1);

	printf("%d\n", getrank(root, rk[str].second, rk[str].first));

}

void ask2(char *nm) {

	int num=0;

	string str(nm+1);

	for(int i=0; i<str.size(); ++i) num=num*10+str[i]-'0';

	int t=min(tot-num+1, 10);

	for(int i=0; i<t; ++i) {

		printf("%s", select(root, num+i)->name.c_str());

		if(i!=t-1) printf(" ");

	}

	puts("");

}

inline void init() {

	null=new node(0, 0, "", 0); null->ch[0]=null->ch[1]=null; null->wei=oo;

	root=null;

}

int main() {

	init();

	int n=getint();

	char str[30];

	while(n--) {

		scanf("%s", str);

		if(str[0]=='+') ins(str);

		else {

			if(str[1]>='A'&&str[1]<='Z') ask1(str);

			else ask2(str);

		}

	}

	return 0;

}

 

 


 

 

Description

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

Input

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

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
4

HINT

20%数据满足N<=100 100%数据满足N<=250000

Source

你可能感兴趣的:(game)