题意:模拟一个队列,能够查询位置k的数是多少 和 数k在哪个位置 操作是把其中一个数提到队头
解法:用splay模拟 把所有的提到头部的操作离线 然后划分区间 每个区间对应树的一个节点
然后提到头部的操作就是将对应线段提根 然后把它的左树送给与它中序的后继节点做左子树
查询位置k的节点很方便就是通过节点所记录的子树节点个数依次走下去就可以
然后查询数k所在的位置的话 要先找到对应的段 然后再splay把对应的节点提根
要注意的是 如果没有top操作 仍然会存在一个真节点和两个伪节点 真节点对应的是[1,n]用unique会跪在这里
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 222222
#define ls ch[rt][0]
#define rs ch[rt][1]
#define rls ch[root][0]
#define rrs ch[root][1]
#define mid ((l+r)>>1)
int st[maxn],ed[maxn],num[maxn],fa[maxn],ch[maxn][2],root,N;
inline void up(int rt){num[rt]=num[ls]+num[rs]+ed[rt]-st[rt]+1;}
inline void rot(int rt){
int f=fa[rt],side=ch[f][1]==rt,&ll=ch[rt][!side];
fa[ll]=f,ch[f][side]=ll;
fa[rt]=fa[f],ch[fa[f]][ch[fa[f]][1]==f]=rt;
fa[f]=rt,ch[rt][!side]=f;
up(f),up(rt);
}
inline void splay(int rt,int aim){
while(fa[rt]!=aim){
int f=fa[rt],ff=fa[f];
if(ff==aim)rot(rt);
if((ch[ff][1]==f)==(ch[f][1]==rt))rot(f),rot(rt);
else rot(rt),rot(rt);
}if(!aim)root=rt;
}
void top(int aim){
splay(aim,0);
int rt=rrs;
while(ls)rt=ls;
splay(rt,aim);
fa[ch[aim][0]]=rt,ls=ch[aim][0],ch[aim][0]=0;
up(rt),up(aim);
}
int query(int rt){splay(rt,0);return num[ls]+1;}
int rak(int tot){
int rt=root;
while(1){
if(num[ls]<tot&&num[ls]+ed[rt]-st[rt]+1>=tot)break;
if(num[ls]>=tot)rt=ls;
else tot-=ed[rt]-st[rt]+1+num[ls],rt=rs;
}
int ans=st[rt]+tot-num[ls]-1;
return ans;
}
int bin(int rt){
int l=1,r=N;
while(l<=r){
if(st[mid]>rt)r=mid-1;
else if(ed[mid]<rt)l=mid+1;
else return mid;
}
return l;
}
int a[maxn],ops[maxn];
char op[maxn],s[111];
int main(){
int t,n,q,cnt,k,_=0;scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&q);
_++;
k=0;
for(int i=0;i<q;i++){
scanf("%s%d",s,&cnt);
ops[i]=cnt,op[i]=s[0];
if(s[0]=='T')a[k++]=cnt;
}
sort(a,a+k);cnt=max((int)(unique(a,a+k)-a),1);
k=1;
if(a[0]>1)st[k]=1,ed[k++]=a[0]-1;
for(int i=0;i<cnt;i++){
st[k]=ed[k]=a[i],k++;
if(i<cnt-1){
if(a[i+1]-a[i]>1)st[k]=a[i]+1,ed[k++]=a[i+1]-1;
}
else if(a[i]<n)st[k]=a[i]+1,ed[k++]=n;
}
st[k]=++n,ed[k++]=n;
memset(ch,0,sizeof ch);
N=k-1;num[0]=0;
for(int i=1;i<=N;i++){
ch[i][0]=i-1,num[i]=num[i-1]+ed[i]-st[i]+1;
fa[i-1]=i;
}
root=N,fa[N]=0;
printf("Case %d:\n",_);
for(int i=0;i<q;i++){
if(op[i]=='T')top(bin(ops[i]));
else if(op[i]=='Q'){
cnt=bin(ops[i]);
printf("%d\n",query(cnt)+ops[i]-st[cnt]);
}
else printf("%d\n",rak(ops[i]));
}
}
return 0;
}