bzoj 1861: [Zjoi2006]Book 书架

1861: [Zjoi2006]Book 书架

Time Limit: 4 Sec   Memory Limit: 64 MB
Submit: 1133   Solved: 657
[ Submit][ Status][ Discuss]

Description

小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

HINT

数据范围


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

 

Source



#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<algorithm>  
#define N 1600000  
using namespace std;  
int n,m;  
int a[N],key[N],size[N],ch[N][3],fa[N],sz,root,pd[N];  
int head=0,tail=0;  
void clear(int x)  
{  
    size[x]=ch[x][1]=ch[x][0]=fa[x]=key[x];   
}  
int get(int x)  
{  
   return ch[fa[x]][1]==x;  
}  
void update(int x)  
{  
    size[x]=size[ch[x][0]]+size[ch[x][1]]+1;  
}  
void rotate(int x)  
{  
    int y=fa[x]; int z=fa[y]; int which=get(x);  
    ch[y][which]=ch[x][which^1]; fa[ch[y][which]]=y;  
    ch[x][which^1]=y; fa[y]=x; fa[x]=z;  
    if (z) ch[z][ch[z][1]==y]=x;  
    update(y); update(x);  
}  
void splay(int x)  
{  
    for (int f;(f=fa[x]);rotate(x))  
     if (fa[f]) rotate(get(x)==get(f)?f:x);  
    root=x;  
}  
int build(int l,int r)  
{  
  if (r<l) return 0;  
  if (l==r)  
   {  
     key[++sz]=a[l];  
     size[sz]=1;  
     ch[sz][1]=ch[sz][0]=0;  
     pd[a[l]]=sz;  
     if (l==1) head=sz;  
     if (l==n)  tail=sz;  
     return sz;  
   }  
  int mid=(l+r)/2;  
  int now=++sz;  
  ch[now][0]=build(l,mid-1);  
  ch[now][1]=build(mid+1,r);  
  fa[ch[now][0]]=fa[ch[now][1]]=now;  
  size[now]=size[ch[now][0]]+size[ch[now][1]]+1; 
  if (mid==1) head=now;
  if (mid==n) tail=now; 
  key[now]=a[mid]; pd[a[mid]]=now;  
  return now;  
}  
int findx(int x)  
{  
    int now=root;  
    while(true)  
    {  
        if (x<=size[ch[now][0]])  
         now=ch[now][0];  
        else  
        {  
            int temp=size[ch[now][0]]+1;  
            if (temp==x) return now;  
            x-=temp;  
            now=ch[now][1];  
        }  
    }  
}  
int next()  
{  
    int now=ch[root][1];  
    while(ch[now][0]) now=ch[now][0];  
    return now;  
}  
int pre()  
{  
    int now=ch[root][0];  
    while(ch[now][1]) now=ch[now][1];  
    return now;  
}  
void del(int x)  
{  
    int k=pd[x]; splay(k);  
    if (!ch[root][0]&&!ch[root][1])   
    {  
        clear(root);   root=0;
        return;  
    }  
    if (!ch[root][0])  
     {  
        int old=root; root=ch[root][1]; fa[root]=0; clear(old); return;  
     }  
    if (!ch[root][1])  
     {  
        int old=root; root=ch[root][0]; fa[root]=0; clear(old); return;  
      }  
    int f=pre(); int old=root;  
    splay(f); ch[root][1]=ch[old][1];  fa[ch[old][1]]=root;  
    clear(old);  
    update(root);  
}
int main()  
{ 
    scanf("%d%d",&n,&m);  
    for (int i=1;i<=n;i++)  
     {  
        scanf("%d",&a[i]);  
     }  
    sz=0;
    root=build(1,n);  
    for (int i=1;i<=m;i++)  
    {  
        //cout<<i<<endl;  cout<<head<<" "<<pd[3]<<endl;
        char s[10]; scanf("%s",s);  
        if (s[0]=='A')   
        {  
         int x; scanf("%d",&x);  
         splay(pd[x]);   
         printf("%d\n",size[ch[root][0]]);  
        }  
        if (s[0]=='Q')  
        {  
          int x; scanf("%d",&x);  
          printf("%d\n",key[findx(x)]);  
        }  
        if (s[0]=='T')  
        {  
            int x; scanf("%d",&x);  
            //if (pd[x]==tail)  tail=findx(n-1);
            del(x);
			int t=findx(1);  
            splay(t);  
            ch[root][0]=++sz; key[sz]=x; pd[x]=sz; size[sz]=1;  
            fa[sz]=root; update(root); head=sz;  splay(sz);
        }  
       if (s[0]=='B')  
        {  
            int x; scanf("%d",&x); 
			if (tail==pd[x]) continue; 
			//if (pd[x]==head) head=findx(2);
            del(x);
			int t=findx(n-1);  
            splay(t);  
            ch[root][1]=++sz; key[sz]=x; pd[x]=sz; size[sz]=1;  
            fa[sz]=root; update(root); tail=sz;  splay(sz); 
        }  
        if (s[0]=='I')  
        {  
            int x,t; scanf("%d%d",&x,&t);  
            if (t==0) continue;  
            splay(pd[x]); int l=pd[x];  
            if (t==1)  
            {  
                int k=next(); //if (k==tail) tail=l;  
                int ky=key[k];
                key[k]=x;
			    pd[x]=k;
                key[l]=ky;
				pd[ky]=l; splay(pd[x]);
            }  
            else  
            {  
                int k=pre(); //if (head==k)  head=l;  
                int ky=key[k];
                key[k]=x;
			    pd[x]=k;
                key[l]=ky;
				pd[ky]=l; splay(pd[x]);
            }  
        }  
    }  
}  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值