BZOJ 1861 Book 书架(splay)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1861

题意:一个n个数字的数列,数字两两不同。5种操作:(1) 将某个数字调整到第一个位置;(2)将某个数字调整到最后一个位置;(3)将某个数字向前、向后调整一个位置;(4)询问某个数字在数列中的位置;(5)询问数列中某个位置的数字。

思路:使用map映射某个数字与其所在数组的地址。其他的就是简单的splay。

 

struct node
{
    int size,s;
    node *c[2],*f;
};




int n,m;


int d[N];


map<int,node*> mp;
node a[N],*nullNode,*root;
int e;




void pushUp(node *x)
{
    if(x==nullNode) return;    
    x->size=x->c[0]->size+1+x->c[1]->size;
}


void zig(node *x)
{
    node *p=x->f,*q=p->f;
    p->c[0]=x->c[1];
    if(x->c[1]!=nullNode) x->c[1]->f=p;
    x->c[1]=p;
    p->f=x;
    x->f=q;
    if(q!=nullNode)
    {
        if(q->c[0]==p) q->c[0]=x;
        else q->c[1]=x;
    }
    pushUp(p);
    pushUp(x);
    if(root==p) root=x;
}
 
void zag(node *x)
{
    node *p=x->f,*q=p->f;
    p->c[1]=x->c[0];
    if(x->c[0]!=nullNode) x->c[0]->f=p;
    x->c[0]=p;
    p->f=x;
    x->f=q;
    if(q!=nullNode)
    {
        if(q->c[0]==p) q->c[0]=x;
        else q->c[1]=x;
    }
    pushUp(p);
    pushUp(x);
    if(root==p) root=x;





void splay(node *x,node *goal)
{
    while(x->f!=goal)
    {
        if(x->f->f!=goal)
        {
            if(x->f->f->c[0]==x->f)
            {
                if(x->f->c[0]==x) zig(x->f),zig(x);
                else zag(x),zig(x);
            }
            else 
            {
                if(x->f->c[1]==x) zag(x->f),zag(x);
                else zig(x),zag(x);
            }
        }
        else
        {
            if(x->f->c[0]==x) zig(x);
            else zag(x);
        }
    }
}




void select(int k,node *goal)
{
    node *x=root;
    while(x->c[0]->size+1!=k)
    {
        if(x->c[0]->size>=k) x=x->c[0];
        else
        {
            k-=1+x->c[0]->size;
            x=x->c[1];
        }
    }
    splay(x,goal);
}


int select1(int k)
{
    node *x=root;
    while(x->c[0]->size+1!=k)
    {
        if(x->c[0]->size>=k) x=x->c[0];
        else
        {
            k-=1+x->c[0]->size;
            x=x->c[1];
        }
    }
    return x->s;
}
 


node* newNode(int s,node *f)
{
    node *p=&a[++e];
    p->c[0]=p->c[1]=nullNode;
    p->f=f;
    p->s=s;
    p->size=1;
    
    mp[s]=p;
    return p;
}
 
void init()
{
    nullNode=new node();
    nullNode->c[0]=nullNode->c[1]=nullNode->f=nullNode;
    nullNode->size=0;
    
    root=newNode(0,nullNode);
    root->c[1]=newNode(0,root);
    pushUp(root);



node *build(int L,int R,node *f)
{
    int M=(L+R)>>1;
    node *p=newNode(d[M],f);
    if(L<M) p->c[0]=build(L,M-1,p);
    if(M<R) p->c[1]=build(M+1,R,p);
    pushUp(p);
    return p;
}


void del(node* p)
{
    splay(p,nullNode);
    int L=p->c[0]->size;
    select(L,nullNode);
    select(L+2,root);
    root->c[1]->c[0]=nullNode;
    splay(root->c[1],nullNode);
}


void insert(int pos,node *p)
{
    select(pos,nullNode);
    select(pos+1,root);
    root->c[1]->c[0]=p;
    p->f=root->c[1];
    splay(p,nullNode);
}


void top(int s)
{
    node *p=mp[s];
    del(p);
    p=newNode(s,nullNode);
    insert(1,p);
}


void bottom(int s)
{
    node *p=mp[s];
    del(p);
    p=newNode(s,nullNode);
    insert(n,p);
}




void insert(int S,int T)
{
    if(T==0) return;
    node *p=mp[S];
    splay(p,nullNode);
    int size=p->c[0]->size;
    del(p);
    p=newNode(S,nullNode);
    if(T==-1) insert(size-1,p);
    else insert(size+2-1,p);
}


int ask(int s)
{
    node *p=mp[s];
    splay(p,nullNode);
    return p->c[0]->size-1;
}


int query(int s)
{
    return select1(s+1);
}




void go()
{
    char op[20];
    int S,T;
    while(m--)
    {
        RD(op); RD(S);
        if(op[0]=='T') top(S);
        else if(op[0]=='B') bottom(S);
        else if(op[0]=='I') RD(T),insert(S,T);
        else if(op[0]=='A') PR(ask(S));
        else PR(query(S));
    }
}






int main()
{
    RD(n,m);
    int i;
    FOR1(i,n) RD(d[i]);
    init(); 
    node *p=build(1,n,root->c[1]);
    root->c[1]->c[0]=p;
    splay(p,nullNode);
    go();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值