1056: [HAOI2008]排名系统&1862: [Zjoi2006]GameZ游戏排名系统&codevs 1985

要求打一个数据结构,支持单点修改,单点排名查询,区间排名查询。

Splay模板题。

可以多加两个节点在两边,开个数组记录玩家在Splay上的位置。

然而bzoj卡cin,又懒,不想打哈希,于是愉快的精神AC了。

可以交codevs:http://codevs.cn/problem/1985/


手贱错误:

del操作while(tr[p].son[1]!=0) p=tr[p].son[1];   不要手贱成while(tr[p].son[1]!=0) p=tr[x].son[1];
ins操作后要更新x节点


code:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<map>
#include<string>
#include<iostream>
#define LL long long
using namespace std;
const LL inf=(1LL<<55);
const int maxn=1320020;
struct trnode{
    int d2,id,c,son[2],fa;//d1是权值 d2是位置权 
    LL d1;
}tr[maxn];int root=0,len=0,n;
map <string ,int> name;
struct node{
    string s;
    int id,len;
}a[maxn];int num=0,tot=0;
void update(int x)
{
    int lc=tr[x].son[0],rc=tr[x].son[1];
    tr[x].c=tr[lc].c+tr[rc].c+1;
}
bool big(LL x1,int x2,LL y1,int y2)
{
    if(x1>y1) return true;
    if(x1<y1) return false;
    return x2<y2;
}
void add(LL d1,int d2,int fa,int id,int x)
{
    tr[x].d1=d1;tr[x].d2=d2;tr[x].c=1;tr[x].id=id;
    tr[x].son[0]=tr[x].son[1]=0;tr[x].fa=fa;
    tr[fa].son[big(d1,d2,tr[fa].d1,tr[fa].d2)?0:1]=x;
}
void rotate(int x)
{
    int y=tr[x].fa,z=tr[y].fa,w,R,r;
    w=tr[y].son[0]==x?1:0;
    R=y;r=tr[x].son[w];
    tr[R].son[1-w]=r;
    if(r!=0) tr[r].fa=R;
    R=z;r=x;
    tr[R].son[tr[z].son[0]==y?0:1]=r;
    if(r!=0) tr[r].fa=R;
    R=x;r=y;
    tr[R].son[w]=r;
    if(r!=0) tr[r].fa=R;
    update(y);update(x);
}
void splay(int x,int fa)
{
    while(tr[x].fa!=fa)
    {
        int y=tr[x].fa,z=tr[y].fa;
        if(z==fa) rotate(x);
        else
            if((tr[z].son[0]==y)==(tr[y].son[0]==x)) rotate(y),rotate(x);
            else rotate(x),rotate(x);
    }
    if(fa==0) root=x;
}
int findid(LL d1,int d2)
{
    int x=root;
    while(1)
    {
        int lc=tr[x].son[0],rc=tr[x].son[1];
        if(big(d1,d2,tr[x].d1,tr[x].d2))
            if(lc==0) break;
            else x=lc;
        else
            if(rc==0) break;
            else x=rc;
    }
    return x;
}
int findip(int k)
{
    int x=root;
    while(1)
    {
        int lc=tr[x].son[0],rc=tr[x].son[1];
        if(k<=tr[lc].c) x=lc;
        else if(k>tr[lc].c+1) k-=(tr[lc].c+1),x=rc;
        else break;
    }
    return x;
}
void ins(LL d1,int d2,int id,int tmp)
{
    if(root==0){add(d1,d2,0,id,tmp);root=tmp;return;}
    int x=findid(d1,d2);
    add(d1,d2,x,id,tmp);
    update(x);splay(x,0);
}
void del(int x)
{
    splay(x,0);
    if(tr[x].son[0]==0&&tr[x].son[1]==0){root=len=0;return;}
    if(tr[x].son[0]!=0&&tr[x].son[1]==0){tr[tr[x].son[0]].fa=0;root=tr[x].son[0];return;}
    if(tr[x].son[0]==0&&tr[x].son[1]!=0){tr[tr[x].son[1]].fa=0;root=tr[x].son[1];return;}
    int p=tr[x].son[0];
    while(tr[p].son[1]!=0) p=tr[p].son[1];
    splay(p,x);root=p;tr[root].fa=0;
    tr[root].son[1]=tr[x].son[1];
    tr[tr[x].son[1]].fa=root;
    update(root);
}
void solve(int l,int r)//让l,r这段区间独立出来
{
    int x=findip(l),y=findip(r+2);
    splay(x,0);splay(y,x);
}
bool first;
void print(int x)
{
    if(tr[x].son[0]!=0) print(tr[x].son[0]);
    int id=tr[x].id;
    if(first) first=false;
    else printf(" ");
    for(int i=1;i<a[id].len;i++) printf("%c",a[id].s[i]);
    if(tr[x].son[1]!=0) print(tr[x].son[1]);
}
int main()
{
    scanf("%d",&n);
    add(inf,-99999999,0,0,++len);add(-inf,99999999,1,0,++len);
    root=1;string ch;
    while(n--)
    {
        cin>>ch;
        if(ch[0]=='+')
        {
            LL d1;scanf("%lld",&d1);
            if(name[ch]==0)
            {
                name[ch]=++num;a[num].s=ch;a[num].id=++len;
                ins(d1,++tot,num,len);a[num].len=ch.size();
            }
            else
            {
                int id=name[ch],x=a[id].id;del(x);
                ins(d1,++tot,id,x);
            }
        }
        else
            if('A'<=ch[1]&&ch[1]<='Z')
            {
                ch[0]='+';int id=name[ch];
                int x=a[id].id;splay(x,0);
                printf("%d\n",tr[tr[x].son[0]].c);
            }
            else
            {
                int tmp=ch.size();int l=0;
                for(int i=1;i<tmp;i++) l=l*10+ch[i]-'0';
                int r=min(num,l+9);solve(l,r);
                first=true;
                print(tr[tr[root].son[1]].son[0]);
                cout<<endl;
            }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值