1056/1862. [ZJOI2006]GameZ游戏排名系统【平衡树-splay】

Description

GameZ为他们最新推出的游戏开通了一个网站。世界各地的玩家都可以将自己的游戏得分上传到网站上。这样就可以看到自己在世界上的排名。得分越高,排名就越靠前。当两个玩家的名次相同时,先上传记录者优先。由于新游戏的火爆,网站服务器已经难堪重负。为此GameZ雇用了你来帮他们重新开发一套新的核心。排名系统通常要应付三种请求:上传一条新的得分记录、查询某个玩家的当前排名以及返回某个区段内的排名记录。当某个玩家上传自己最新的得分记录时,他原有的得分记录会被删除。为了减轻服务器负担,在返回某个区段内的排名记录时,最多返回10条记录。

Input

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

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

cnmd辣鸡题目范围都不给清楚?
调了一上午心态爆炸
其实只要把树稍微修改一下,原本是左子树是小于的数
这个题弄成左子树是小于等于的数
唯一把find函数和其他函数包含Cnt数组部分稍作修改即可。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<map>
  5 #define MAXN (1000000+10)
  6 #define LL long long
  7 using namespace std;
  8 LL Father[MAXN];
  9 LL Son[MAXN][2];
 10 LL Key[MAXN];
 11 LL Size[MAXN];
 12 LL Root,sz;
 13 map<string,LL>Num;
 14 map<LL,string>Name;
 15 LL n;
 16 char c[101];
 17 
 18 inline void Clear(LL x)
 19 {
 20     Father[x]=Son[x][0]=Son[x][1]=Key[x]=Size[x]=0;
 21 }
 22 
 23 inline LL Get(LL x)
 24 {
 25     return Son[Father[x]][1]==x;
 26 }
 27 
 28 inline void Update(LL x)
 29 {
 30     Size[x]=1+Size[Son[x][0]]+Size[Son[x][1]];
 31 }
 32 
 33 inline void Rotate(LL x)
 34 {
 35     LL wh=Get(x);
 36     LL fa=Father[x],fafa=Father[fa];
 37     Son[fa][wh]=Son[x][wh^1];//fa
 38     Father[fa]=x;
 39     if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
 40     Son[x][wh^1]=fa;//x
 41     Father[x]=fafa;
 42     if (fafa) Son[fafa][Son[fafa][1]==fa]=x;//fafa
 43     Update(fa);
 44     Update(x);
 45 }
 46 
 47 inline void Splay(LL x)
 48 {
 49     for (LL fa; fa=Father[x]; Rotate(x))
 50         if (Father[fa])
 51             Rotate(Get(fa)==Get(x)?fa:x);
 52     Root=x;
 53 }
 54 
 55 inline LL Pre()
 56 {
 57     LL now=Son[Root][0];
 58     while (Son[now][1])
 59         now=Son[now][1];
 60     return now;
 61 }
 62 
 63 inline void Insert(LL x)
 64 {
 65     if (!Root)
 66     {
 67         Key[++sz]=x;
 68         Root=sz;
 69         Size[sz]=1;
 70         return;
 71     }
 72     LL fa=0,now=Root;
 73     while (1)
 74     {
 75         fa=now;
 76         now=Son[now][x>Key[now]];
 77         if (!now)
 78         {
 79             Key[++sz]=x;
 80             Father[sz]=fa;
 81             Size[sz]=1;
 82             Son[fa][x>Key[fa]]=sz;
 83             Update(fa);
 84             Splay(sz);
 85             break;
 86         }
 87     }
 88 }
 89 inline LL Find(LL x)
 90 {
 91     LL Ans=0,now=Root;
 92     while (1)
 93         if (Key[x]<Key[now] || Key[x]==Key[now] && x>now)
 94             //这里稍作修改,因为当数相等时肯定后面加入的更小,所以节点的编号可以看作第二关键字
 95             now=Son[now][0];
 96         else
 97         {
 98             Ans+=Size[Son[now][0]];
 99             if (x==now)
100             {
101                 Splay(now);
102                 return Ans+1;
103             }
104             Ans++;
105             now=Son[now][1];
106         }
107 }
108 
109 inline LL Findx(LL x)
110 {
111     LL now=Root;
112     while (1)
113         if (x<=Size[Son[now][0]])
114             now=Son[now][0];
115         else
116         {
117             x-=Size[Son[now][0]];
118             if (x==1)
119             {
120                 Splay(now);
121                 return now;
122             }
123             x--;
124             now=Son[now][1];
125         }
126 }
127 
128 inline void Delete(LL x)
129 {
130     Splay(x);
131     if (!Son[Root][0] && !Son[Root][1])
132     {
133         Clear(Root);
134         Root=0;
135         return;
136     }
137     if (!Son[x][0])
138     {
139         Root=Son[Root][1];
140         Clear(Father[Root]);
141         Father[Root]=0;
142         return;
143     }
144     if (!Son[x][1])
145     {
146         Root=Son[Root][0];
147         Clear(Father[Root]);
148         Father[Root]=0;
149         return;
150     }
151     LL Oldroot=Root;
152     LL pre=Pre();
153     Splay(pre);
154     Son[Root][1]=Son[Oldroot][1];
155     Father[Son[Root][1]]=Root;
156     Clear(Oldroot);
157     Update(Root);
158 }
159 
160 void Work1()//+
161 {
162     LL s;
163     string st="";
164     for (LL i=1; i<=strlen(c)-1; ++i)
165         st+=c[i];
166     if (Num[st]) Delete(Num[st]);
167     scanf("%lld",&s);
168     Insert(s);
169     Name[Root]=st;
170     Num[st]=Root;
171 }
172 
173 void Work2()
174 {
175     LL s=0;
176     string st="";
177     for (LL i=1; i<=strlen(c)-1; ++i)
178     {
179         if (c[i]>='A' && c[i]<='Z')
180             st+=c[i];
181         if (c[i]>='0' && c[i]<='9')
182             s=s*10+c[i]-48;
183     }
184     if (st!="")
185         printf("%lld",Size[Root]-Find(Num[st])+1);
186     if (s)
187     {
188         LL i=Size[Root]-s+1,sum=1;
189         cout<<Name[Findx(i)];
190         i--;
191         while (i>=1)
192         {
193             cout<<' '<<Name[Findx(i)];
194             i--;
195             sum++;
196             if (sum==10) break;
197         }
198 
199     }
200     printf("
");
201 }
202 
203 int main()
204 {
205     scanf("%lld",&n);
206     for (LL i=1; i<=n; ++i)
207     {
208         scanf("%s",&c);
209         if (c[0]=='+')
210             Work1();
211         else
212             Work2();
213     }
214 }
原文地址:https://www.cnblogs.com/refun/p/8680809.html