洛谷P3165 [CQOI2014]排序機械臂【splay】
阿新 • • 發佈:2018-04-05
物體 題目 分享圖片 char s node 如果 反序 splay upd
若直接對高度sort,可能存在不穩定性
手寫sort請無視
題目描述
為了把工廠中高低不等的物品按從低到高排好序,工程師發明了一種排序機械臂。它遵循一個簡單的排序規則,第一次操作找到高度最低的物品的位置 $p_1$,並把左起第一個物品至$p_1$間的物品 (即區間 $[1,p_1]$間的物品) 反序;第二次找到第二低的物品的位置$p_2$,並把左起第二個至$p_2$ 間的物品 (即區間$[2,p_2]$間的物品) 反序……最終所有的物品都會被排好序。
上圖給出有六個物品的示例,第一次操作前,高度最低的物品在位置 4 ,於是把第一至第四的物品反序;第二次操作前,第二低的物品在位罝六,於是把第二至六的物品反序……
你的任務便是編寫一個程序,確定一個操作序列,即每次操作前第$p_i$ 低的物品所在位置$p_i$,以便機械臂工作。需要註意的是,如果有高度相同的物品,必須保證排序後它們的相對位置關系與初始時相同。
輸入格式:
第一行包含正整數n,表示需要排序的物品數星。
第二行包含n個空格分隔的整數ai,表示每個物品的高度。
輸出格式:
輸出一行包含n個空格分隔的整數Pi。
輸入樣例
6
3 4 5 1 6 2
輸出樣例
4 6 4 5 6 6
說明
N<=100000
Pi<=10^7
************************
題目分析
比較常規的splay區間翻轉題
加入哨兵結點建樹
高度排序後一次查詢排名並翻轉
有兩點需要註意
1.每次要先把元素旋轉到根得到他的排名在反轉區間
所以在這裏splay裏面也要加push下推
而且 z, y, x都要push
2.高度相同的物體排序後順序也要相同
讀入時要把高度與編號存入結構體再雙關鍵字排序
若直接對高度sort,可能存在不穩定性
#include<iostream> #include<vector> #include<algorithm> #include<queue> #include<cstring> #include<cstdio> using namespace std; int read() { int f=1,x=0; char ss=getchar(); while(ss<‘0‘||ss>‘9‘){if(ss==‘-‘)f=-1;ss=getchar();} while(ss>=‘0‘&&ss<=‘9‘){x=x*10+ss-‘0‘;ss=getchar();} return f*x; } const int maxn=200010; int n; struct node{int v,pos;}a[maxn]; int ch[maxn][2],fa[maxn]; int size[maxn],sz,rt; int lzy[maxn]; bool cmp(node a,node b) { if(a.v==b.v) return a.pos<b.pos; return a.v<b.v; } void update(int p) { size[p]=size[ch[p][0]]+size[ch[p][1]]+1; } inline void push(int p) { if(lzy[p]) { swap(ch[p][0],ch[p][1]); lzy[ch[p][0]]^=1; lzy[ch[p][1]]^=1; lzy[p]=0; } } void rotate(int &p,int x) { int y=fa[x],z=fa[y]; int t=(ch[y][0]==x); if(y==p) p=x; else if(ch[z][0]==y) ch[z][0]=x; else ch[z][1]=x; fa[y]=x; fa[ch[x][t]]=y; fa[x]=z; ch[y][t^1]=ch[x][t]; ch[x][t]=y; update(y); update(x); } void splay(int &p,int x) { while(x!=p) { int y=fa[x],z=fa[y]; push(z);push(y);push(x); if(y!=p) { if((ch[z][0]==y)^(ch[y][0]==x))rotate(p,x); else rotate(p,y); } rotate(p,x); } } void build(int p,int ll,int rr) { if(ll>rr) return; int mid=ll+rr>>1; fa[mid]=p; size[mid]=1; ch[p][mid>p]=mid; if(ll==rr) return; build(mid,ll,mid-1);build(mid,mid+1,rr); update(mid); } int find(int p,int k) { push(p); int ss=size[ch[p][0]]; if(k==ss+1) return p; if(k<=ss) return find(ch[p][0],k); else return find(ch[p][1],k-ss-1); } void rev(int ll,int rr) { int x=find(rt,ll-1),y=find(rt,rr+1); splay(rt,x); splay(ch[rt][1],y); lzy[ch[y][0]]^=1; } void solve() { for(int i=2;i<=n;++i) { int x=a[i].pos; splay(rt,x); printf("%d ",size[ch[rt][0]]); int ll=i-1,rr=size[ch[rt][0]]; rev(ll+1,rr+1); } printf("%d ",n);//最後一個元素的排名必定為n,所以不用查詢 } int main() { n=read(); for(int i=2;i<=n+1;++i){ a[i].v=read(); a[i].pos=i;} a[1].v=-1e8; a[1].pos=1;//讀入高度信息 a[n+2].v=1e8; a[n+2].pos=n+2; rt=n+3>>1; build(rt,1,n+2); sort(a+1,a+n+3,cmp);//雙關鍵字排序 solve(); return 0; }
洛谷P3165 [CQOI2014]排序機械臂【splay】