【BZOJ 1552】[Cerc2007]robotic sort

1552: [Cerc2007]robotic sort

Time Limit: 5 Sec   Memory Limit: 64 MB
Submit: 326   Solved: 133
[ Submit][ Status]

Description

【BZOJ 1552】[Cerc2007]robotic sort_第1张图片

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;
}

【BZOJ 1552】[Cerc2007]robotic sort_第2张图片

你可能感兴趣的:(数据结构,splay,OI,bzoj)