• 洛谷 P2596 [ZJOI2006]书架 (splay)


    题目描述

    小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,权值为x[i]的第i个插入,splay维护的是顺序

    显然插入到第x+1本或者第x-1本书的操作是将x的权值与他的后继或者前驱交换

    插到底或者顶就是将x的左子树换到他的后继的左子树或者将x的右子树换到他的前驱的右子树

    然后就可以用splay瞎搞了

    代码如下:

    #include<set>
    #include<map>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define lson ch[x][0]
    #define rson ch[x][1]
    #define mod 1000000007
    using namespace std;
    
    int n,m;
    int pos[100010],sz[100010],key[100010],f[100010],ch[100010][3],cnt,rt;
    
    int push_up(int x)
    {
        sz[x]=sz[lson]+sz[rson]+1;
        pos[key[lson]]=lson;
        pos[key[rson]]=rson;
    }
    
    int rotate(int x)
    {
        int y=f[x],z=f[y],kd=(ch[y][1]==x),xs=ch[x][!kd];
        if(z) ch[z][ch[z][1]==y]=x;
        ch[x][!kd]=y;
        ch[y][kd]=xs;
        if(xs) f[xs]=y;
        f[x]=z;
        f[y]=x;
        push_up(y);
    }
    
    int splay(int goal,int x)
    {
        int y,z;
        while(f[x]!=goal)
        {
            y=f[x],z=f[y];
            if(z!=goal)
            {
                (ch[y][0]==x)^(ch[z][0]==y)?rotate(x):rotate(y);
            }
            rotate(x);
        }
        push_up(x);
        if(!goal) rt=x;
    }
    
    int insert(int x)
    {
        key[++cnt]=x;
        sz[cnt]=1;
        pos[x]=cnt;
        ch[cnt][0]=ch[cnt][1]=0;
        if(cnt>1)
        {
            ch[cnt-1][1]=cnt;
            f[cnt]=cnt-1;
            splay(0,cnt);
        }
    }
    
    int find(int x,int tot)
    {
        if(sz[lson]+1==tot)
        {
            return x;
        }
        else
        {
            if(sz[lson]+1<tot)
            {
                return find(rson,tot-sz[lson]-1);
            }
            else return find(lson,tot);
        }
    }
    
    int get(int x,int kd)
    {
        int y=ch[x][kd];
        while(ch[y][!kd])
        {
            y=ch[y][!kd];
        }
        return y;
    }
    
    int make_top(int x)
    {
        x=pos[x];
        splay(0,x);
        if(!lson) return 0;
        if(!rson) swap(lson,rson);
        else
        {
            int y=get(x,1);
            f[lson]=y;
            ch[y][0]=lson;
            lson=0;
            splay(0,ch[y][0]);
        }
    }
    
    int make_buttom(int x)
    {
        x=pos[x];
        splay(0,x);
        if(!rson) return 0;
        if(!lson) swap(lson,rson);
        else
        {
            int y=get(x,0);
            f[rson]=y;
            ch[y][1]=rson;
            rson=0;
            splay(0,ch[y][1]);
        }
    }
    
    int change(int x,int kd)
    {
        if(!kd) return 0;
        splay(0,pos[x]);
        int y=(kd==1)?get(pos[x],1):get(pos[x],0);
        int tmp1=key[y],tmp2=pos[x];
        swap(pos[x],pos[tmp1]);
        swap(key[tmp2],key[y]);
    }
    
    void print(int x)
    {
        splay(0,x);
        printf("%d
    ",sz[lson]);
    }
    
    void dayin(int x)
    {
        printf("%d %d %d
    ",x,lson,rson);
        if(lson) dayin(lson);
        if(rson) dayin(rson);
    }
    
    int main()
    {
        ch[0][0]=ch[0][1]=sz[0]=f[0]=key[0]=pos[0]=0;
        scanf("%d%d",&n,&m);
        int tmp;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&tmp);
            insert(tmp);
        }
        string op;
        while(m--)
        {
            cin>>op;
            int tmp1,tmp2;
            if(op[0]=='T')
            {
                scanf("%d",&tmp1);
                make_top(tmp1);
            }
            if(op[0]=='B')
            {
                scanf("%d",&tmp2);
                make_buttom(tmp2);
            }
            if(op[0]=='I')
            {
                scanf("%d%d",&tmp1,&tmp2);
                change(tmp1,tmp2);
            }
            if(op[0]=='A')
            {
                scanf("%d",&tmp1);
                print(pos[tmp1]);
            }
            if(op[0]=='Q')
            {
                scanf("%d",&tmp1);
                printf("%d
    ",key[find(rt,tmp1)]);
            }
        }
    }
  • 相关阅读:
    孙权劝学
    劝学
    为学
    字符串的全排列
    剑指offer面试题3二维数组中的查找
    如何正确安装软件
    写给自己的话
    Linux常用命令
    第三届华为杯
    D^3ctf两道 pwn
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/9588119.html
Copyright © 2020-2023  润新知