1861: [Zjoi2006]Book 书架
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 1271 Solved: 731
[ 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
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
9
9
7
5
3
HINT
数据范围
Source
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 8E4 + 80;
int n,m,Root,ch[maxn][2],fa[maxn],siz[maxn],a[maxn];
char com[20];
void maintain(int x)
{
siz[x] = 1;
for (int i = 0; i < 2; i++)
siz[x] += siz[ch[x][i]];
}
void rotate(int x)
{
int y = fa[x],d = ch[y][0] == x?0:1;
ch[y][d] = ch[x][d^1];
fa[ch[y][d]] = y; ch[x][d^1] = y;
fa[x] = fa[y]; fa[y] = x;
int z = fa[x]; ch[z][ch[z][1] == y] = x;
maintain(y); maintain(x);
}
void splay(int u,int v)
{
int g = fa[v];
for (int y = fa[u]; y != g; rotate(u),y = fa[u])
if (fa[y] != g)
rotate((ch[y][0] == u)^(ch[fa[y]][0] == y)?y:u);
if (v == Root) Root = u;
}
int Rank(int x)
{
splay(x,Root);
return siz[ch[x][0]] + 1;
}
int Find(int x,int k)
{
int Left = siz[ch[x][0]] + 1;
if (Left == k) return x;
if (Left < k) return Find(ch[x][1],k - Left);
return Find(ch[x][0],k);
}
void Del(int x)
{
int rank = Rank(x);
splay(Find(Root,rank - 1),Root);
splay(x,ch[Root][1]);
ch[Root][1] = ch[x][1];
fa[ch[x][1]] = Root;
fa[x] = ch[x][1] = 0;
maintain(Root);
}
void Build(int l,int r,int &x)
{
if (l > r) return;
if (l == r) {x = a[l]; maintain(x); return;}
int mid = (l + r) >> 1;
x = a[mid];
Build(l,mid - 1,ch[x][0]);
fa[ch[x][0]] = x;
Build(mid + 1,r,ch[x][1]);
fa[ch[x][1]] = x;
maintain(x);
}
int getcom()
{
scanf("%s",com);
if (com[0] == 'T') return 1;
if (com[0] == 'B') return 2;
if (com[0] == 'I') return 3;
if (com[0] == 'A') return 4;
return 5;
}
void Swap(int x,int y,int d)
{
for (int i = 0; i < 2; i++) {
fa[ch[x][i]] = y;
fa[ch[y][i]] = x;
swap(ch[x][i],ch[y][i]);
}
fa[y] = 0; fa[x] = y;
Root = y; ch[y][d] = x;
maintain(x); maintain(y);
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> n >> m; a[0] = n + 1;
for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
Build(0,n,Root);
while (m--) {
int typ = getcom();
if (typ == 1) {
int s; scanf("%d",&s); Del(s);
splay(Find(Root,2),Root);
int t = ch[Root][0];
fa[s] = t; ch[t][1] = s;
maintain(s); maintain(t); maintain(Root);
}
else if (typ == 2) {
int s; scanf("%d",&s); Del(s);
splay(Find(Root,n),Root);
fa[s] = Root; ch[Root][1] = s;
maintain(s); maintain(ch[Root][1]); maintain(Root);
}
else if (typ == 3) {
int s,t; scanf("%d%d",&s,&t);
if (!t) continue;
int rank = Rank(s);
if (rank == 2 && t == -1) continue;
if (rank == n + 1 && t == 1) continue;
if (t == -1) {
splay(Find(Root,rank - 1),Root);
splay(s,ch[Root][1]); Swap(Root,s,1);
}
else {
splay(Find(Root,rank + 1),Root);
splay(s,ch[Root][0]); Swap(Root,s,0);
}
}
else if (typ == 4) {
int s; scanf("%d",&s);
printf("%d\n",Rank(s) - 2);
splay(s,Root);
}
else {
int s; scanf("%d",&s);
int Ans = Find(Root,s + 1);
printf("%d\n",Ans);
splay(Ans,Root);
}
}
return 0;
}