排名系统通常要应付三种请求:上传一条新的得分记录、查询某个玩家的当前排名以及返回某个区段内的排名记录。当某个玩家上传自己最新的得分记录时,他原有的得分记录会被删除。为了减轻服务器负担,在返回某个区段内的排名记录时,最多返回10条记录。
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; }
排名系统通常要应付三种请求:上传一条新的得分记录、查询某个玩家的当前排名以及返回某个区段内的排名记录。当某个玩家上传自己最新的得分记录时,他原有的得分记录会被删除。为了减轻服务器负担,在返回某个区段内的排名记录时,最多返回10条记录。
第 一行是一个整数n(n>=10)表示请求总数目。接下来n行,每行包含了一个请求。请求的具体格式如下: +Name Score 上传最新得分记录。Name表示玩家名字,由大写英文字母组成,不超过10个字符。Score为最多8位的正整数。 ?Name 查询玩家排名。该玩家的得分记录必定已经在前面上传。 ?Index 返回自第Index名开始的最多10名玩家名字。Index必定合法,即不小于1,也不大于当前有记录的玩家总数。
对于?Name格式的请求,应输出一个整数表示该玩家当前的排名。对于?Index格式的请求,应在一行中依次输出从第Index名开始的最多10名玩家姓名,用一个空格分隔。
20%数据满足N<=100 100%数据满足N<=250000