[HDU1890] Robotic Sort SPLAY

原题走这里

原题有点难以描述,就不描述了,很明显的Splay(也许可以加一个离散化)

思维上最大的难点就在于如何找出下一个待排序的元素的位置

由于SPLAY数组中的元素下标是不变的

只需预处理出一个数组,储存第n个元素在SPLAY数组中的位置即可


每次把待排序元素的后继旋到根

输出(根的左子树大小-i+1)

将根的左子树翻转,待排序元素就到了SPALY的最左侧

将其删去后重复上述即可


有一个有点麻烦的地方,就是数据中可能会有重复的数

我的方法是在一开始离散化的时候,把单纯的排序,改为每个数按照原数作为第一关键字,下标为第二关键字排序即可

做起来让人感觉很难受的一道题

不过做的越难受AC得就越爽


#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <iostream> 
#include <cstring>
using namespace std;
char buf[5000000],*pp=buf;
#define getchar() *(pp++)
#define d(x) tr[x].d
#define s(x) tr[x].s
#define f(x) tr[x].f
#define r(x) tr[x].r
#define c(x,y) tr[x].c[y]
inline int read() {
    int X=0,w=1;char ch=0;
    while(ch>'9'||ch<'0')w=(ch=='-'?-1:1),ch=getchar();
    while(ch<='9'&&ch>='0') X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return X*w;
}
struct node
{
	int d,f,c[2],s;
	bool r;
	node(int _d,int _f)
	{
		d=_d;
		f=_f;
		s=1;
		r=0;
		c[0]=c[1]=0;
	}
	node(){d=f=s=r=c[0]=c[1]=0;}
}tr[200000];
int n,m,root,b[100010],pos[100010];
struct data
{
	int x,y;
	data(int _x=0,int _y=0)
	{
		x=_x;
		y=_y;
	}
	bool inline friend operator<(data d1,data d2)
	{
		if(d1.x==d2.x)return d1.y<d2.y;
		return d1.x<d2.x;
	}
}a[100010],sorted[100010];
inline void update(int x)
{
	s(x)=s(c(x,0))+s(c(x,1))+1;
}
void rotate(int x)
{
	int y=f(x),z=f(y);
	bool d=(c(y,0)==x);
	f((c(y,d^1)=c(x,d)))=y;
	f((c(x,d)=y))=x;
	f(x)=z;
	if(z)c(z,c(z,1)==y)=x;
	update(y);
	update(x);
}
inline void push_down(int x)
{
	if(r(x))
	{
		if(c(x,0))r(c(x,0))^=1,swap(c(c(x,0),0),c(c(x,0),1));
		if(c(x,1))r(c(x,1))^=1,swap(c(c(x,1),0),c(c(x,1),1));
	}
	r(x)=0;
}
int dfs(int l,int r,int ff)
{
	if(l>r)return 0;
	int mid=(l+r)/2;
	int c0=dfs(l,mid-1,mid);
	int c1=dfs(mid+1,r,mid);
	tr[mid]=node(b[mid],ff);
	pos[b[mid]]=mid;
	c(mid,0)=c0;
	c(mid,1)=c1;
	update(mid);
	return mid;
}
int st[100010],top;
void splay(int x,int rt)
{
	top=0;
	for(int i=x;i;i=f(i))st[++top]=i;
	for(;top;top--)push_down(st[top]);
	while(f(x)!=rt)
	{
		int y=f(x),z=f(y);
		if(z!=rt)rotate(c(z,1)==y^c(y,1)==x?x:y);
		rotate(x);
	}
	if(rt==0)root=x;
}
int main()
{
	fread(buf,sizeof(char),sizeof(buf),stdin);
	while(n=read())
	{
		memset(tr,0,sizeof(tr));
		for(int i=1;i<=n;i++)
		{
			sorted[i]=a[i]=data(read(),i);
		} 
		sort(sorted+1,sorted+n+1);
		for(int i=1;i<=n;i++)
		{
			b[i]=lower_bound(sorted+1,sorted+n+1,a[i])-sorted;
		}
		dfs(1,n+1,0);
		root=(n+1)/2;
		for(int i=1;i<=n;i++)
		{
			splay(pos[i],0);
			int x=c(root,1);
			for(;c(x,0);x=c(x,0))push_down(x);
			splay(x,0);			
			int temp=c(root,0);
			printf("%d",s(temp)+i-1); 
			if(i!=n)printf(" ");
			r(temp)^=1;
			swap(c(temp,0),c(temp,1));
			x=root;
			for(;c(x,0);x=c(x,0))push_down(x);
			splay(x,0);
			root=c(root,1);
			f(root)=0;
		}
		cout<<endl;
	}
	return 0;
}
/*
6
3 4 5 1 6 2
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值