BZOJ 1056([HAOI2008]排名系统-Treap旋转概率)

1056: [HAOI2008]排名系统

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 670   Solved: 179
[ Submit][ Status][ Discuss]

Description

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

Input

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

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
4





HINT

20%数据满足N<=100
100%数据满足N<=250000

Source

[ Submit][ Status][ Discuss]



根据CLJ在重量平衡树中提到的Treap旋转概率1/子树大小

我成功的写出了这题

由于这题要记录父节点(可以不记?我i弱)话外:神犇无视

以及对*&x 的理解不能(现在懂了,就是址传指针(等于没说?),这里改变会同时修改传递过来的指针的指向,然后又影响回程序 )

还有对root的各种特判无能(话说我只要加一个无用Root的就好了,费那事干嘛)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<map>
#include<string>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define MAXLen (10+1)
int n;
struct node
{
    node *ch[2],*fa;
    char a[MAXLen];
    int size,w;
    node(char c[],int _w):size(1),w(_w){memcpy(a,c,sizeof(a));ch[0]=ch[1]=NULL;}
    node(char c[],node *_fa,int _w):w(_w),size(1){memcpy(a,c,sizeof(a));fa=_fa;ch[0]=ch[1]=NULL;}
    void update()
    {
        size=1;
        if (ch[0]!=NULL) size+=ch[0]->size;
        if (ch[1]!=NULL) size+=ch[1]->size;
    }
}*root=NULL;
char s[MAXLen];
void rotate(node *&x,int i)
{
    node *y=x->ch[i^1];x->ch[i^1]=y->ch[i];if (x->ch[i^1]) x->ch[i^1]->fa=x;y->ch[i]=x;
    y->fa=x->fa;
    x->fa=y;
    x->update();y->update();
    if (y->fa)
    {
        if (y->fa->ch[0]==x) y->fa->ch[0]=y;
        else y->fa->ch[1]=y;
    }
    x=y;
}
map<string,node*> h;
void insert(node *&x,int w)
{
    if (x==NULL) {x=new node(s,w);x->fa=NULL;h[string(s)]=x;return;}
    int i=w<=x->w;
    if (x->ch[i]==NULL) {x->ch[i]=new node(s,x,w);h[string(s)]=x->ch[i];x->update();return;}
    else insert(x->ch[i], w);
    x->update();
    if (rand()%(x->size)<1) rotate(x,i^1);
    if (x->fa==NULL) root=x;
}
void delet(node *&x)
{

    while (1)
    {
        if (x->ch[0]) {rotate(x,1);if (x->fa==NULL) root=x;x=x->ch[1];}
        else if (x->ch[1]) {rotate(x,0);if (x->fa==NULL) root=x;x=x->ch[0];}
        else break;
    }
    if (x->fa)
    {
        node* p=x->fa;
        int i=p->ch[1]==x;
        p->ch[i]=NULL;
        while (p) p->size--,p=p->fa;
    }
    if (root==x) root=NULL;
    delete x;

}
void print(node *&x)
{
    if (x->ch[0]) print(x->ch[0]);
    printf("%s ",x->a);
    //cout<<x->size<<' ';
    if (x->ch[1]) print(x->ch[1]);
}
void find_kth(node *&x,int k)
{
    int ls=x->ch[0]!=NULL?x->ch[0]->size:0;
    int rs=x->size-1-ls;
    if (ls>=k) find_kth(x->ch[0],k);
    else if (ls+1==k) memcpy(s,x->a,sizeof(s));
    else find_kth(x->ch[1],k-ls-1);
}
int count(node *x)
{
    int ans=1;
    ans+=(x->ch[0]!=NULL)?x->ch[0]->size:0;
    while (x)
    {
        node *y=x->fa;
        if (y==NULL) return ans;
        if (y->ch[1]==x) ans+=1,ans+=(y->ch[0])?y->ch[0]->size:0;
        x=x->fa;
    }
    return ans;

}
int main()
{
	freopen("bzoj1056.in","r",stdin);
    scanf("%d\n",&n);
    For(i,n)
    {
        int w;
        char c;
        scanf("%c",&c);
        switch(c)
        {
            case'+':
                {
                    scanf("%s %d\n",s,&w);
                    if (h.find(s)==h.end()) insert(root,w);
                    else delet(h[s]),insert(root,w);
                    //printf("\n%s %d\n",s,w);
                    break;
                }
            case'?':
                {
                    scanf("%s\n",s);
                    if (!isupper(s[0]))
                    {
                        w=strtol(s,0,10);

                        int tot=min(root->size,w+9);
                        Fork(j,w,tot)
                        {
                            find_kth(root,j);
                            printf("%s",s);
                            if (j<tot) printf(" ");
                            else puts("");
                        }

                        //printf("\n%d\n",w);
                    }
                    else
                    {
                        printf("%d\n",count(h[s]));
                        //printf("\n%s\n",s);
                    }
                }
        }
     // print(root);cout<<endl;
    }
    //cout<<h[string("ADAM")]<<endl;
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值