题目大意
数组中有n个数,每次输出第i大的数所在位置,再翻转第i个数到第i大的数,如果有多个数大小相同,则在原数组中下标小的数优先。
我的做法
splay
用pair存每一个数,first是这个数,second是这个数在原数组中的下标。
每次把最小的数翻转到根,答案就是左子树的大小+已经删除的数的个数+1。然后删除树根。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
using namespace std;
struct tree
{
tree *s[2];
bool rev;
int sum;
pair<int,int> min;
pair<int,int> v;
tree()
{
rev=0;
sum=0;
s[0]=s[1]=0;
}
};
pair<int,int> a[100010];
tree *root;
void push(tree *&p)
{
if(!p||!p->rev)
return;
swap(p->s[0],p->s[1]);
if(p->s[0])
p->s[0]->rev^=1;
if(p->s[1])
p->s[1]->rev^=1;
p->rev=0;
}
void mt(tree *&p)
{
p->sum=1;
p->min=p->v;
if(p->s[0])
{
p->sum+=p->s[0]->sum;
p->min=min(p->min,p->s[0]->min);
}
if(p->s[1])
{
p->sum+=p->s[1]->sum;
p->min=min(p->min,p->s[1]->min);
}
}
void rotate(tree *&p,int d)
{
push(p);
tree *q=p->s[d^1];
push(q);
p->s[d^1]=q->s[d];
q->s[d]=p;
mt(p);
mt(q);
p=q;
}
void splay(tree *&p,int k)
{
push(p);
int s=0;
if(p->s[0])
s=p->s[0]->sum;
if(k<=s)
{
splay(p->s[0],k);
rotate(p,1);
return;
}
if(k==s+1)
return;
splay(p->s[1],k-s-1);
rotate(p,0);
}
void splaymin(tree *&p)
{
push(p);
if(p->s[0]&&p->s[0]->min==p->min)
{
splaymin(p->s[0]);
rotate(p,1);
return;
}
if(p->min==p->v)
return;
splaymin(p->s[1]);
rotate(p,0);
}
void build(tree *&p,int l,int r)
{
if(l>r)
return;
p=new tree;
p->sum=1;
int mid=(l+r)>>1;
p->v=p->min=a[mid];
build(p->s[0],l,mid-1);
build(p->s[1],mid+1,r);
mt(p);
}
void insert(tree *&p,pair<int,int> k)
{
push(p);
if(!p)
{
p=new tree;
p->sum=1;
p->v=k;
return;
}
if(k<=p->v)
{
insert(p->s[0],k);
rotate(p,1);
}
else
{
insert(p->s[1],k);
rotate(p,0);
}
mt(p);
}
void remove(tree *&p)
{
if(!p)
return;
remove(p->s[0]);
remove(p->s[1]);
delete p;
p=0;
}
void split(tree *&p,tree *&p1,tree *&p2,int k)
{
if(!k)
{
p2=p;
p=0;
return;
}
splay(p,k);
p2=p->s[1];
p->s[1]=0;
mt(p);
p1=p;
p=0;
}
void merge(tree *&p,tree *&p1,tree *&p2)
{
if(!p1)
{
p=p2;
p2=0;
return;
}
splay(p1,p1->sum);
p1->s[1]=p2;
mt(p1);
p=p1;
p1=p2=0;
}
int cnt;
void print(tree *&p)
{
if(!p)
return;
push(p);
print(p->s[0]);
if(cnt++)
printf(" ");
printf("%d",p->v);
print(p->s[1]);
}
int main()
{
int n;
while(scanf("%d",&n),n!=0)
{
remove(root);
int i;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i].first);
a[i].second=i;
}
build(root,1,n);
for(i=1;i<=n;i++)
{
splaymin(root);
tree *p1=root->s[0],*p2=root->s[1];
delete root;
root=0;
int s=0;
if(p1)
s=p1->sum;
printf("%d",i+s);
if(i<n)
printf(" ");
if(!p1)
root=p2;
else
{
p1->rev^=1;
merge(root,p1,p2);
}
}
printf("\n");
}
return 0;
}