题目描述
为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂。它遵循一个简单的排序规则,第一次操作找到高度最低的物品的位置 $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,可能存在不稳定性
手写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;
}