首页 > 代码库 > BZOJ 1861 ZJOI 2006 Book 书架 Splay

BZOJ 1861 ZJOI 2006 Book 书架 Splay

题目大意:有一个书架,现在需要经常改变这些书的位置,每次询问一本书在哪或者第几本书是什么。


思路:赤裸裸的Splay,只是有些小事需要注意。因为他有的时候问你一个书在哪,这个事情不能只在Splay中就能解决,我们需要辅助他解决。注意到操作中没有加入书的操作,也就是书的总数并不会变化,而且Splay的过程中只是指针的变动,所以不会有点发生变化,所以在一开始建树的时候维护一个数组,表示这本书在Splay中的节点,这样我们就能快速的找到任意一本书的节点。询问一本书的排名的时候,我们需要先找到这个节点,然后不断向根靠近,在这过程中进行统计有多少个节点在这个节点前面就行了。自己YY出来的思路,不过感觉这种操作不是Splay原生的操作,应该还有更优雅的解决方法吧。。具体见代码。


CODE:


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 80010
using namespace std;

struct SplayTree{
    int val,size;
    SplayTree *son[2],*father;
    
    bool Check() {
        return father->son[1] == this;
    }
    void Combine(SplayTree *a,bool dir) {
        a->father = this;
        son[dir] = a;
    }
}*pos[MAX],none,*nil = &none,*root;

int points,asks;
int src[MAX];

char s[10];

SplayTree *NewNode(int _)
{
    SplayTree *re = new SplayTree();
    re->son[0] = re->son[1] = nil;
    re->val = _;
    re->size = 1;
    return re;
}

inline void PushUp(SplayTree *a)
{
    a->size = a->son[0]->size + a->son[1]->size + 1;
}

SplayTree *BuildTree(int l,int r)
{
    if(l > r)   return nil;
    int mid = (l + r) >> 1;
    SplayTree *re = NewNode(src[mid]);
    pos[src[mid]] = re;
    re->Combine(BuildTree(l,mid - 1),false);
    re->Combine(BuildTree(mid + 1,r),true);
    PushUp(re);
    return re;
}

inline void Rotate(SplayTree *&a,bool dir)
{
    SplayTree *f = a->father;
    f->son[!dir] = a->son[dir];
    f->son[!dir]->father = f;
    a->son[dir] = f;
    f->father->son[f->Check()] = a;
    a->father = f->father;
    f->father = a;
    PushUp(f);
    if(root == f)	root = a;
}

inline void Splay(SplayTree *a,SplayTree *aim)
{
    while(a->father != aim) {
        if(a->father->father == aim)
            Rotate(a,!a->Check());
        else if(!a->father->Check()) {
            if(!a->Check())
                Rotate(a->father,true),Rotate(a,true);
            else	Rotate(a,false),Rotate(a,true);
        }
        else {
            if(a->Check())
                Rotate(a->father,false),Rotate(a,false);
            else	Rotate(a,true),Rotate(a,false);
        }
    }
    PushUp(a);
}

SplayTree *Find_(SplayTree *a,int k)
{
    if(k <= a->son[0]->size)	return Find_(a->son[0],k);
    k -= a->son[0]->size;
    if(k == 1)	return a;
    return Find_(a->son[1],k - 1);
}

int Find(SplayTree *a,int k)
{
    if(k <= a->son[0]->size)	return Find(a->son[0],k);
    k -= a->son[0]->size;
    if(k == 1)	return a->val;
    return Find(a->son[1],k - 1);
}

inline int Rank(SplayTree *a)
{
    int re = a->son[0]->size;
    while(a != root) {
        if(a->Check())
            re += a->father->son[0]->size + 1;
        a = a->father;
    }
    return re + 1;
}

inline void Insert(int rank,int aim)
{
    Splay(Find_(root,rank - 1),nil);
    Splay(Find_(root,rank + 1),root);
    SplayTree *temp = root->son[1]->son[0];
    root->son[1]->son[0] = nil;
    PushUp(root->son[1]);
    PushUp(root);
    Splay(Find_(root,aim - 1),nil);
    Splay(Find_(root,aim),root);
    root->son[1]->Combine(temp,false);
    PushUp(root->son[1]);
    PushUp(root);
}

int main()
{
    cin >> points >> asks;
    for(int i = 1; i <= points; ++i)
        scanf("%d",&src[i]);
    root = BuildTree(0,points + 1);
    root->father = nil;
    nil->son[1] = root;
    nil->son[0] = nil;
    for(int x,y,i = 1; i <= asks; ++i) {
        scanf("%s",s);
        if(s[0] == 'Q') {
            scanf("%d",&x);
            printf("%d\n",Find(root,x + 1));
        }
        if(s[0] == 'A') {
            scanf("%d",&x);
            printf("%d\n",Rank(pos[x]) - 2);
        }
        if(s[0] == 'T') {
            scanf("%d",&x);
            int rank = Rank(pos[x]);
            Insert(rank,2);
        }
        if(s[0] == 'B') {
            scanf("%d",&x);
            int rank = Rank(pos[x]);
            Insert(rank,points + 1);
        }
        if(s[0] == 'I') {
            scanf("%d%d",&x,&y);
            if(!y)	continue;
            int rank = Rank(pos[x]),temp;
            if(y == 1)	temp = rank + 1;
            else	temp = rank - 1;
            Insert(rank,temp);
        }
    }
    return 0;
}


BZOJ 1861 ZJOI 2006 Book 书架 Splay