您的位置:首页 > 其它

【BZOJ 1552】[Cerc2007]robotic sort

2014-11-27 18:50 351 查看

1552: [Cerc2007]robotic sort

Time Limit: 5 Sec Memory Limit: 64 MB

Submit: 326 Solved: 133

[Submit][Status]

Description



Input

输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000。第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号。

Output

输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,(1 < = Pi < = N),Pi表示第i次操作前第i小的物品所在的位置。 注意:如果第i次操作前,第i小的物品己经在正确的位置Pi上,我们将区间[Pi,Pi]反转(单个物品)。

Sample Input

6

3 4 5 1 6 2

Sample Output

4 6 4 5 6 6

HINT

Source

HNOI2009集训Day6

以位置为关键字的splay。

本题的大致思路就是每次找到整棵树中值最小的结点,把他旋到根结点即可求出他的位置,把他赋值为最大值(在根结点赋值只要Push_up(root)就可以了),然后反转区间,重复n次即可。

注意:
1.在数列中插入永远在排在最前和最后的两个值,赋值为最大值,方便后面操作

2.有权值相同的点输出在起始时候最早出现的位置,我解决的方法是:
每个结点多维护两个值:no,minno,分别表示在起始数列中的位置,和最小值出现的最早位置(在起始数列中最靠前)。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define maxn 0x7fffffff
using namespace std;
struct splay
{
int data,no,rev,l,r,fa,minn,size,minno;
}a[100005];
int rr[100005],n,root,tot=0;
void Push_up(int x)
{
a[x].size=1+a[a[x].r].size+a[a[x].l].size;
a[x].minno=maxn;
int minn=maxn;
if (a[x].r) minn=a[a[x].r].minn,a[x].minno=a[a[x].r].minno;
if (a[x].l&&a[a[x].l].minn<=minn)
{
if (minn==a[a[x].l].minn&&a[x].minno>a[a[x].l].minno)
a[x].minno=a[a[x].l].minno;
if (minn>a[a[x].l].minn)
minn=a[a[x].l].minn,a[x].minno=a[a[x].l].minno;
}
a[x].minn=minn;
if (a[x].data<=a[x].minn)
{
if (a[x].data==minn&&a[x].no<a[x].minno) a[x].minno=a[x].no;
if (a[x].data<a[x].minn)
a[x].minn=a[x].data,a[x].minno=a[x].no;
}
}
void Push_down(int x)
{
if (a[x].rev)
{
a[x].rev=0;
swap(a[x].l,a[x].r);
a[a[x].l].rev^=1;
a[a[x].r].rev^=1;
}
}
void New_Node(int &x,int fa,int key,int no)
{
x=++tot;
a[x].fa=fa;
a[x].l=a[x].r=a[x].rev=a[x].size=0;
a[x].data=key;
a[x].no=no;
}
void Build(int &x,int fa,int l,int r)
{
if (l>r) return;
int m=(l+r)>>1;
New_Node(x,fa,rr[m],m-1);
Build(a[x].l,x,l,m-1);
Build(a[x].r,x,m+1,r);
Push_up(x);
}
void zig(int x)
{
int y=a[x].fa;
int z=a[y].fa;
Push_down(y);Push_down(x);
a[y].fa=x,a[x].fa=z;
a[y].l=a[x].r,a[a[x].r].fa=y,a[x].r=y;
if (y==a[z].l) a[z].l=x;
else a[z].r=x;
Push_up(y);
}
void zag(int x)
{
int y=a[x].fa;
int z=a[y].fa;
Push_down(y);Push_down(x);
a[y].fa=x,a[x].fa=z;
a[y].r=a[x].l,a[a[x].l].fa=y,a[x].l=y;
if (y==a[z].l) a[z].l=x;
else a[z].r=x;
Push_up(y);
}
void splay(int x,int s)
{
Push_down(x);
while (a[x].fa!=s)
{
int y=a[x].fa;
int z=a[y].fa;
if (z==s)
{
if (x==a[y].l) zig(x);
else zag(x);
break;
}
if (y==a[z].l)
{
if (x==a[y].l) zig(y),zig(x);
else zag(x),zig(x);
}
else
{
if (x==a[y].r) zag(y),zag(x);
else zig(x),zag(x);
}
}
Push_up(x);
if (s==0) root=x;
}
int Find(int x)
{
if ((a[x].data==a[x].minn)&&a[x].no==a[x].minno) return x;
Push_down(x);
if (a[a[x].l].minn==a[x].minn&&a[a[x].l].minno==a[x].minno)
return Find(a[x].l);
return Find(a[x].r);
}
int Findkth(int x,int k)
{
Push_down(x);
int s=a[a[x].l].size;
if (k==s+1) return x;
if (s>=k) return Findkth(a[x].l,k);
return Findkth(a[x].r,k-s-1);
}
int Getmin(int x)
{
Push_down(x);
while (a[x].l)
{
x=a[x].l;
Push_down(x);
}
return x;
}
int Findnext(int x)
{
return Getmin(a[root].r);
}
void Reserve(int x,int y)
{
splay(x,0);
splay(y,root);
a[a[y].l].rev^=1;
}
int main()
{
scanf("%d",&n);
root=tot=0;
for (int i=1;i<=n;i++)
scanf("%d",&rr[i]);
rr[0]=rr[n+1]=maxn;
Build(root,0,0,n+1);
for (int i=1;i<=n;i++)
{
int ans;
ans=Find(root);
splay(ans,0);
a[root].data=maxn;
Push_up(root);
printf("%d",a[a[root].l].size);
Reserve(Findkth(root,i),Findnext(ans));
if (i==n) printf("\n");
else printf(" ");
}
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: