• COGS 197 [HAOI2008] 排名系统


                      ★★★☆   输入文件:rank.in   输出文件:rank.out   简单对比
                        时间限制:1 s   内存限制:128 MB

    [题目描述]

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

    [输入]

    第一行是一个整数n(10<=n<=250000)表示请求总数目。接下来n行,每行包含了一个请求。请求的具体格式如下:

    +Name Score 上传最新得分记录。Name表示玩家名字,由大写英文字母组成,不超过10个字符。Score为最多8位的正整数。

    ?Name 查询玩家排名。该玩家的得分记录必定已经在前面上传。如果两个玩家的得分相同,则先得到该得分的玩家排在前面。

    ?Index 返回自第Index名开始的最多10名玩家名字。Index必定合法,即不小于1,也不大于当前有记录的玩家总数。

    [输出]

    对于?Name格式的请求,应输出一个整数表示该玩家当前的排名。

    对于?Index格式的请求,应在一行中依次输出从第Index名开始的最多10名玩家姓名,用一个空格分隔。

    [样例]

    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

    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

    说明:

    +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的排名

    [数据范围]

    20%数据满足N<=100

    100%数据满足N<=250000

    题解:

      用SBT维护每个玩家的记录和上传时间,以记录为第一关键字,时间为第二关键字。因为游戏排名记录越高排名越靠前,所以我让 左子树>根>右子树。如果记录一样,时间不一样,时间靠后的往右子树走,时间靠前的往左子树走。

      用map把字符串与玩家编号(1,2,3.....)建立联系,方便建树。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<vector>
      8 #include<queue>
      9 #include<map>
     10 #include<set>
     11 using namespace std;
     12 typedef long long LL;
     13 const LL maxn=250010,base=31;
     14 map<unsigned LL,LL> m;
     15 char s[100],sname[maxn][100]; 
     16 unsigned long long hash;
     17 LL totnum,tottime,Time[maxn],num[maxn];
     18 LL N,tot,root;
     19 LL tim[maxn],key[maxn],name[maxn],siz[maxn],lc[maxn],rc[maxn];
     20 void r_rotate(LL &rt){
     21     LL k=lc[rt];
     22     lc[rt]=rc[k];
     23     rc[k]=rt;
     24     siz[k]=siz[rt];
     25     siz[rt]=siz[lc[rt]]+siz[rc[rt]]+1;
     26     rt=k;
     27 }  
     28 void l_rotate(LL &rt){
     29     LL k=rc[rt];
     30     rc[rt]=lc[k];
     31     lc[k]=rt;
     32     siz[k]=siz[rt];
     33     siz[rt]=siz[lc[rt]]+siz[rc[rt]]+1;
     34     rt=k;
     35 }
     36 void Maintain(LL &rt,bool flag){
     37     if(flag==false){
     38         if(siz[lc[lc[rt]]]>siz[rc[rt]]) r_rotate(rt);
     39         else if(siz[rc[lc[rt]]]>siz[rc[rt]]){
     40             l_rotate(lc[rt]);
     41             r_rotate(rt);
     42         }
     43         else return;
     44     }
     45     else{
     46         if(siz[rc[rc[rt]]]>siz[lc[rt]]) l_rotate(rt);
     47         else if(siz[lc[rc[rt]]]>siz[lc[rt]]){
     48             r_rotate(rc[rt]);
     49             l_rotate(rt);
     50         }
     51         else return;
     52     }
     53     Maintain(lc[rt],0); Maintain(rc[rt],1);
     54     Maintain(rt,1); Maintain(rt,0);
     55 }
     56 void insert(LL &rt,LL player,LL v){
     57     if(rt==0){
     58         rt=++tot;
     59         name[rt]=player; key[rt]=v; tim[rt]=Time[player]; //每个节点维护玩家姓名,记录,时间 
     60         lc[rt]=rc[rt]=0;
     61         siz[rt]=1;
     62         return ;
     63     }
     64     siz[rt]++;
     65     if(v>key[rt]) insert(lc[rt],player,v);//排名系统要求key值越大排名越靠前,key值相同,tim值靠后的放在右子树 
     66     else insert(rc[rt],player,v);
     67     Maintain(rt,false); Maintain(rt,true); 
     68 }
     69 void Delete(LL &rt,LL t,LL v){//删除时间为 t,记录为 v的玩家数据 
     70     if((v>key[rt]&&lc[rt]==0)||(v<key[rt]&&rc[rt]==0)) return ;
     71     siz[rt]--;
     72     if(v==key[rt]){
     73         if(t==tim[rt]){
     74             if(lc[rt]==0||rc[rt]==0) rt=lc[rt]+rc[rt];
     75             else{
     76                 LL u=lc[rt];
     77                 while(rc[u]!=0) u=rc[u];
     78                 name[rt]=name[u]; key[rt]=key[u]; tim[rt]=tim[u];
     79                 Delete(lc[rt],tim[u],key[u]);    
     80             }
     81         }
     82         else if(t<tim[rt]) Delete(lc[rt],t,v);//tim值小的在左子树 
     83         else Delete(rc[rt],t,v);
     84         return ;
     85     }
     86     if(v>key[rt]) Delete(lc[rt],t,v);
     87     else Delete(rc[rt],t,v);
     88 }
     89 LL rank(LL &rt,LL t,LL v){
     90     if(rt==0) return (LL)0;
     91     if(v==key[rt]){
     92         if(t==tim[rt]) return siz[lc[rt]]+(LL)1;
     93         else if(t<tim[rt]) return rank(lc[rt],t,v);
     94         else return siz[lc[rt]]+(LL)1+rank(rc[rt],t,v);
     95     }
     96     if(v>key[rt]) return rank(lc[rt],t,v);
     97     else return siz[lc[rt]]+(LL)1+rank(rc[rt],t,v);
     98 }
     99 LL select(LL &rt,LL k){
    100     if(k==siz[lc[rt]]+1) return name[rt];
    101     if(k< siz[lc[rt]]+1) return select(lc[rt],k);
    102     else return select(rc[rt],k-siz[lc[rt]]-1);
    103 }
    104 int main(){
    105     scanf("%lld",&N);
    106     for(LL i=1,tmp=0;i<=N;i++){
    107         scanf("%s",s);
    108         if(s[1]>'9'||s[1]<'0'){//是 +Name 或 ?Name 
    109             for(LL i=1;i<strlen(s);i++) hash=hash*base+s[i]-'A'+1; //哈希 
    110             if(s[0]=='+'){//添加记录 
    111                 scanf("%lld",&tmp);
    112                 if(m[hash]==0){//是新人 
    113                     m[hash]=++totnum;// 建立map联系 hash值-->玩家编号 
    114                     for(int i=1;i<strlen(s);i++)  sname[totnum][i-1]=s[i];// 玩家编号-->名字 
    115                 }
    116                 else Delete(root,Time[m[hash]],num[m[hash]]);//已经有过,删除记录,时间 记录两个关键字都要保证 
    117                 
    118                 num[m[hash]]=tmp; Time[m[hash]]=++tottime;//时间要改变 
    119                 insert(root,m[hash],tmp);
    120             }
    121             else{
    122                 printf("%d
    ",rank(root,Time[m[hash]],num[m[hash]]));//查询排名 
    123             }
    124         }
    125         else{// ?Index 返回自第 Index 名开始的最多10名玩家名字
    126             tmp=0;
    127             for(int i=1;i<strlen(s);i++)  tmp=tmp*10+s[i]-'0';
    128             for(int i=tmp;i<=tmp+9&&i<=siz[root];i++){
    129                 int j=select(root,i);//找到玩家编号 
    130                 if(i!=tmp) printf(" ");
    131                 printf("%s",sname[j]);
    132             }
    133             printf("
    ");
    134         }
    135         hash=0;
    136     }
    137     return 0;
    138 }
  • 相关阅读:
    记录log中的16进制和ASCII码字符输出
    有效的沟通技巧
    时间的真谛
    目标设定与时间管理
    第四代时间管理
    什么是高效沟通
    error LNK1104: cannot open file 错误解决方案
    js压缩工具1.0界面绘制
    时间管理的定义与目的
    JArgs命令行选项解析>Java套件
  • 原文地址:https://www.cnblogs.com/CXCXCXC/p/5137324.html
Copyright © 2020-2023  润新知