题目描述
小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
调试一万年系列又一题
这题主要是要给每本书另外定一个优先级作为v,用数组a来记下它们的优先级,再在树里面另开一个值记编号就好了,记住,它们的优先级并不等于它们现在所在的位置
所以插入的应该是a[x]而不是x
top操作就是把这本书的优先级变为最小再插入回去,bottom操作就是把这本书的优先级变为最大再插入回去,insert就是把两本书的优先级交换再插回去
query x 对应 kth(x),ask x 对应 find(a[x])
以上
下面是代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define ll int
using namespace std;
const int N=80010;
ll n,a[N],now,m,maxn,minn;
struct node
{
node* ch[2];ll s,r,v,w;
node(int v):v(v){ch[0]=ch[1]=NULL;s=1;r=rand();w=now;}
void maintain()
{
s=1;
if(ch[0] != NULL) s+=ch[0]->s;
if(ch[1] != NULL) s+=ch[1]->s;
}
int cmp(int x){if(v == x) return -1;return v < x;}
};
node* rt;
void rotate(node* &o,int d)
{
node* k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
o->maintain();k->maintain();o=k;
}
void ins(node* &o,int x)
{
if(o == NULL) {o=new node(x);return ;}
int d=(o->v < x);ins(o->ch[d],x);
if(o->ch[d]->r > o->r) rotate(o,d^1);
o->maintain();
}
void del(node* &o,int x)
{
if(o == NULL) return ;
int d=o->cmp(x);
if(d == -1)
{
if(o->ch[0] != NULL && o->ch[1] != NULL)
{
int d2=(o->ch[0]->r > o->ch[1]->r);
rotate(o,d2);del(o->ch[d2],x);
}
else {if(o->ch[0] == NULL) o=o->ch[1];else o=o->ch[0];}
}
else del(o->ch[d],x);
if(o != NULL) o->maintain();
}
void kth(node* &o,int k,int &ans)
{
if(o == NULL || k <=0 || k > o->s) return ;
int ss=(o->ch[0] == NULL ? 0 : o->ch[0]->s);
if(k == ss+1) {ans=o->w;return ;}
if(k <= ss) kth(o->ch[0],k,ans);
else kth(o->ch[1],k-ss-1,ans);
}
int rank(node* &o,int x)
{
if(o == NULL) return 0;
int d=o->cmp(x),ss=(o->ch[0] == NULL ? 0 : o->ch[0]->s);
if(d == -1) return ss+1;
if(d == 0) return rank(o->ch[0],x);
return rank(o->ch[1],x)+ss+1;
}
int read(){
int out=0,f=1;char c=getchar();
while(c < '0' || c > '9')
{if(c == '-') f=-1;c=getchar();}
while(c >= '0' && c <= '9' )
{out=(out<<1)+(out<<3)+c-'0';c=getchar();}
return out*f;
}
void solve()
{
n=read(),m=read(),maxn=n,minn=1;
for(int i=1;i<=n;i++)
{
now=read();
ins(rt,i);
a[now]=i;
}
for(int i=1;i<=m;i++)
{
string cmd;
cin>>cmd;
if(cmd == "Query")
{
int k=read(),ans;kth(rt,k,ans);
printf("%d\n",ans);
}
if(cmd == "Ask")
{
int x=read();
printf("%d\n",rank(rt,a[x])-1);
}
if(cmd == "Top")
{
int x=read();
del(rt,a[x]);
a[x]=--minn;
now=x;ins(rt,a[x]);
}
if(cmd == "Bottom")
{
int x=read();
del(rt,a[x]);
a[x]=++maxn;
now=x;ins(rt,a[x]);
}
if(cmd == "Insert")
{
int x=read(),t=read();
if(t)
{
int rank1=rank(rt,a[x]),rank2=rank1+t;
int x2;kth(rt,rank2,x2);
del(rt,a[x]);del(rt,a[x2]);
a[x]+=a[x2];a[x2]=a[x]-a[x2];a[x]-=a[x2];
now=x;ins(rt,a[x]);now=x2;ins(rt,a[x2]);
}
}
}
}
int main()
{
solve();
return 0;
}