http://acm.hdu.edu.cn/showproblem.php?pid=3436
离线操作,将两个数之间那段数的个数也当做一个节点放在伸展树中,找的时候根据节点的个数往左或往右找就好了
/* 关键是离散化的技巧 其他没什么 */ #include<cstdio> #include<cstdlib> #include<vector> #include<algorithm> using namespace std; const int inf = ~0u>>2; #define L ch[x][0] #define R ch[x][1] #define KT (ch[ ch[rt][1] ][0]) const int maxn = 200010; struct SplayTree { int sz[maxn]; int ch[maxn][2]; int pre[maxn]; int rt,top; inline void up(int x){ sz[x] = s[x] + sz[ L ] + sz[ R ]; } inline void Rotate(int x,int f){ int y=pre[x]; ch[y][!f] = ch[x][f]; pre[ ch[x][f] ] = y; pre[x] = pre[y]; if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] =x; ch[x][f] = y; pre[y] = x; up(y); } inline void Splay(int x,int goal){//将x旋转到goal的下面 while(pre[x] != goal){ if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0] == x); else { int y=pre[x],z=pre[y]; int f = (ch[z][0]==y); if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f); else Rotate(y,f),Rotate(x,f); } } up(x); if(goal==0) rt=x; } inline void RTO(int k,int goal){//将第k位数旋转到goal的下面 int x=rt; while(sz[ L ] != k-1) { if(k < sz[ L ]+1) x=L; else { k-=(sz[ L ]+1); x = R; } } Splay(x,goal); } inline void vist(int x){ if(x){ printf("结点%2d : 左儿子 %2d 右儿子 %2d %2d sz=%d\n",x,L,R,mp[x],sz[x]); vist(L); vist(R); } } void Del(){ int t=rt; if(ch[rt][1]) { rt=ch[rt][1]; RTO(1,0); ch[rt][0]=ch[t][0]; if(ch[rt][0]) pre[ch[rt][0]]=rt; } else rt=ch[rt][0]; pre[rt]=0; up(rt); } inline void Newnode(int &x,int id,int f){ x=++top; L = R = 0; pre[x] = f; sz[x]=s[x]=ed[id]-bg[id]+1; mp[x]=id; node[id]=x; } void build(int &x,int l,int r,int f){ if(l>r) return ; int m=l+r>>1; Newnode(x,m,f); build(L,l,m-1,x); build(R,m+1,r,x); pre[x]=f; up(x); } void init(){ ch[0][0]=ch[0][1]=pre[0]=sz[0]=0; rt=top=0; scanf("%d%d",&n,&m); tot=0; int k=0; num[k++]=1; for(int i=1;i<=m;i++){ scanf("%s%d",op[i],&x[i]); if(op[i][0]=='T' || op[i][0]=='Q') num[k++]=x[i]; } num[k++]=n; sort(num,num+k); bg[tot]=num[0]; ed[tot++]=num[0]; for(int i=1;i<k;i++){ if(num[i]!=num[i-1]){ if(num[i-1]+1<num[i]) { bg[tot]=num[i-1]+1; ed[tot++]=num[i]-1; } bg[tot]=num[i]; ed[tot++]=num[i]; } } build(rt,0,tot-1,0); } void Insert(int &x,int id,int p){ if(x==0) { Newnode(x,id,p); Splay(x,0); return ; } Insert(L,id,x); up(x); } void Query(int xx){ int id=lower_bound(bg,bg+tot,xx)-bg; Splay(node[id],0);; printf("%d\n",sz[ch[rt][0]]+1); } void Top(int xx) { int id=lower_bound(bg,bg+tot,xx)-bg; Splay(node[id],0); Del(); Insert(rt,id,0); Splay(node[id],0); } int Find(int x,int xx){ int id=mp[x]; if(xx <= sz[ L ]) return Find(L,xx); else if(xx <= sz[ L ] + s[x]) return bg[id] + (xx-sz[ L ]) -1; else return Find(R,xx - sz[ L ] - s[x]); } void solve() { for(int i=1;i<=m;i++) { if(op[i][0]=='T') { Top(x[i]); } else if(op[i][0]=='Q'){ Query(x[i]); } else { printf("%d\n",Find(rt,x[i])); } } } int bg[maxn]; int ed[maxn]; int num[maxn]; int s[maxn]; int mp[maxn]; int x[maxn]; int node[maxn]; int n,m,tot; char op[maxn][6]; }spt; int main(){ int t,ca=1; scanf("%d",&t); while(t--) { printf("Case %d:\n",ca++); spt.init(); spt.solve(); } return 0; }