一、题目
题目描述
通过一系列移动,将某些物品按顺序摆好。规定只能使用如下方式排序: 先找到编号最小的物品的位置P1,将区间[1,P1]反转,再找到编号第二小的物品的位置P2,将区间[2,P2]反转……
输入n和编号,求出所有的Pi,有多组数据,
1
≤
n
≤
1
0
5
1\leq n\leq 10^5
1≤n≤105
tips
如果有相同的编号,要考虑顺序,可以理解为离散化,越后面的越大
二、解法
区间翻转的经典题,考虑无旋
treap
\text{treap}
treap。
先离散化,然后插入编号进平衡树,这里有一个问题,我们如何找到第几小的,由于这种排序方式满足操作第
i
i
i次时,全序列的第
i
i
i小值是
[
i
,
n
]
[i,n]
[i,n]中的最小值,我们就可以让平衡树维护一个编号的最小值,每次操作时先分裂出来
[
i
,
n
]
[i,n]
[i,n],找到它最小的编号的排名
t
t
t,就可以把
[
i
,
t
−
i
+
1
]
[i,t-i+1]
[i,t−i+1]分裂出来,打上标记,然后拼回去,找排名是沿着
min
=
i
\min=i
min=i子树找,然后就能找到排名了。
无旋
treap
\text{treap}
treap还是很好,容易写,功能也比较齐全。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <ctime>
using namespace std;
const int MAXN = 100005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,rt,num[MAXN],pos[MAXN];
int ch[MAXN][2],Min[MAXN],siz[MAXN],hp[MAXN],fl[MAXN];
bool cmp(int x,int y)
{
if(num[x]==num[y])
return x<y;
return num[x]<num[y];
}
struct node
{
int p[2];
node() {p[0]=p[1]=0;}
}emp;
void up(int x)
{
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
Min[x]=min(num[x],min(Min[ch[x][0]],Min[ch[x][1]]));
}
void down(int x)
{
fl[ch[x][0]]^=1;fl[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
fl[x]=0;
}
node split(int x,int s)
{
if(!x) return emp;
if(fl[x]) down(x);
node y;
if(siz[ch[x][0]]>=s)
{
y=split(ch[x][0],s);
ch[x][0]=y.p[1];
y.p[1]=x;
}
else
{
y=split(ch[x][1],s-siz[ch[x][0]]-1);
ch[x][1]=y.p[0];
y.p[0]=x;
}
up(x);
return y;
}
int merge(int x,int y)
{
if(!x || !y) return x+y;
if(hp[x]<hp[y])
{
if(fl[x]) down(x);
ch[x][1]=merge(ch[x][1],y);
up(x);
return x;
}
if(fl[y]) down(y);
ch[y][0]=merge(x,ch[y][0]);
up(y);
return y;
}
int find(int x,int v)
{
if(!x) return 0;
if(fl[x]) down(x);
if(num[x]==v) return siz[ch[x][0]]+1;
if(ch[x][0] && Min[ch[x][0]]==v)
return find(ch[x][0],v);
if(ch[x][1])
return siz[ch[x][0]]+1+find(ch[x][1],v);
return 0;
}
int main()
{
srand(time(0));
while(~scanf("%d",&n) && n)
{
rt=0;Min[0]=0x3f3f3f3f;
for(int i=1;i<=n;i++)
num[i]=read(),pos[i]=i;
sort(pos+1,pos+1+n,cmp);
for(int i=1;i<=n;i++)
num[pos[i]]=i;
for(int i=1;i<=n;i++)
{
ch[i][0]=ch[i][1]=0;
Min[i]=num[i];siz[i]=1;fl[i]=0;hp[i]=rand();
rt=merge(rt,i);
}
for(int i=1;i<n;i++)
{
node x=split(rt,i-1);
int t=find(x.p[1],i);
node y=split(x.p[1],t);
fl[y.p[0]]^=1;
rt=merge(x.p[0],merge(y.p[0],y.p[1]));
printf("%d ",t+i-1);
}
printf("%d\n",n);
}
}