![【BZOJ 1552】[Cerc2007]robotic sort_第1张图片](http://img.e-com-net.com/image/info5/b94900454003416b996cc40e916225a0.gif)
HNOI2009集训Day6
以位置为关键字的splay。
本题的大致思路就是每次找到整棵树中值最小的结点,把他旋到根结点即可求出他的位置,把他赋值为最大值(在根结点赋值只要Push_up(root)就可以了),然后反转区间,重复n次即可。
注意:
1.在数列中插入永远在排在最前和最后的两个值,赋值为最大值,方便后面操作
2.有权值相同的点输出在起始时候最早出现的位置,我解决的方法是:
每个结点多维护两个值:no,minno,分别表示在起始数列中的位置,和最小值出现的最早位置(在起始数列中最靠前)。
#include <iostream> #include <algorithm> #include <cstring> #include <cstdlib> #include <cstdio> #define maxn 0x7fffffff using namespace std; struct splay { int data,no,rev,l,r,fa,minn,size,minno; }a[100005]; int rr[100005],n,root,tot=0; void Push_up(int x) { a[x].size=1+a[a[x].r].size+a[a[x].l].size; a[x].minno=maxn; int minn=maxn; if (a[x].r) minn=a[a[x].r].minn,a[x].minno=a[a[x].r].minno; if (a[x].l&&a[a[x].l].minn<=minn) { if (minn==a[a[x].l].minn&&a[x].minno>a[a[x].l].minno) a[x].minno=a[a[x].l].minno; if (minn>a[a[x].l].minn) minn=a[a[x].l].minn,a[x].minno=a[a[x].l].minno; } a[x].minn=minn; if (a[x].data<=a[x].minn) { if (a[x].data==minn&&a[x].no<a[x].minno) a[x].minno=a[x].no; if (a[x].data<a[x].minn) a[x].minn=a[x].data,a[x].minno=a[x].no; } } void Push_down(int x) { if (a[x].rev) { a[x].rev=0; swap(a[x].l,a[x].r); a[a[x].l].rev^=1; a[a[x].r].rev^=1; } } void New_Node(int &x,int fa,int key,int no) { x=++tot; a[x].fa=fa; a[x].l=a[x].r=a[x].rev=a[x].size=0; a[x].data=key; a[x].no=no; } void Build(int &x,int fa,int l,int r) { if (l>r) return; int m=(l+r)>>1; New_Node(x,fa,rr[m],m-1); Build(a[x].l,x,l,m-1); Build(a[x].r,x,m+1,r); Push_up(x); } void zig(int x) { int y=a[x].fa; int z=a[y].fa; Push_down(y);Push_down(x); a[y].fa=x,a[x].fa=z; a[y].l=a[x].r,a[a[x].r].fa=y,a[x].r=y; if (y==a[z].l) a[z].l=x; else a[z].r=x; Push_up(y); } void zag(int x) { int y=a[x].fa; int z=a[y].fa; Push_down(y);Push_down(x); a[y].fa=x,a[x].fa=z; a[y].r=a[x].l,a[a[x].l].fa=y,a[x].l=y; if (y==a[z].l) a[z].l=x; else a[z].r=x; Push_up(y); } void splay(int x,int s) { Push_down(x); while (a[x].fa!=s) { int y=a[x].fa; int z=a[y].fa; if (z==s) { if (x==a[y].l) zig(x); else zag(x); break; } if (y==a[z].l) { if (x==a[y].l) zig(y),zig(x); else zag(x),zig(x); } else { if (x==a[y].r) zag(y),zag(x); else zig(x),zag(x); } } Push_up(x); if (s==0) root=x; } int Find(int x) { if ((a[x].data==a[x].minn)&&a[x].no==a[x].minno) return x; Push_down(x); if (a[a[x].l].minn==a[x].minn&&a[a[x].l].minno==a[x].minno) return Find(a[x].l); return Find(a[x].r); } int Findkth(int x,int k) { Push_down(x); int s=a[a[x].l].size; if (k==s+1) return x; if (s>=k) return Findkth(a[x].l,k); return Findkth(a[x].r,k-s-1); } int Getmin(int x) { Push_down(x); while (a[x].l) { x=a[x].l; Push_down(x); } return x; } int Findnext(int x) { return Getmin(a[root].r); } void Reserve(int x,int y) { splay(x,0); splay(y,root); a[a[y].l].rev^=1; } int main() { scanf("%d",&n); root=tot=0; for (int i=1;i<=n;i++) scanf("%d",&rr[i]); rr[0]=rr[n+1]=maxn; Build(root,0,0,n+1); for (int i=1;i<=n;i++) { int ans; ans=Find(root); splay(ans,0); a[root].data=maxn; Push_up(root); printf("%d",a[a[root].l].size); Reserve(Findkth(root,i),Findnext(ans)); if (i==n) printf("\n"); else printf(" "); } return 0; }