• bzoj1861 [Zjoi2006]Book 书架 splay


    小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。 当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。 久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:(1)编号为X的书在书柜的什么位置;(2)从上到下第i本书的编号是多少。

    Input

    第一行有两个数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本书的编号。

    Output

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

    Sample 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

    Sample Output

    2
    9
    9
    7
    5
    3
    数据范围
    30%的数据,n,m < = 10000
    100%的数据,n,m < = 80000

    这是一道splay的模板题,算是入门了吧,毕竟不会所有平衡树,过会得开一讲了,
    这道题就是裸的splay,真的比较水,整理的是hzwer大佬的模板,注释在代码上来。
      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cmath>
      5 #include<cstring>
      6 
      7 using namespace std;
      8 
      9 const int NN=80007,inf=1e9+7;
     10 
     11 int n,m,rt,sz;
     12 int c[NN][2],fa[NN],deep[NN];
     13 int a[NN],size[NN],v[NN],pos[NN];
     14 
     15 void update(int k)//仅仅用来得到k的大小 
     16 {
     17     size[k]=size[c[k][0]]+size[c[k][1]]+1;
     18 }
     19 void rotate(int x,int &k)//一次旋转 
     20 {
     21     int y=fa[x],z=fa[y],l,r;
     22     if (c[y][0]==x) l=0;
     23     else l=1;
     24     r=l^1;
     25     if (y==k) k=x;
     26     else if (c[z][0]==y) c[z][0]=x;
     27          else c[z][1]=x;
     28     fa[x]=z,fa[y]=x,fa[c[x][r]]=y;
     29     c[y][l]=c[x][r],c[x][r]=y;
     30     update(y),update(x);//普通的一次操作。 
     31 }
     32 void splay(int x,int &k)
     33 {
     34     while(x!=k)
     35     {
     36         int y=fa[x],z=fa[y];
     37         if (y!=k)
     38         {
     39             if (c[y][0]==x^c[z][0]==y)//这个是判断zig还是zag,来决定谁先交换。 
     40                 rotate(x,k);
     41             else rotate(y,k);
     42         }
     43         rotate(x,k);
     44     }
     45 }
     46 void build(int l,int r,int f)//l,r是表示区间,f表示根 
     47 {
     48     if (l>r) return;
     49     int now=l,last=f;
     50     if (l==r)
     51     {
     52         v[now]=a[l],size[now]=1,fa[now]=last;
     53         if (l<f) c[last][0]=now;//右边左边的问题 
     54         else c[last][1]=now;
     55         return;
     56     }
     57     int mid=(l+r)>>1;
     58     now=mid;
     59     build(l,mid-1,mid);build(mid+1,r,mid);
     60     v[now]=a[mid],fa[now]=last;
     61     update(now);
     62     if (mid<f) c[last][0]=now;
     63     else c[last][1]=now;
     64 }
     65 int find(int k,int rank)//以k为根的树中找rank 
     66 {
     67     int l=c[k][0],r=c[k][1];
     68     if (size[l]+1==rank) return k;
     69     else if (size[l]>=rank) return find(l,rank);
     70          else return find(r,rank-size[l]-1);
     71 }
     72 void del(int k)
     73 {
     74     int x,y,z;
     75     x=find(rt,k-1),y=find(rt,k+1);
     76     splay(x,rt),splay(y,c[x][1]);
     77     z=c[y][0],c[y][0]=0,fa[z]=size[z]=0;//把前驱转到根,把后驱转到根右子树,然后根右子树左儿子就是要删除的值。 
     78     update(y),update(x);
     79 }
     80 void move(int k,int val)//就是将编号为k的放到val值的地方。 
     81 {
     82     int x,y,z=pos[k],rank;
     83     splay(z,rt);
     84     rank=size[c[z][0]]+1;
     85     del(rank);
     86     if (val==inf) x=find(rt,n),y=find(rt,n+1);
     87     else if (val==-inf) x=find(rt,1),y=find(rt,2);
     88          else x=find(rt,rank+val-1),y=find(rt,rank+val);
     89     splay(x,rt),splay(y,c[x][1]);
     90     size[z]=1,fa[z]=y,c[y][0]=z;
     91     update(y),update(x);
     92 }
     93 int main()
     94 {
     95     scanf("%d%d",&n,&m);
     96     for (int i=2;i<=n+1;i++)//特别把1空出来,防止越界。 
     97     {
     98         scanf("%d",&a[i]);
     99         pos[a[i]]=i;//反向映射。 
    100     }
    101     build(1,n+2,0);
    102     rt=(3+n)>>1;
    103     char ch[10];int S,T;
    104     for (int i=1;i<=m;i++)
    105     {
    106         scanf("%s%d",ch,&S);
    107         switch(ch[0])
    108         {
    109             case'T':move(S,-inf);break; 
    110             case'B':move(S,inf);break;
    111             case'I':scanf("%d",&T);move(S,T);break;
    112             case'A':splay(pos[S],rt);printf("%d
    ",size[c[pos[S]][0]]-1);break;
    113             case'Q':printf("%d
    ",v[find(rt,S+1)]);break;
    114         }
    115     }
    116 }
  • 相关阅读:
    Java基础101 给c:forEach的select下拉框中的值,设置默认值(后台传值,前台默认选中)
    Java进阶知识27 SSH整合(Struts2、Spring、Hibernate)
    错误/异常:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/classes/beans_common.xml]...的解决方法
    Java进阶知识26 Spring与Hibernate整合到一起
    Java进阶知识25 Spring的事务管理(事务回滚)
    spring各个版本源码
    sql之left join、right join、inner join的区别
    git命令之git stash 暂存临时代码
    apollo配置相关
    idea快捷键
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/7475235.html
Copyright © 2020-2023  润新知