[HDU1890] Robotic Sort(Splay)

前言

适合入门但其实不算很裸的平衡树题

题目

洛谷

HDU

讲解

在做这道题之前,最好先康康这道更板的题:

P3391 【模板】文艺平衡树

对于这道题,模拟就完事了

我使用平衡树是\(Splay\)

这道题的难点就在如何快速找到排名第\(i\)个数的位置

至于\(reverse\)操作,在板题中应该已经熟悉了

其实很简单,只需要将每个数与其对应在\(Splay\)上的点的编号记录下来,当你需要找到它的位置的时候,将它\(splay\)到根即可,它的位置就是左儿子大小+1

注意我们插入的\(1\)\(n+2\)两个哨兵对各种造成的影响

同时注意输出格式,末尾不能有多余空格

代码

int ID[MAXN];
struct number
{
	int x,pos;
}num[MAXN];

bool cmp1(number a,number b)
{
	if(a.x != b.x) return a.x < b.x;
	return a.pos < b.pos;
}
bool cmp2(number a,number b)
{
	return a.pos < b.pos;
}

#define lc t[x].ch[0]
#define rc t[x].ch[1]
struct Splay
{
	int tot,rt;//点,根
	
	struct node
	{
		int ch[2],val,f,siz,cnt;//儿子,value,父亲,size,count
		bool fz;//翻转标记 
	}t[MAXN];
	
	int newnode(int fa,int val)
	{
		++tot;
		t[tot].ch[0] = t[tot].ch[1] = 0;
		t[tot].siz = t[tot].cnt = 1;
		t[tot].val = val;
		t[tot].f = fa;
		t[tot].fz = 0;
		return tot;
	}
	bool chk(int x)//判断是左儿子还是右儿子 
	{
		return t[t[x].f].ch[1] == x;
	}
	void up(int x)
	{
		t[x].siz = t[lc].siz + t[rc].siz + t[x].cnt;
	}
	void down(int x)
	{
		if(!t[x].fz) return;
		t[x].fz = 0;
		t[lc].fz ^= 1;
		t[rc].fz ^= 1;
		swap(lc,rc);
	}
	int Build(int fa,int l,int r)
	{
		if(l > r) return 0;
		int mid = (l+r) >> 1;
		int x = newnode(fa,num[mid].x);
		ID[num[mid].x] = x;//记录对应在平衡树上点的编号
		lc = Build(x,l,mid-1);rc = Build(x,mid+1,r);
		up(x);
		return x;
	}
	void rotate(int x)
	{
		down(t[x].f);down(x);
		int y = t[x].f,z = t[t[x].f].f;
		bool cz = chk(y),cy = chk(x);
		t[x].f = z; t[z].ch[cz] = x;
		t[y].ch[cy] = t[x].ch[cy^1]; t[t[x].ch[cy^1]].f = y;
		t[x].ch[cy^1] = y; t[y].f = x;
		up(y);up(x);
	}
	void splay(int x,int to = 0)
	{
		while(t[x].f != to)
		{
			int y = t[x].f,z = t[t[x].f].f;
			if(z != to)//双旋 
			{
				if(chk(x) == chk(y)) rotate(y);
				else rotate(x);
			}
			rotate(x);
		}
		if(!to) rt = x;//记得改根 
	}
	int kth(int k)
	{
		int x = rt;
		while(1)
		{
			down(x);
			if(t[lc].siz >= k) x = lc;
			else if(t[lc].siz + t[x].cnt < k) k -= t[lc].siz + t[x].cnt,x = rc;
			else return x;
		}
	}
	void reverse(int l,int r)
	{
		if(l == r) return;
		l = kth(l-1);r = kth(r+1);
		splay(l);splay(r,l);
		t[t[r].ch[0]].fz ^= 1;
	}
	void print(int x)
	{
		if(!x) return;
		down(x);
		print(lc);
		Put(t[x].val,'\n');
		print(rc);
	}
}S;

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);	
	while(~scanf("%d",&n) && n)
	{
		S.tot = 0;
		for(int i = 2;i <= n+1;++ i)
			num[i].x = Read(),num[i].pos = i;
		sort(num+2,num+n+2,cmp1);
		num[1].pos = 1;num[n+2].pos = n+2;
		for(int i = 1;i <= n+2;++ i)
			num[i].x = i;
		sort(num+1,num+n+3,cmp2);
		S.rt = S.Build(0,1,n+2);
		for(int i = 2;i <= n+1;++ i)
		{
			S.splay(ID[i]);
			int pos = S.t[S.t[S.rt].ch[0]].siz;
			Put(pos);
			if(i == n+1) putchar('\n');
			else putchar(' ');
			S.reverse(i,pos+1);
		} 
	}
	return 0;
}
posted @ 2020-09-11 09:01  皮皮刘  阅读(152)  评论(0编辑  收藏  举报