Description
有n个物品,每个物品有它的高度a[i],现在我们要采用一种神奇的方法把这n个物品排好序。第x次我们找到第x矮的物品位置p[x],并且把x到p[x]中间的物品翻转。如果有多个一样高度的,位置后的更高。
求所有的p[i]。
n<=10^5
Solution
我们可以模拟题目中的操作。
翻转神马的splay杠杠的。
于是这道题就是一道基础splay序列题。
为了方便查找,我们可以先把所有物品排个序,然后每次把1~i-1翻转,并且把i删除(防止对后面的影响),接着把1~i-1和i+1~n合并。
练一练码力。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 100005
using namespace std;
struct note{int v,w;}a[N];
bool cmp(note x,note y) {return x.v<y.v||x.v==y.v&&x.w<y.w;}
int n,t[N][2],f[N],size[N],rev[N],d[N],ans[N],root;
void updata(int x) {
size[x]=size[t[x][0]]+size[t[x][1]]+1;
}
int son(int x) {
if (x==t[f[x]][0]) return 0;else return 1;
}
void back(int x) {
rev[x]^=1;swap(t[x][0],t[x][1]);
}
void down(int x) {
if (rev[x]) {
if (t[x][0]) back(t[x][0]);
if (t[x][1]) back(t[x][1]);
rev[x]=0;
}
}
void remove(int x,int y) {
if (x==y) return;
do {
d[++d[0]]=x;x=f[x];
} while (x!=y);
while (d[0]) down(d[d[0]--]);
}
void rotate(int x) {
int y=f[x],z=son(x);f[x]=f[y];
if (f[y]) t[f[y]][son(y)]=x;
t[y][z]=t[x][1-z];
if (t[x][1-z]) f[t[x][1-z]]=y;
t[x][1-z]=y;f[y]=x;
updata(y);updata(x);
}
void splay(int x,int y) {
remove(x,y);
while (f[x]!=y) {
if (f[f[x]]!=y)
if (son(x)==son(f[x])) rotate(f[x]);
else rotate(x);
rotate(x);
}
if (!y) root=x;
}
int build(int l,int r,int fa) {
if (l>r) return 0;
int m=(l+r)/2;
f[m]=fa;size[m]=r-l+1;
if(l==r)return l;
t[m][0]=build(l,m-1,m);
t[m][1]=build(m+1,r,m);
return m;
}
void find(int x) {
down(x);x=t[x][1];
while (x) {
down(x);
if (t[x][0]) x=t[x][0];
else break;
}
splay(x,0);
}
void del(int x) {
f[t[x][0]]=f[x];
t[f[x]][0]=t[x][0];
updata(f[x]);
}
int main() {
scanf("%d",&n);
fo(i,1,n) scanf("%d",&a[i].v),a[i].w=i;
build(1,n+1,0);
sort(a+1,a+n+1,cmp);
fo(i,1,n) {
splay(a[i].w,0);back(t[root][0]);
printf("%d",size[t[root][0]]+i);
if (i!=n) printf(" ");
find(root);del(t[root][0]);
}
}