bzoj1861 [Zjoi2006]Book 书架——splay
Posted zinn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1861 [Zjoi2006]Book 书架——splay相关的知识,希望对你有一定的参考价值。
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1861
发现自己想splay的时候总是纠结那个点权是什么,因为splay原本是二分查找树...
但其实splay已经不是维护点权大小顺序的,它的最大作用就在于无论怎样旋转都保持着中序遍历这个相对位置不变;
所以很对应这道题,用splay进行各种操作的同时书的摆放顺序是不变的;
假设出一个‘1’点、一个‘n+1’点方便操作,所以整体+1;
这个建树的方法不错呢。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int const maxn=80005,inf=0x3f3f3f3f; int n,m,rt,a[maxn],pos[maxn],v[maxn],c[maxn][3],siz[maxn],fa[maxn]; void pushup(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; // if(l<f)c[f][0]=l;else c[f][1]=l; 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; // if(mid<f)c[f][0]=mid;else c[f][1]=mid; c[f][(mid>f)]=mid; pushup(mid); } void rotate(int x,int &k) { int y=fa[x],z=fa[y]; int d=(c[y][1]==x); if(y==k)k=x; else c[z][(c[z][1]==y)]=x; fa[x]=z;fa[y]=x;fa[c[x][d^1]]=y; c[y][d]=c[x][d^1];c[x][d^1]=y; pushup(y);pushup(x); } void splay(int x,int &k) { while(x!=k) { int 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 x,int rank) { int l=c[x][0],r=c[x][1]; if(rank==siz[l]+1)return x; else if(rank<=siz[l])return find(l,rank); else return find(r,rank-siz[l]-1); } void del(int k) { int x=find(rt,k-1),y=find(rt,k+1); splay(x,rt);splay(y,c[x][1]); int z=c[y][0];c[y][0]=0;siz[z]=0;fa[z]=0; pushup(y);pushup(x); } void move(int k,int val) { int x,y,z=pos[k],rank; splay(z,rt);rank=siz[c[z][0]]+1; del(rank); if(val==-inf)x=find(rt,1),y=find(rt,2); else if(val==inf)x=find(rt,n),y=find(rt,n+1);//else if而非if!!! //del后有n-1本书 else x=find(rt,rank+val-1),y=find(rt,rank+val); splay(x,rt);splay(y,c[x][1]); c[y][0]=z;siz[z]=1;fa[z]=y; pushup(y);pushup(x); } int main() { scanf("%d%d",&n,&m); for(int i=2;i<=n+1;i++) scanf("%d",&a[i]),pos[a[i]]=i; build(1,n+2,0);rt=(n+3)/2;//+‘1‘ char ch[10]; for(int i=1,x,T;i<=m;i++) { scanf("%s",&ch);scanf("%d",&x); if(ch[0]==‘T‘)move(x,-inf);//top if(ch[0]==‘B‘)move(x,inf);//bottom if(ch[0]==‘I‘)scanf("%d",&T),move(x,T); if(ch[0]==‘A‘)splay(pos[x],rt),printf("%d ",siz[c[pos[x]][0]]-1);//‘1‘ if(ch[0]==‘Q‘)printf("%d ",v[find(rt,x+1)]);//‘1‘ } return 0; }
以上是关于bzoj1861 [Zjoi2006]Book 书架——splay的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1861: [Zjoi2006]Book 书架 splay
BZOJ 1861: [Zjoi2006]Book 书架 (splay)