1056: [HAOI2008]排名系统/1862: [Zjoi2006]GameZ游戏排名系统

题目链接

题目大意:维护动态修改,查询排名,查询排名从l开始后10人的姓名

题解:hash一下直接上平衡树
按照分数降序,第二关键字为时间升序排序,这个处理一下就可以了……
输出区间的操作理论上应该把区间提取出来然后中序遍历输出,但是我懒得写了……
然后我因为hash挂了调了2h……改成双模终于过了……

我的收获:数据结构劲啊

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;

#define ll long long
#define pii pair<ll,ll>

const ll N=550005;

ll n,cnt,TOTP;

char opt[15];

map<pii,ll> vis;

pii gethash()
{
    ll seed=0;pii has;
    for(ll i=1;opt[i];i++) seed=seed*277+opt[i]-'A'+1,seed%=987654323;
    has.first=seed;
    for(ll i=1;opt[i];i++) seed=seed*2333+opt[i],seed%=666666431;
    has.second=seed;
    return has;
}

struct fhqtreap{

    ll root;
    ll c[N][2],rk[N],size[N];
    ll k[N];
    char name[N][13];

    ll new_node(ll v)
    {
        size[++cnt]=1;
        k[cnt]=v;
        rk[cnt]=rand();
        memcpy(name[cnt],opt,strlen(opt));
        return cnt;
    }

    void update(ll x){size[x]=size[c[x][0]]+size[c[x][1]]+1;}

    ll merge(ll x,ll y)
    {
        if(!x||!y) return x+y;
        if(rk[x]<rk[y])
        {
            c[x][1]=merge(c[x][1],y);
            update(x);
            return x;
        }
        else
        {
            c[y][0]=merge(x,c[y][0]);
            update(y);
            return y;
        }
    }

    void split(ll now,ll w,ll &x,ll &y)
    {
        if(!now) x=y=0;
        else
        {
            if(k[now]<=w)
                x=now,split(c[now][1],w,c[now][1],y);
            else
                y=now,split(c[now][0],w,x,c[now][0]);
            update(now);
        }
    }

    void del(pii am)
    {
        ll x,y,z; 
        split(root,vis[am],x,z);
        split(x,vis[am]-1,x,y);
        y=merge(c[y][0],c[y][1]);
        root=merge(merge(x,y),z);
    }

    void ins(pii am,ll v)
    {
        if(vis[am]) del(am),TOTP--;
        vis[am]=v,TOTP++;
        ll x,y;
        split(root,v,x,y);
        root=merge(merge(x,new_node(v)),y);
    }

    ll getrank(pii am)
    {
        ll x,y;
        split(root,vis[am]-1,x,y);
        printf("%d\n",size[x]+1);
        root=merge(x,y);
    }

    ll kth(ll now,ll w)
    {
        while(1)
        {
            if(w<=size[c[now][0]]) now=c[now][0];
            else if(w==size[c[now][0]]+1) return now;
            else w-=size[c[now][0]]+1,now=c[now][1];
        }
    }

    void ask(ll l,ll r)
    {
        for(ll i=l;i<=r;i++){
            ll out=kth(root,i),len=strlen(name[out]);
            for(ll j=1;j<len;j++) putchar(name[out][j]);
            if(i<r) putchar(' ');
        }
        putchar('\n');
    } 

}T;

void init()
{
    scanf("%d",&n);
    ll vakl;
    for(ll i=1;i<=n;i++){
        scanf("%s",opt);
        if(opt[0]=='+'){
            scanf("%lld",&vakl);
            T.ins(gethash(),-vakl*300000+i);
        }
        else if(opt[0]=='?'&&opt[1]>='A'&&opt[1]<='Z'){
            T.getrank(gethash());
        }
        else{
            ll str=0,len=strlen(opt);
            for(ll j=1;j<len;j++) str=str*10+opt[j]-'0';
            T.ask(str,min(str+9,TOTP));
        }
    }
}

int main()
{
    init();
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值