神奇脑洞题解——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;
}
原文地址:https://www.cnblogs.com/XLINYIN/p/11570802.html