• BZOJ1862: [Zjoi2006]GameZ游戏排名系统


    BZOJ1862: [Zjoi2006]GameZ游戏排名系统

    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

    题解Here!

    一眼看去——平衡树!
    果断选择了$Splay$大法!
    然后我们来对这些操作一个一个分析:

    操作一:更新

    这个操作显然就是两种情况:

    1. 原本没有,那就插入平衡树

    2. 原本有,那就先删除原来的,再插入更新后的。

    但是怎么找到这个人在平衡树中对应的节点呢?

    我们使用了$STL$——已经封装好的$map$!~

    有现成的为什么不用呢?

    于是这个问题就完美解决了。

    操作二:查询排名

    用$map$找到对应节点,伸展到根,然后其左子树的大小即为排名。

    为什么不减一呢?

    因为我们为了操作三,设立了两个哨兵节点。

    操作三:查询名字

    本蒟蒻一开始的想法是一个一个$kth$,然后$TLE$到爆炸。。。

    其实只要把十个节点单独拎出来,按照其后序遍历输出名字即可。

    好了,这个题就做完了。

    然后本蒟蒻还$RE imes2$,原因是在建立新的节点时,$newnode$函数没有返回值。。。

    尴尬到极致。。。

    最后,这个题我还手写读入、手写输出的。。。

    然后具体的细节看代码吧。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<string>
    #include<cstring>
    #include<map>
    #define MAXN 1000010
    #define MAX 2147483646
    using namespace std;
    map<string,int> id;
    int root=0,size=0;
    struct Splay{
        int f,s,son[2];
        int v;
        string name;
    }a[MAXN];
    inline int read(){
        int date=0,w=1;char c=0;
        while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
        while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
        return date*w;
    }
    string input_que(int &f,int &val){
        char ch[15];
        string name="";
        val=0;
        scanf("%s",ch);
        if(ch[0]=='+'){
            f=1;
            int l=strlen(ch);
            for(int i=1;i<l;i++)name+=ch[i];
            val=read();
            return name;
        }
        else{
            if(ch[1]>='0'&&ch[1]<='9'){
                f=3;
                int l=strlen(ch);
                for(int i=1;i<l;i++)val=val*10+ch[i]-'0';
                return name;
            }
            else{
                f=2;
                int l=strlen(ch);
                for(int i=1;i<l;i++)name+=ch[i];
                return name;
            }
        }
        return name;
    }
    void output(string name){
        for(int i=0;i<name.size();i++)putchar(name[i]);
        putchar(' ');
    }
    void print(int rt){
        if(!rt)return;
        if(a[rt].son[1])print(a[rt].son[1]);
        output(a[rt].name);
        if(a[rt].son[0])print(a[rt].son[0]);
    }
    inline void clean(int rt){
        a[rt].f=a[rt].s=a[rt].son[1]=a[rt].son[2]=a[rt].v=0;
        a[rt].name="";
    }
    inline void pushup(int rt){
        if(!rt)return;
        a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+1;
    }
    inline void turn(int rt,int k){
        int x=a[rt].f,y=a[x].f;
        a[x].son[k^1]=a[rt].son[k];
        if(a[rt].son[k])a[a[rt].son[k]].f=x;
        a[rt].f=y;
        if(y)a[y].son[a[y].son[1]==x]=rt;
        a[x].f=rt;
        a[rt].son[k]=x;
        pushup(x);pushup(rt);
    }
    void splay(int rt,int ancestry){
        while(a[rt].f!=ancestry){
            int x=a[rt].f,y=a[x].f;
            if(y==ancestry)turn(rt,a[x].son[0]==rt);
            else{
                int k=a[y].son[0]==x?1:0;
                if(a[x].son[k]==rt){turn(rt,k^1);turn(rt,k);}
                else{turn(x,k);turn(rt,k);}
            }
        }
        if(ancestry==0)root=rt;
    }
    inline int newnode(int fa,string name,int v){
        int rt=++size;
        a[rt].son[0]=a[rt].son[1]=0;
        if(fa)a[fa].son[a[fa].v<v]=rt;
        a[rt].v=v;a[rt].f=fa;
        a[rt].s=1;a[rt].name=name;
        id[name]=rt;
        return rt;
    }
    void insert(int rt,string name,int v){
        int fa=0;
        while(rt){
            fa=rt;
            rt=a[rt].son[a[rt].v<v];
        }
        rt=newnode(fa,name,v);
        splay(rt,0);
    }
    int kth(int rt,int k){
        if(k<1)k=1;
        while(1){
            int y=a[rt].son[0];
            if(k>a[y].s+1){
                k-=a[y].s+1;
                rt=a[rt].son[1];
            }
            else if(k<=a[y].s)rt=y;
            else return rt;
        }
    }
    int front_next(int rt,int k){
        rt=a[rt].son[k];
        while(a[rt].son[k^1])rt=a[rt].son[k^1];
        return rt;
    }
    void remove(int rt){
        splay(rt,0);
        int front=front_next(rt,0),next=front_next(rt,1),q;
        splay(front,0);splay(next,front);
        q=a[next].son[0];
        a[next].son[0]=0;
        clean(q);
        pushup(next);pushup(front);
    }
    void update(string name,int v){
        int x=id[name];
        remove(x);
        insert(root,name,v);
    }
    void get_rank(string name){
        int x=id[name];
        splay(x,0);
        printf("%d
    ",a[a[x].son[1]].s);
    }
    void get_name(int k){
        k=a[root].s-k;
        int next=kth(root,k+1),front=kth(root,k-10),q;
        splay(front,0);splay(next,front);
        q=a[next].son[0];
        print(q);putchar('
    ');
    }
    void work(){
        string name;
        int f,val;
        int t=read();
        while(t--){
            name=input_que(f,val);
            switch(f){
                case 1:{
                    if(id[name])update(name,val);
                    else insert(root,name,val);
                    break;
                }
                case 2:{
                    get_rank(name);
                    break;
                }
                case 3:{
                    get_name(val);
                    break;
                }
            }
        }
    }
    void init(){
        insert(root," ",-1);insert(root," ",MAX);
    }
    int main(){
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    利用LibreOffice进行WORD转PDF
    SpringBoot实践
    Solr学习笔记(一)
    HashMap原理(转)
    PDF.js展示本地文件
    设计模式之代理模式
    (一)DUBBO基本学习
    如何架构一个框架
    冒泡排序
    js 函数传数组参数
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9863844.html
Copyright © 2020-2023  润新知