题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1861
Splay模板。
这种写法的建树很好,创建虚拟的1点和n+2点,实际点变成2~n+1,就能自如应对“top”和“bottom”操作了。
一直不太理解Splay里点的角标、值和rank的关系。现在明白rank表示位置,只和siz有关。值和角标不会改变,可以记录一些别的信息。
(注意别把角标和rank搞混)
有一些注意地方:
1.那个 if((c[y][0]==x)^(c[z][0]==y)),意为如果是拐一下的就先转中间点,如果是顺着的就先转最底下的点;
2.注意update先弄底下的点;
3.用scanf("%s",ch)输入字符串。
4.为了建虚拟的1,输入从2开始。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=80005,INF=0x7fffffff; int n,m,a[N],pos[N],v[N],c[N][2],fa[N],siz[N],rt; char ch[10]; void update(int x){siz[x]=siz[c[x][0]]+siz[c[x][1]]+1;} void build(int l,int r,int f) { if(l>r)return; if(l==r) { v[l]=a[l];siz[l]=1;fa[l]=f; c[f][l>f]=l;return; } int mid=((l+r)>>1); build(l,mid-1,mid);build(mid+1,r,mid); v[mid]=a[mid];fa[mid]=f;c[f][mid>f]=mid; update(mid); } void rotate(int x,int &k) { int y=fa[x],z=fa[y],d=(x==c[y][1]); if(y!=k)c[z][y==c[z][1]]=x; else k=x; fa[x]=z;fa[y]=x;fa[c[x][!d]]=y; c[y][d]=c[x][!d];c[x][!d]=y; update(y);update(x); // } void splay(int x,int &k) { int y,z; while(x!=k) { y=fa[x];z=fa[y]; if(y!=k) { if((c[y][0]==x)^(c[z][0]==y)) rotate(x,k); else rotate(y,k); } rotate(x,k); } } int find(int k,int rank) { int d=siz[c[k][0]]+1; if(rank==d)return k; if(rank<d)return find(c[k][0],rank); return find(c[k][1],rank-d); } void del(int k) { int x=find(rt,k-1),y=find(rt,k+1); splay(x,rt);splay(y,c[x][1]); fa[c[y][0]]=0;siz[c[y][0]]=0;c[y][0]=0;//这里的c[y][0]不是k,k是rank,以大小判断;c[y][0]是角标,表示原位置 update(y);update(x); } void move(int cr,int tmp) { int x,y,z=pos[cr],rank; splay(z,rt);rank=siz[c[z][0]]+1; del(rank); if(tmp==-INF)x=find(rt,1),y=find(rt,2); else if(tmp==INF)x=find(rt,n),y=find(rt,n+1); else x=find(rt,rank+tmp-1),y=find(rt,rank+tmp); splay(x,rt);splay(y,c[x][1]); fa[z]=y;c[y][0]=z;siz[z]=1; update(y);update(x); } int main() { scanf("%d%d",&n,&m); for(int i=2;i<=n+1;i++)scanf("%d",&a[i]),pos[a[i]]=i;//2~n+1为了虚拟的1 build(1,n+2,0); int cr,tp;rt=((n+3)>>1); for(int i=1;i<=m;i++) { scanf("%s",ch);scanf("%d",&cr); if(ch[0]=='T')move(cr,-INF); if(ch[0]=='B')move(cr,INF); if(ch[0]=='I')scanf("%d",&tp),move(cr,tp); if(ch[0]=='A')splay(pos[cr],rt),printf("%d ",siz[c[rt][0]]-1); if(ch[0]=='Q')printf("%d ",v[find(rt,cr+1)]); } return 0; }