【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

posted @ 2014-08-26 16:18  iwtwiioi  阅读(611)  评论(1编辑  收藏  举报