• BZOJ1861:[ZJOI2006]书架——题解


    http://www.lydsy.com/JudgeOnline/problem.php?id=1861

    (题面复制于洛谷)

    题目描述

    小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

    ————————————————————————————————

    首先我们splay平衡条件为当前元素插入顺序,插入顺序的关系为lson<root<rson。

    然后多开一个数组pos记录序号所代表的树上的位置。

    剩下的正常splay就行了。

    PS1:读入字符串推荐一个一个字符读入……不然洛谷AC,BZOJ RE。

    PS2:top(x)操作基本上是:

    1.将xsplay。

    2.找到它后面编号的点y,删掉x,将y作为新的假根节点。

    3.将y作为x的右儿子(将x重新添加回来)。

    显然bottom操作和他基本类似。

    又显然ins也类似。

    又显然其他操作很显然。

    #include<cstdio>
    #include<queue>
    #include<cctype>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=80001;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    int fa[N],tr[N][2],key[N],size[N],pos[N];
    int root,sz,n,m;
    inline bool get(int x){
        return tr[fa[x]][1]==x;
    }
    inline void update(int x){
        size[x]=1;
        if(x){  
        if(tr[x][0])size[x]+=size[tr[x][0]];  
        if(tr[x][1])size[x]+=size[tr[x][1]];
        if(tr[x][0])pos[key[tr[x][0]]]=tr[x][0];
        if(tr[x][1])pos[key[tr[x][1]]]=tr[x][1];
        pos[key[x]]=x;
        }
        return;
    }
    inline void rotate(int x){
        int old=fa[x],oldf=fa[old],which=get(x);
        tr[old][which]=tr[x][which^1];fa[tr[old][which]]=old;  
        fa[old]=x;tr[x][which^1]=old;fa[x]=oldf;
        if(oldf)tr[oldf][tr[oldf][1]==old]=x;
        update(old);update(x);
        return;
    }
    inline void splay(int x){
        int f=fa[x];
        while(f){
        if(fa[f])rotate((get(x)==get(f)?f:x));
        rotate(x);f=fa[x];
        }
        root=x;
        return;
    }
    inline void insert(int v){
        sz++;tr[sz][0]=tr[sz][1]=fa[sz]=0;
        key[sz]=v;pos[v]=sz;size[sz]=1;
        if(sz==1)root=sz;
        else{
        tr[sz-1][1]=sz;
        fa[sz]=sz-1;
        update(fa[sz]);splay(sz);
        }
        return;
    }
    inline int find(int x,int v){
        int y=tr[x][0];
        if(size[y]+1==v)return x;
        else if(size[y]>=v)return find(y,v);
        else return find(tr[x][1],v-size[y]-1);
    }
    inline void top(int x){
        x=pos[x];
        splay(x);
        if(!tr[x][0])return;
        if(!tr[x][1])tr[x][1]=tr[x][0],tr[x][0]=0;
        else{
        int y=find(root,size[tr[x][0]]+2);//找到它后面编号的点
        fa[tr[root][0]]=y;
        tr[y][0]=tr[root][0];
        tr[root][0]=0;
        splay(y);
        }
        return;
    }
    inline void bottom(int x){
        x=pos[x];
        splay(x);
        if(!tr[x][1])return;
        if(!tr[x][0])tr[x][0]=tr[x][1],tr[x][1]=0;
        else{
        int y=find(root,size[tr[x][0]]);//找到它后面编号的点
        fa[tr[root][1]]=y;
        tr[y][1]=tr[root][1];
        tr[root][1]=0;
        splay(y);
        }
        return;
    }
    inline void ins(int x,int t){
        if(!t)return;
        splay(pos[x]);
        int y=find(root,t==1?size[tr[pos[x]][0]]+2:size[tr[pos[x]][0]]);
        int x1=key[y],x2=pos[x];
        swap(pos[x],pos[x1]);
        swap(key[x2],key[y]);
        return;
    }
    inline int ask(int x){
        x=pos[x];
        splay(x);
        return size[tr[x][0]];
    }
    inline int query(int x){
        return key[find(root,x)];
    }
    inline char getc(){
        char c=getchar();
        while(c==' '||c=='
    ')c=getchar();
        char ch=c;
        while(c>='a'&&c<='z')c=getchar();
        return ch;
    }
    int main(){
        n=read();
        m=read();
        for(int i=1;i<=n;i++){
        int t=read();
        insert(t);
        }
        for(int i=1;i<=m;i++){
        char ch=getc();
        if(ch=='T')top(read());
        if(ch=='B')bottom(read());
        if(ch=='I'){
            int s=read();
            int t=read();
            ins(s,t);
        }
        if(ch=='A')printf("%d
    ",ask(read()));
        if(ch=='Q')printf("%d
    ",query(read()));
        }
        return 0;
    }
  • 相关阅读:
    数字加密
    大道至简第四章读后感
    输出类中的对象个数
    大道至简第三章读后感
    02java语法基础问题总结
    从命令行接收多个数字并求和输出
    软件工程个人作业03
    第四周学习进度条
    软件工程概论-课后作业2(单元测试)
    第三周学习进度
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8137278.html
Copyright © 2020-2023  润新知