• 神奇脑洞题解——HAOI[2008]排名系统


    这是一道人种检测题!

    为啥说他是人种检测题呢,因为官方标算是有随机数的参与的,至于在哪,下面再说。

        [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

    这道题一看就知道是Splay维护得分,至于如何替换?

    不换,把原来的得分记录删掉,直接新加进去一个得分即可(同时储存每个人对应最新一次得分记录的序号)

    至于字符串处理问题吗,用Map直接压一下即可。

    然后强调一下插入的问题,这道题是没有同分维护的,也就是说即使有相同的得分也要再开一个新点。

    这个新点一定要开到得分相同点的左儿子上。

    因为查询的时候要求同分情况下优先输出最先压入的,这样就可以保证查询时一定按照压入顺序输出。

    人种测试:

    这道题的官方题解中是有随机化提根的(就是在某个时刻将Splay的形状改变,将根变为某个随机的点)

    这个时刻和提出哪个点都是你自己定的,毕竟提根也是有时间的,提的多了亏了,提的少了没用,还有可能随机数提根将树提成链的

    非洲福利:根据本人无限次非酋,每200个操作提一次根,提根直接用rand()%tot+1作为被提起的根即可,不要加srand(time(0))。

    因为一旦加上time以当前时间作为种子,rand的值就是动态的了。这也就是决定非欧的空间。

    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<algorithm>
    #include<ctime>
    using namespace std;
    struct PE
    {
        int ff,val,size,ch[2];
    };
    PE t[2500100];
    map<string,int> M;
    string name[2500100];
    int rt,tot,n;
    string x1,x2;
    void pushup(int x)
    {
        t[x].size=t[t[x].ch[0]].size+1+t[t[x].ch[1]].size; 
    } 
    void rotate(int x)
    {
        int y=t[x].ff;
        int z=t[y].ff;
        int k=(t[y].ch[1]==x);
        t[z].ch[y==t[z].ch[1]]=x;
        t[y].ch[k]=t[x].ch[k^1];
        t[t[x].ch[k^1]].ff=y;
        t[x].ch[k^1]=y;
        t[y].ff=x;
        t[x].ff=z;
        pushup(y);
        pushup(x);
    }
    void Splay(int x,int goal)
    {
        while(t[x].ff!=goal)
        {
            int y=t[x].ff;
            int z=t[y].ff;
            if(z!=goal)
            {
                (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
            }
            rotate(x);
        }
        if(goal==0)
            rt=x; 
    }
    void insert(int x,int id)
    {
        int u=rt;
        while(t[u].ch[x>t[u].val])
        {
            u=t[u].ch[x>t[u].val];
        }
        t[id].ff=u;
        t[id].val=x;
        t[id].ch[0]=t[id].ch[1]=0;
        t[id].size=1;
        t[u].ch[t[u].val<x]=id;
        Splay(id,0);
    }
    int KTH(int K)
    {
        int u=rt;
        while(1)
        {
            if(t[t[u].ch[0]].size+1==K)
                return u;
            if(t[t[u].ch[0]].size>=K)
                u=t[u].ch[0];
            else
            {
                K-=t[t[u].ch[0]].size+1;
                u=t[u].ch[1];
            }
        }
    } 
    void Del(int x)
    {
        Splay(x,0);
        int rk=t[t[x].ch[0]].size;
        int l=KTH(rk);
        int r=KTH(rk+2);
        Splay(l,0);
        Splay(r,l);
        t[r].ch[0]=0;
        t[x].ff=t[x].size=t[x].val=0;
        pushup(r);
        pushup(l);
    }
    void Print(int x,int &sum)
    {
        if(!sum)
            return ;
        if(t[x].ch[1])
        {
            Print(t[x].ch[1],sum);
        }
        if(!sum)
            return;
        if(x>2)
        {
            //x=1是正无限的id,x=2是负无限的id 
            sum--;
            cout<<name[x]<<' ';
        }
        if(t[x].ch[0])
            Print(t[x].ch[0],sum);
    }
    int main()
    {
        freopen("rank.in","r",stdin);
        freopen("rank.out","w",stdout);
        //srand(time(0));
        scanf("%d",&n);
        insert(2147483647,++tot);
        insert(-2147483647,++tot);
        for(int i=1;i<=n;i++)
        {
            cin>>x1;
            if(x1[0]=='+')
            {
                x1.erase(0,1);
                int kl;
                cin>>kl;
                if(M[x1])
                {
                    int ids=M[x1];
                    Del(ids);
                    insert(kl,ids);
                }
                else
                {
                    insert(kl,++tot);
                    M[x1]=tot;
                    name[tot]=x1;
                }
            }
            else
            {
                if(x1[0]=='?')
                {
                    x1.erase(0,1);
                    if(x1[0]>='0'&&x1[0]<='9')
                    {
                        int temp=0;
                        for(int j=0;j<x1.size();j++)
                        {
                            temp=temp*10+x1[j]-'0';
                        }
                        int l=KTH(tot-temp+1);
                        Splay(l,0);
                        int sum=10;
                        Print(t[l].ch[0],sum);
                        cout<<endl;
                    }
                    else
                    {
                        int kkk=M[x1];
                        Splay(kkk,0);
                        cout<<t[t[kkk].ch[1]].size<<endl;
                    }
                }
            }
            if((i+200)%200==0)
            {
                Splay(rand()%tot+1,0);
            }
        }
        return 0;
    }
  • 相关阅读:
    7、【Linux系统编程】阻塞和非阻塞
    css样式
    如果目录不存在就创建
    api图片传输,转成64位字符串进行传输
    c#获取远程图片的方法
    分页
    使用微信js接口的方法 ,以调用相机为例
    某个文件下下面的文件批量改名
    查找本地文件中的特定字符串并替换代码
    第35月第6天 自定义view初始化
  • 原文地址:https://www.cnblogs.com/XLINYIN/p/11570802.html
Copyright © 2020-2023  润新知