P3165 [CQOI2014]排序機械臂
題目描述
為了把工廠中高低不等的物品按從低到高排好序,工程師發明了一種排序機械臂。它遵循一個簡單的排序規則,第一次操作找到高度最低的物品的位置 P1P_1P1? ,並把左起第一個物品至 P1P_1P1? 間的物品 (即區間 [1,P1][1,P_1][1,P1?] 間的物品) 反序;第二次找到第二低的物品的位置 P2P_2P2? ,並把左起第二個至 P2P_2P2? 間的物品 (即區間 [2,P2][2,P_2][2,P2?] 間的物品) 反序……最終所有的物品都會被排好序。
上圖給出有六個物品的示例,第一次操作前,高度最低的物品在位置 444 ,於是把第一至第四的物品反序;第二次操作前,第二低的物品在位罝六,於是把第二至六的物品反序……
你的任務便是編寫一個程序,確定一個操作序列,即每次操作前第 iii 低的物品所在位置 PiP_iPi? ,以便機械臂工作。需要註意的是,如果有高度相同的物品,必須保證排序後它們的相對位置關系與初始時相同。
輸入輸出格式
輸入格式:第一行包含正整數n,表示需要排序的物品數星。
第二行包含n個空格分隔的整數PiP_iPi?,表示每個物品的高度。
輸出格式:輸出一行包含n個空格分隔的整數Pi。
輸入輸出樣例
輸入樣例#1:6
3 4 5 1 6 2
輸出樣例#1:
4 6 4 5 6 6
說明
N<=100000
Pi<=10^7
Solution:
本題既然區間反轉,那麽Splay裸題。
首先對高度排序得到操作的順序,再對初始位置中序遍歷建樹。
對於每次操作的原位置,將其旋到根,答案(新的位置)就是其左子樹的大小,然後因為它的前趨之前的數已經位置固定,那麽只要把它和後繼所在的子樹翻轉,所以把前趨旋轉到根,再把後繼旋轉到根的右兒子,打上懶惰標記就好了。
註意,每次在splay改變樹的形態時下放標記,用棧存下一條鏈上的節點並下放,在查排名的時候也得下放標記。
代碼:
/*Code by 520 -- 9.20*/ #include<bits/stdc++.h> #define il inline #definell long long #define RE register #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--) #define son(x) (x==ch[fa[x]][1]) using namespace std; const int N=100005; int n,ans,stk[N],top; int root,cnt,ch[N][2],siz[N],lazy[N],fa[N]; struct node{ int v,id; bool operator < (const node &a) const {return v==a.v?id<a.id:v<a.v;} }a[N]; int gi(){ int a=0;char x=getchar();bool f=0; while((x<‘0‘||x>‘9‘)&&x!=‘-‘) x=getchar(); if(x==‘-‘) x=getchar(),f=1; while(x>=‘0‘&&x<=‘9‘) a=(a<<3)+(a<<1)+(x^48),x=getchar(); return f?-a:a; } il void pushup(int rt){siz[rt]=siz[ch[rt][0]]+siz[ch[rt][1]]+1;} il void pushdown(int rt){ if(lazy[rt]){ lazy[ch[rt][0]]^=1,lazy[ch[rt][1]]^=1; swap(ch[rt][0],ch[rt][1]),lazy[rt]=0; } } il void rotate(int x){ int y=fa[x],z=fa[y],b=son(x),c=son(y),a=ch[x][!b]; z?ch[z][c]=x:root=x; fa[x]=z; if(a) fa[a]=y; ch[y][b]=a; fa[y]=x,ch[x][!b]=y; pushup(y),pushup(x); } il void splay(int x,int i){ int tp=x;top=0; while(fa[tp]!=i) stk[++top]=tp,tp=fa[tp]; while(top) pushdown(stk[top--]); while(fa[x]!=i){ int y=fa[x],z=fa[y]; if(z==i) rotate(x); else { if(son(x)==son(y)) rotate(y),rotate(x); else rotate(x),rotate(x); } } } int build(int l,int r,int lst){ int rt=l+r>>1; fa[rt]=lst,siz[rt]=1; if(l<rt) ch[rt][0]=build(l,rt-1,rt); if(r>rt) ch[rt][1]=build(rt+1,r,rt); pushup(rt);return rt; } il int getrank(int x){ int rt=root; while(1){ pushdown(rt); if(siz[ch[rt][0]]>=x&&ch[rt][0]) rt=ch[rt][0]; else { x-=siz[ch[rt][0]]+1; if(!x) return rt; rt=ch[rt][1]; } } } int main(){ n=gi(); a[1]={-0x7fffffff,1},a[n+2]={0x7fffffff,n+2}; For(i,2,n+1) a[i].v=gi(),a[i].id=i; sort(a+1,a+n+3); root=build(1,n+2,0); For(i,2,n) { splay(a[i].id,0); ans=siz[ch[root][0]]+1; printf("%d ",ans-1); int pre=getrank(i-1),suc=getrank(ans+1); splay(pre,0),splay(suc,pre); lazy[ch[ch[root][1]][0]]^=1; } printf("%d",n); return 0; }
P3165 [CQOI2014]排序機械臂