zoukankan      html  css  js  c++  java
  • 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('
    ')
    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
  • 相关阅读:
    很长的下拉框菜单
    Pure CSS Buttons – Good Button Style and No Images
    ssh 配置
    php大量session存储到内存中,散列及过期回收
    array_append_distinct, array_erase函数
    关于C# 中的Attribute 特性(转载)
    Jquery如何操作Table的某一个td
    ASP.NET应用程序生命周期趣谈(四) HttpHandler和页面生命周期
    ASP.NET应用程序生命周期趣谈(五) IIS7瞎说
    ASP.NET应用程序生命周期趣谈(三)
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10680271.html
Copyright © 2011-2022 走看看