数据较大,需要先把每个top不会操作到的段缩成一个点,记录其开始和结束的位置,和top能操作到的点一起建立一颗伸展树模拟
然后就是普通的队列模拟操作
/* 不会被top操作到的区间就缩点 通过splay tree模拟出序列,初始序列的第i个缩点对应的树结点也是i 操作top a:找到结点a,将其移到最左边 query a:结点a的左边有多少人 rank a:第a个结点是第几个结点 */ #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define maxn 100005 #define L ch[r][0] #define R ch[r][1] using namespace std; int pre[maxn],ch[maxn][2],size[maxn],num[maxn],root,tot; int s[maxn],e[maxn],cnt; void debug(); inline void newnode(int &r,int fa,int k){ r=k; ch[r][0]=ch[r][1]=0; pre[r]=fa; size[r]=num[r]=e[k]-s[k]+1; } inline void pushup(int r){ size[r]=size[L]+size[R]+num[r]; } void build(int &x,int l,int r,int fa){ if(l>r) return; int mid=l+r>>1; newnode(x,fa,mid); build(ch[x][0],l,mid-1,x); build(ch[x][1],mid+1,r,x); pushup(x); } void init(int n){ root=tot=0; size[root]=pre[root]=ch[root][0]=ch[root][1]=0; build(root,1,n,0); } void Rotate(int x,int kind) { int y = pre[x]; //pushdown(y); //pushdown(x);//先把y的标记下传,在把x的标记下传 ch[y][!kind] = ch[x][kind]; pre[ch[x][kind]] = y; if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y] = x; pre[x] = pre[y]; ch[x][kind] = y; pre[y] = x; pushup(y); } //Splay调整,将r结点调整到goal下面 void splay(int r,int goal) { //push_down(r); while(pre[r] != goal) { if(pre[pre[r]] == goal) Rotate(r,ch[pre[r]][0]==r); else { int y = pre[r]; int kind = ch[pre[y]][0]==y; if(ch[y][kind] == r) { Rotate(r,!kind); Rotate(r,kind); } else { Rotate(y,kind); Rotate(r,kind); } } } pushup(r); if(goal == 0) root = r; } int getmin(int r){while(L) r=L;return r;} void del(){ int t=root; if(ch[root][1]){ root=ch[root][1]; splay(getmin(root),0); ch[root][0]=ch[t][0]; if(ch[root][0]) pre[ch[root][0]]=root; } else root=ch[root][0]; pre[root]=0; pushup(root); } int Bin(int x){//二分查找x属于那一段 int l=1,r=cnt; while(l<=r){ int mid=l+r>>1; if(s[mid]<=x && e[mid]>=x) return mid; if(x<s[mid]) r=mid-1; else l=mid+1; } return -1; }void Treavel(int x) { if(x) { Treavel(ch[x][0]); printf("结点:%2d: 左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d num = %2d s = %2d e = %2d ",x,ch[x][0],ch[x][1],pre[x],size[x],num[x],s[x],e[x]); Treavel(ch[x][1]); } } void debug() { printf("root:%d ",root); Treavel(root); } void top(int x){//把结点r移到最左边 int r=Bin(x); splay(r,0); del(); ch[r][0]=0; ch[r][1]=root; pre[root]=r; root=r; pre[root]=0; pushup(root); //debug(); } int query(int x){//结点x左边有多少结点 int r=Bin(x); splay(r,0); return size[ch[root][0]]+x-s[r]+1; } int rankk(int r,int k){//排在第k位的结点 int t=size[ch[r][0]]; if(k<=t) return rankk(ch[r][0],k); else if(k<=t+num[r]) return s[r]+k-t-1; else return rankk(ch[r][1],k-t-num[r]); } char op[maxn][10]; int qnum[maxn],p[maxn]; int main(){ int n,q,T; scanf("%d",&T); for(int tt=1;tt<=T;tt++){ scanf("%d%d",&n,&q); int t=0; for(int i=0;i<q;i++){ scanf("%s%d",op[i],&qnum[i]); if(op[i][0]=='T') p[t++]=qnum[i]; } p[t++]=1; p[t++]=n; sort(p,p+t); t=unique(p,p+t)-p; cnt=0; for(int i=0;i<t;i++){ if(i>0 && p[i]-p[i-1]>1){ cnt++; s[cnt]=p[i-1]+1; e[cnt]=p[i]-1; } cnt++; s[cnt]=p[i];e[cnt]=p[i]; } init(cnt); // debug(); printf("Case %d: ",tt); for(int i=0;i<q;i++){ // debug(); if(op[i][0]=='T') top(qnum[i]); else if(op[i][0]=='Q') printf("%d ",query(qnum[i])); else printf("%d ",rankk(root,qnum[i])); // debug(); } } return 0; }