bzoj1861

bzoj1861[ZJOI2006]书架

题目描述

小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。

小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。

当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。

久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:(1)编号为X的书在书柜的什么位置;(2)从上到下第i本书的编号是多少。

输入输出格式

输入格式:

 

第一行有两个数n,m,分别表示书的个数以及命令的条数;第二行为n个正整数:第i个数表示初始时从上至下第i个位置放置的书的编号;第三行到m+2行,每行一条命令。命令有5种形式:

1. Top S——表示把编号为S的书放在最上面。

2. Bottom S——表示把编号为S的书放在最下面。

3. Insert S T——T∈{-1,0,1},若编号为S的书上面有X本书,则这条命令表示把这本书放回去后它的上面有X+T本书;

4. Ask S——询问编号为S的书的上面目前有多少本书。

5. Query S——询问从上面数起的第S本书的编号。

 

输出格式:

 

对于每一条Ask或Query语句你应该输出一行,一个数,代表询问的答案。

 

输入输出样例

输入样例#1: 复制
10 10
1 3 2 7 5 8 10 4 9 6
Query 3
Top 5
Ask 6
Bottom 3
Ask 3
Top 6
Insert 4 -1
Query 5
Query 2
Ask 2
输出样例#1: 复制
2
9
9
7
5
3

说明

100%的数据,n,m <= 80000

 

sol:虽然是模板题,但由于本人是幼儿园水平,十分无奈的看题解了(确实有很多细节写不出来)

最重要的两个变量:

int Pos[N] 标号为i的书在树上的位置

int Id[N] 树上位置为i的节点在书架上的标号[1,n]

然后我还是不会把一个节点移到任意一个位置(多多指教)

对于置顶:把当前节点Splay为根后,把左子树串到后继节点的左子树即可,置底同理

对于移动,只要交换两个点的Pos和Id就可以了,多多Splay防T

巨丑无比的代码

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');    return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=80005,inf=0x3f3f3f3f;
int n,Q;
namespace Pht
{
    int Points=0,Root;
    int Child[N][2],Parent[N];
    int Pos[N];//标号为i的书在树上的位置
    int Id[N];//树上位置为i的节点在书架上的标号[0,n+1]
    int Size[N];
    
    inline void Init();
    inline int Check(int x);
    inline void PushUp(int x);
    inline void Rotate(int x);
    inline void Splay(int At,int To);
    inline void Insert(int Val);
    inline void Above(int Val);
    inline void Below(int Val);
    inline void Move(int Val,int Delta);
    inline int Ask_Rank(int Val);
    inline int Ask_Kth(int K);
    inline void Solve();
    
    inline void Init()
    {
        int i;
        for(i=1;i<=n;i++) Insert(read());
    }
    inline int Check(int x)
    {
        return (Child[Parent[x]][0]==x)?0:1;
    }
    inline void PushUp(int x)
    {
        Size[x]=Size[Child[x][0]]+Size[Child[x][1]]+1;
        Pos[Id[Child[x][0]]]=Child[x][0];
        Pos[Id[Child[x][1]]]=Child[x][1];
    }
    inline void Rotate(int x)
    {
        int y,z,oo;
        y=Parent[x];
        z=Parent[y];
        oo=Check(x);
        Child[y][oo]=Child[x][oo^1]; Parent[Child[x][oo^1]]=y;
        Child[z][Check(y)]=x; Parent[x]=z;
        Child[x][oo^1]=y; Parent[y]=x;
        PushUp(x);
        PushUp(y);
    }
    inline void Splay(int At,int To)
    {
        while(Parent[At]!=To)
        {
            int Father=Parent[At];
            if(Parent[Father]==To)
            {
                Rotate(At);
            }
            else if(Check(At)==Check(Father))
            {
                Rotate(Father); Rotate(At);
            }
            else
            {
                Rotate(At); Rotate(At);
            }
        }
        Pos[Id[At]]=At;
        if(To==0) Root=At;
    }
    inline void Insert(int Val)
    {
        int Now=Root,Par=0;
        while(Now)
        {
            Par=Now;
            Now=Child[Now][1];
        }
        Now=++Points;
        if(Par) Child[Par][1]=Now;
        Child[Now][0]=Child[Now][1]=0;
        Parent[Now]=Par;
        Size[Now]=1;
        Pos[Val]=Now;
        Id[Now]=Val;
        Splay(Now,0);
    }
//    inline void Remove(int Val)
//    {
//        int P1=Ask_Kth(Val-1),P2=Ask_Kth(Val+1);
//        Splay(P1,0);
//        Splay(P2,P1);
//        int Pos=Child[P2][0];
//        Child[P2][0]=0;
//        Size[Pos]=Parent[Pos]=Id[Pos]=0;
//        Splay(P2,0);
//    }
    inline void Above(int Val)
    {
        Splay(Pos[Val],0);
        if(!Child[Root][0]) return; //最上面了
        if(!Child[Root][1]) //下面没了直接把左儿子移到右儿子就可以了
        {
            Child[Root][1]=Child[Root][0];
            Child[Root][0]=0;
        }
        else
        {
            int Now=Child[Root][1];
            while(Child[Now][0]) Now=Child[Now][0];
            Parent[Child[Root][0]]=Now; //把左儿子串到后继节点上,中序遍历仍然正确 
            Child[Now][0]=Child[Root][0];
            Child[Root][0]=0;
            Splay(Child[Now][0],0); //从新串的节点更新一遍 
        }
    }
    inline void Below(int Val)
    {
        Splay(Pos[Val],0);
        if(!Child[Root][1]) return;
        if(!Child[Root][0])
        {
            Child[Root][0]=Child[Root][1]; Child[Root][1]=0;
        }
        else
        {
            int Now=Child[Root][0];
            while(Child[Now][1]) Now=Child[Now][1]; //前驱节点 
            Parent[Child[Root][1]]=Now;
            Child[Now][1]=Child[Root][1];
            Child[Root][1]=0;
            Splay(Child[Now][1],0);
        }
    }
    inline void Move(int Val,int Delta)
    {
        Splay(Pos[Val],0);
        if(!Delta) return;
        else if(Delta==1)
        {
            int Upper=Child[Root][1],tmp=Pos[Val];
            while(Child[Upper][0]) Upper=Child[Upper][0];
            swap(Pos[Val],Pos[Id[Upper]]);
            swap(Id[tmp],Id[Upper]);
        }
        else
        {
            int Lower=Child[Root][0],tmp=Pos[Val];
            while(Child[Lower][1]) Lower=Child[Lower][1];
            swap(Pos[Val],Pos[Id[Lower]]);
            swap(Id[tmp],Id[Lower]);
        }
    }
    inline int Ask_Rank(int Val)
    {
        Splay(Pos[Val],0);
        return Size[Child[Root][0]];
    }
    inline int Ask_Kth(int K)
    {
        int Now=Root;
        for(;;)
        {
            if(Size[Child[Now][0]]>=K)
            {
                Now=Child[Now][0];
            }
            else if(Size[Child[Now][0]]+1==K)
            {
                return Now;
            }
            else
            {
                K-=(Size[Child[Now][0]]+1);
                Now=Child[Now][1];
            }
        }
    }
    inline void Solve()
    {
        int x;
        char S[10];
        Init();
        while(Q--)
        {
            scanf("%s",S+1);
            switch (S[1])
            {
                case 'T':
                    Above(read());
                    break;
                case 'B':
                    Below(read());
                    break;
                case 'I':
                    R(x);
                    Move(x,read());
                    break;
                case 'A':
                    Wl(Ask_Rank(read()));
                    break;
                case 'Q':
                    Wl(Id[Ask_Kth(read())]);
                    break;
            }
        }
    }
}
int main()
{
    int i;
    R(n); R(Q);
    Pht::Solve();
    return 0;
}
/*
input
10 10
1 3 2 7 5 8 10 4 9 6
Query 3
Top 5
Ask 6
Bottom 3
Ask 3
Top 6
Insert 4 -1
Query 5
Query 2
Ask 2
output
2
9
9
7
5
3
*/
View Code

 

posted @ 2019-04-10 21:46  yccdu  阅读(188)  评论(0编辑  收藏  举报