【传送门:BZOJ1552&BZOJ3506】
简要题意:
给出一个长度为n的序列,现在要将它们进行排序,排序的操作为:
如果当前是第i次排序,则先找到当前序列中的最i小值所在位置x(如果有多个,则找到一开始给出序列顺序中排在最前面的数),然后将第i到第x的位置上的数都翻转
求出每次操作中x的值
题解:
splay裸题,树上记录最小值以及如果有多个最小值时初始位置最小的数在树上的位置,以及翻转标记
然后每做完一次操作,就要把x从树中删掉就行了
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define Maxn 110000 #define INF 1<<30 using namespace std; struct T{int f,son[2],c,d,p,mp,mn;bool fz;T(){mn=INF;fz=false;}}tr[Maxn];int len; int rt,a[Maxn]; void update(int x) { int lc=tr[x].son[0],rc=tr[x].son[1]; int mmin=min(tr[x].d,min(tr[lc].mn,tr[rc].mn)),t=INF; if(tr[x].d==mmin) if(t>tr[x].p) t=tr[x].p; if(tr[lc].mn==mmin) if(t>tr[lc].mp) t=tr[lc].mp; if(tr[rc].mn==mmin) if(t>tr[rc].mp) t=tr[rc].mp; tr[x].mn=mmin;tr[x].mp=t; tr[x].c=tr[lc].c+tr[rc].c+(tr[x].d!=INF); } int ins(int l,int r) { int mid=(l+r)/2; int now=++len; tr[now].d=a[mid];tr[now].p=mid; if(l<mid) tr[now].son[0]=ins(l,mid-1),tr[tr[now].son[0]].f=now; if(mid<r) tr[now].son[1]=ins(mid+1,r),tr[tr[now].son[1]].f=now; update(now); return now; } void reverse(int x) { int lc=tr[x].son[0],rc=tr[x].son[1]; if(lc!=0) tr[lc].fz^=1; if(rc!=0) tr[rc].fz^=1; swap(tr[x].son[0],tr[x].son[1]); tr[x].fz^=1; } void rotate(int x,int w) { int f=tr[x].f,ff=tr[f].f; int r,R; r=tr[x].son[w];R=f; tr[R].son[1-w]=r; if(r!=0) tr[r].f=R; r=x;R=ff; if(tr[R].son[0]==f) tr[R].son[0]=r; else tr[R].son[1]=r; tr[r].f=R; r=f;R=x; tr[R].son[w]=r; tr[r].f=R; update(f); update(x); } int s[Maxn],tot; void splay(int x,int tp) { int i=x,tot=0; while(tr[i].f!=tp) { s[++tot]=i; i=tr[i].f; } s[++tot]=i; while(tot!=0) { i=s[tot--]; if(tr[i].fz==true) reverse(i); } while(tr[x].f!=tp) { int f=tr[x].f,ff=tr[f].f; if(ff==tp) { if(tr[f].son[0]==x) rotate(x,1); else rotate(x,0); } else { if(tr[f].son[0]==x&&tr[ff].son[0]==f){rotate(f,1);rotate(x,1);continue;} if(tr[f].son[0]==x&&tr[ff].son[1]==f){rotate(x,1);rotate(x,0);continue;} if(tr[f].son[1]==x&&tr[ff].son[0]==f){rotate(x,0);rotate(x,1);continue;} if(tr[f].son[1]==x&&tr[ff].son[1]==f){rotate(f,0);rotate(x,0);continue;} } } if(tp==0) rt=x; } void del(int x) { splay(x,0); if(tr[x].son[0]==0&&tr[x].son[1]==0) rt=0; else if(tr[x].son[0]==0&&tr[x].son[1]!=0) rt=tr[x].son[1],tr[rt].f=0; else if(tr[x].son[0]!=0&&tr[x].son[1]==0) rt=tr[x].son[0],tr[rt].fz^=1,tr[rt].f=0; else { if(tr[x].fz==true) reverse(x); int p=tr[x].son[1]; if(tr[p].fz==true) reverse(p); while(tr[p].son[0]!=0) { p=tr[p].son[0]; if(tr[p].fz==true) reverse(p); } splay(p,x); int r=tr[x].son[0],R=p; tr[R].son[0]=r; tr[r].f=R; rt=R;tr[R].f=0; update(R); tr[r].fz^=1; } len--; } int getmin() { int x=rt; while(tr[x].son[0]!=0||tr[x].son[1]!=0) { if(tr[x].fz==true) reverse(x); int lc=tr[x].son[0],rc=tr[x].son[1]; int mmin=min(tr[x].d,min(tr[lc].mn,tr[rc].mn)),t=INF; if(tr[x].d==mmin) if(t>tr[x].p) t=tr[x].p; if(tr[lc].mn==mmin) if(t>tr[lc].mp) t=tr[lc].mp,x=lc; if(tr[rc].mn==mmin) if(t>tr[rc].mp) t=tr[rc].mp,x=rc; if(x!=lc&&x!=rc) break; } return x; } int main() { int n; scanf("%d",&n); for(int i=2;i<=n+1;i++) scanf("%d",&a[i]);a[1]=a[n+2]=INF; len=0;rt=ins(1,n+2); for(int i=1;i<=n;i++) { int x=getmin(); splay(x,0); if(i<n) printf("%d ",tr[tr[x].son[0]].c+i); else printf("%d\n",tr[tr[x].son[0]].c+i); del(x); } return 0; }