hdu 1890 splay
题意:给定数列,要求每次找到最小的数,输出是第几个,将其本身连同左边翻转,然后删除这个数。如果最小的数不止一个,则取元数列中靠前的那个。
分析:要注意边界情况,以及孩子为0的情况 。结点存储原数列中的下标,子树中最小元素的下标。为了找到最小元素,还要存储最小元素来自左子树还是右子树。
#define keyTree (ch[ ch[root][1] ][0]) const int vaf=0x3fffffff; const int MaxN = 100005; struct SplayTree{ int sz[MaxN]; int ch[MaxN][2];//ch[][0]左孩子 ch[][1]右孩子 int pre[MaxN];//父结点 int root,top1,top2; int sta[MaxN],que[MaxN]; inline void Rotate(int x,int f) {//f==0左旋转 f==1右旋转 int y=pre[x]; PushDown(y); PushDown(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; PushUp(y); //if(y==root)root=x; } inline void Splay(int x,int goal) {//将x旋转到goal的下面 PushDown(x); while(pre[x]!=goal) { if(pre[pre[x]]==goal) Rotate(x,ch[pre[x]][0]==x); else{ int y=pre[x],z=pre[y],f=(ch[z][0]==y); if(ch[y][f]==x) Rotate(x,!f),Rotate(x,f); else Rotate(y,f),Rotate(x,f); } } PushUp(x); if(goal==0) root=x; } inline void RotateTo(int k,int goal) {//将第k个数旋转到goal下面 int x=root; PushDown(x); k++; //由于加入了两个边界结点 所以应为k+1位 while(sz[ch[x][0]]!=k-1) { if(k-1<sz[ch[x][0]]) x=ch[x][0]; else k-=(sz[ch[x][0]]+1),x=ch[x][1]; PushDown(x); } Splay(x,goal); } inline void Delete(int x) {//把以x为祖先结点删掉放进内存池,回收内存 int fa=pre[x],head=0,tail=0; for(que[tail++]=x;head<tail;head++){ sta[top2++]=que[head]; if(ch[que[head]][0]) que[tail++]=ch[que[head]][0]; if(ch[que[head]][1]) que[tail++]=ch[que[head]][1]; } ch[fa][ch[fa][1]==x]=0; while(fa!=root) PushUp(fa),fa=pre[fa]; PushUp(root); } inline int pred(int x){//在x的子树中找x的前驱 int y=ch[x][0]; PushDown(x); PushDown(y); while(ch[y][1]) y=ch[y][1],PushDown(y); //if(y==0) y=1; //x是其子树中最前面的,没有前驱 return y; } inline int succ(int x){//在x的子树中找x的后继 int y=ch[x][1]; PushDown(x); PushDown(y); while(ch[y][0]) y=ch[y][0],PushDown(y); //if(y==0) y=2; //x是其子树中最后面的,没有后继 return y; } //以上一般不修改////////////////////////////////////////////////// inline void NewNode(int &x,int c) { x=++top1; ch[x][0]=ch[x][1]=pre[x]=0; sz[x]=1; p[x]=pos[x]=c; // rev[x]=0; dir[x]=0; } inline void makeTree(int &x,int l,int r,int father){ if(l>r) return; int m=(l+r)>>1; NewNode(x,m); //num[m]权值改成题目所需的 makeTree(ch[x][0],l,m-1,x); makeTree(ch[x][1],m+1,r,x); pre[x]=father; PushUp(x); } inline void init(int n) { ch[0][0]=ch[0][1]=pre[0]=sz[0]=0; root=top1=top2=0; dir[0]=0; p[0]=pos[0]=0; rev[0]=0; num[0]=vaf; //为了方便处理边界,加两个边界顶点 NewNode(root,0); // NewNode(ch[root][1],0); // pre[top1]=root; sz[root]=2; makeTree(keyTree,1,n,ch[root][1]); PushUp(ch[root][1]); PushUp(root); } inline void PushDown(int x) { if(rev[x]){ if(ch[x][0]) rev[ch[x][0]]^=1; if(ch[x][1]) rev[ch[x][1]]^=1; rev[x]=0; swap(ch[x][0],ch[x][1]); dir[x]*=-1; } } inline void PushUp(int x) { sz[x]=1+sz[ch[x][0]]+sz[ch[x][1]];//sz[0]==0 pos[x]=p[x],dir[x]=0; int pl=pos[ch[x][0]],pr=pos[ch[x][1]]; if(num[pl]<num[pos[x]]||(num[pl]==num[pos[x]]&&pl<pos[x])) pos[x]=pl,dir[x]=-1; if(num[pr]<num[pos[x]]||(num[pr]==num[pos[x]]&&pr<pos[x])) pos[x]=pr,dir[x]=1; } inline void UpDate(int m){ Splay(1,0); int p0=root,p1,p2; while(dir[p0]){ PushDown(p0); if(dir[p0]==-1)p0=ch[p0][0]; else p0=ch[p0][1]; } Splay(p0,root); p1=succ(p0); Splay(p1,root); printf("%d",sz[keyTree]+m); rev[p0]=true; Splay(p0,0); p1=pred(p0); p2=succ(p0); Splay(p1,0); Splay(p2,root); Delete(p0); } int num[MaxN];//只在建树时使用 int p[MaxN]; int pos[MaxN]; int dir[MaxN]; int rev[MaxN]; }spt; int main() { int n ; while(cin>>n,n){ for(int i=1;i<=n;i++) scanf("%d",&spt.num[i]); spt.init(n); for(int m=0;m<n;m++){ spt.UpDate(m); if(m<n-1)printf(" "); } printf("\n"); } return 0; }