[BZOJ 1861] 书架
Link:
Solution:
一道平衡树裸题调了两小时真是**
操作都比较常规:
1、$Top,Bottom$操作
先将$x$转到根节点,分情况讨论将其左/右子树合并到另一边去
2、$Insert$操作
其实完全没有必要先删除再插入,直接将$x$与其前驱/后继的信息交换就好了
Tip:
1、总感觉自己几个量分不清:点的序号,点的权值,点的排名(即在序列中的次序)
此题中$pos[x]$由权值指向序号,因此只有交换节点时改变,其他时候不用更新!
2、一般要对节点进行操作都要将其先旋转到根节点,感觉自己老忘……
3、如果对交换前的值有调用,一定要将原值先存下来!
Code:
#include <bits/stdc++.h> using namespace std; const int MAXN=1e5+10; char s[20];int x,y; int n,m,rt,dat[MAXN],ch[MAXN][2],f[MAXN],sz[MAXN],pos[MAXN],val[MAXN],tot=0; void pushup(int x) {sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;} void Build(int l,int r,int anc) { if(l>r) return; int mid=(l+r)/2; if(mid<anc) ch[anc][0]=mid; else ch[anc][1]=mid; f[mid]=anc;sz[mid]=1; val[mid]=dat[mid];pos[dat[mid]]=mid; Build(l,mid-1,mid);Build(mid+1,r,mid); pushup(mid); } void Rotate(int x) { int y=f[x],z=f[y],k=(ch[y][1]==x); ch[z][ch[z][1]==y]=x;f[x]=z; ch[y][k]=ch[x][k^1];f[ch[x][k^1]]=y; ch[x][k^1]=y;f[y]=x; pushup(x);pushup(y); } void Splay(int x,int up) { while(f[x]!=up) { int y=f[x],z=f[y]; if(z!=up) (ch[y][1]==x)^(ch[z][1]==y)?Rotate(x):Rotate(y); Rotate(x); } if(!up) rt=x; } int Kth(int x) { int k=rt; while(true) { if(sz[ch[k][0]]+1==x) return k; else if(sz[ch[k][0]]>=x) k=ch[k][0]; else x-=sz[ch[k][0]]+1,k=ch[k][1]; } } void Top(int x) { x=pos[x];Splay(x,0); if(!ch[x][0]) return; if(!ch[x][1]){ch[x][1]=ch[x][0];ch[x][0]=0;return;} int y=Kth(sz[ch[x][0]]+2); ch[y][0]=ch[x][0];f[ch[x][0]]=y;ch[x][0]=0; Splay(y,0); } void Bottom(int x) { x=pos[x];Splay(x,0); if(!ch[x][1]) return; if(!ch[x][0]){ch[x][0]=ch[x][1];ch[x][1]=0;return;} int y=Kth(sz[ch[x][0]]); ch[y][1]=ch[x][1];f[ch[x][1]]=y;ch[x][1]=0; Splay(y,0); } void Move(int x,int flag) { if(!flag) return; Splay(pos[x],0);//一定要先Splay int y=Kth(flag==1?sz[ch[pos[x]][0]]+2:sz[ch[pos[x]][0]]); int t=pos[x];//一定要先保留,否则再调用pos[x]时其值就变了 swap(pos[x],pos[val[y]]); swap(val[t],val[y]); } int Ask(int x) {Splay(pos[x],0);return sz[ch[rt][0]];} int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&dat[i]); rt=(n+1)/2;Build(1,n,rt);f[rt]=0; for(int i=1;i<=m;i++) { scanf("%s%d",s,&x); if(s[0]=='T') Top(x); else if(s[0]=='B') Bottom(x); else if(s[0]=='I') scanf("%d",&y),Move(x,y); else if(s[0]=='A') printf("%d\n",Ask(x)); else if(s[0]=='Q') printf("%d\n",val[Kth(x)]); } return 0; }