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;
}
时间: 2024-10-17 08:47:21

BZOJ 1861 ZJOI 2006 Book 书架 Splay的相关文章

BZOJ 1003 ZJOI 2006 物流运输 动态规划+SPFA

题目大意:有一些码头由若干条边组成,有些时候有一些码头需要维修,这个期间不能使用这个码头.跟换航线的话会有一定的花费,求规定天数内的最小花费. 思路:最短路方面用SPFA就行,关键是动态规划.这个动规我想了很久,结果到最后发现自己想复杂了.我一开始想的是用SPFA处理出每一个不同的段,然后动规.这样做不仅分段不好分,动规也不好写.之后才发现,一共天数才100,枚举起点和终点才10000,套一个SPFA的O(kn)也不到1qw... CODE: #include <queue> #include

[题解]bzoj 1861 Book 书架 - Splay

1861: [Zjoi2006]Book 书架 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1396  Solved: 803[Submit][Status][Discuss] Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位

BZOJ 1861: [Zjoi2006]Book 书架 (splay)

1861: [Zjoi2006]Book 书架 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1453  Solved: 822[Submit][Status][Discuss] Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位

BZOJ 1861: [Zjoi2006]Book 书架 splay

1861: [Zjoi2006]Book 书架 Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置.不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1.X或X+1本

BZOJ 1861 [Zjoi2006]Book 书架 ——Splay

[题目分析] 模板题目. 首尾两个虚拟结点,十分方便操作. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream> #include

【BZOJ 1861】Book 书架

Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置.不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1.X或X+1本书. 当然也有特殊情况,比如在看书的时候突然电话

BZOJ 1861 书架

(╯-_-)╯╧╧ 此处为错误代码. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 300050 #define inf 2147483646 using namespace std; int n,m,a[maxn],x,y; int tree[maxn][3],size[maxn],fath[maxn],val[maxn],roo

BZOJ 1862/1056 ZJOI 2006 GameZ游戏排名系统/ HAOI 2008 排名系统 Treap (双倍经验)

题目大意:维护一种游戏排名系统,为他们的得分排序,若得分一样,则时间早的优先.有的时候要查询一个人是第几名,或者一段名次都是谁. 思路:拿到题一看就知道是暴力Treap乱搞,但是一查不知道看到了谁的文章,说Treap会T,我就战战兢兢的写了Splay,结果T了,拿到数据发现被一个点卡了100s.于是怒写Treap,1.2s怒切. PS:千万不要相信谣言.. CODE: #include <cstdio> #include <cctype> #include <cstring&

解题:ZJOI 2006 书架

题面 学习了如何在维护序列的平衡树上查找某个数:按初始的顺序定个权值,然后每次找那个权值的DFS序即可.具体实现就是不停往上跳,然后是父亲的右儿子就加上父亲的左儿子,剩下的就是继续熟悉无旋树堆 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=100005; 6 int num[N],val[N],siz[N],anc[N],