hdoj 1890 Robotic Sort

这道题的splay没有权值,其偏序关系在建完树之后就确定了,所以翻转操作直接交换俩个孩子的指针即可,因为没有权值,也就不用去修改,这样很简单的就改变了该子树的偏序关系,而且可以使用懒惰标记,每次只要把该值所对应的节点旋转到树根然后显示root->size+i(i为该节点排完序后位置,因为每次都会删除排好序的的节点,所以是+i),因为树没有权值,就算我们把每个节点都增加一个域来记录其所对应的数,由于树并不是按该值大小作为关系的,所以也就无法高效的进行查找了,为了解决这个问题,我们在建树时就记录每个数所对应节点的指针,之后直接把该指针所对应节点直接splay到根即可,要小心因为这次的节点不是从上到下select出来的,也就没有把其所有祖先的状态push_down下来,所以splay该指针之前要先回溯到根,然后依次push_dwon下来,即sweep函数(一开始没加开栈的预处理,导致stack overflow了,为了保险最好还是改成迭代的形式)需要注意的是为了方便我们添加了俩个卫兵节点,一个是最小,一个是最大,而进行翻转时,不能改变这俩个节点的关系,所以要确保要翻转的子树中没有这俩个卫兵节点,详细见代码注释

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>
#include <map>
#include <string>
#include <climits> 
#include <set>
#include <string> 
#include <sstream>
#include <utility>
#include <ctime>
#pragma comment(linker, "/STACK:102400000,102400000")  //开栈

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::getline;
using std::make_pair;
using std::greater;




const int MAXN(100010);

struct SPLAY_TREE
{
	struct NODE
	{
		int reverse;
		int size;
		NODE *fa;
		NODE *ch[2];
	};

	NODE pool[MAXN];
	NODE *rear, *root, *NIL;
	int cnt;

	void newnode(NODE *&sour, NODE *f)
	{
		rear->size = 1;
		rear->reverse = 0;
		rear->ch[0] = rear->ch[1] = NIL;
		rear->fa = f;
		sour = rear++;
	}

	void init()
	{
		NIL = pool;
		NIL->fa = NIL->ch[0] = NIL->ch[1] = NIL;
		NIL->size = 0;
		NIL->reverse = 0;
		rear = pool+1;
		newnode(root, NIL);
	}

	void push_down(NODE *sour)
	{
		if(sour->reverse)
		{
			sour->ch[0]->reverse ^= 1;
			sour->ch[1]->reverse ^= 1;
			swap(sour->ch[0], sour->ch[1]);
			sour->reverse = 0;
		}
	}

	void push_up(NODE *sour)
	{
		sour->size = sour->ch[0]->size+sour->ch[1]->size+1;
	}

	void rotate(NODE *sour, int flag)
	{
		NODE *f = sour->fa;
		push_down(f);
		push_down(sour);
		f->ch[!flag] = sour->ch[flag];
		sour->ch[flag]->fa = f;
		sour->fa = f->fa;
		if(f->fa != NIL)
			f->fa->ch[f->fa->ch[1] == f] = sour;
		sour->ch[flag] = f;
		f->fa = sour;
		push_up(f);
	}

	void splay(NODE *sour, NODE *goal)
	{
		push_down(sour);
		while(sour->fa != goal)
		{
			if(sour->fa->fa == goal)
				rotate(sour, sour->fa->ch[0] == sour);
			else
			{
				NODE *f = sour->fa;
				int flag = f->fa->ch[0] == f;
				if(f->ch[flag] == sour)
					rotate(sour, !flag);
				else
					rotate(f, flag);
				rotate(sour, flag);
			}
		}
		push_up(sour);
		if(goal == NIL)
			root = sour;
	}

	NODE *extreme(NODE *sour, int flag)
	{
		push_down(sour);
		while(sour->ch[flag] != NIL)
		{
			sour = sour->ch[flag];
			push_down(sour);
		}
		return sour;
	}

	NODE *insert()
	{
		NODE *sour = extreme(root, 1);
		newnode(sour->ch[1], sour);
		splay(sour->ch[1], NIL);
		return root;
	}

	void sweep(NODE *sour)
	{
		if(sour == NIL)
			return;
		sweep(sour->fa);
		push_down(sour);
	}

	int find(NODE *sour)
	{
		sweep(sour);
		splay(sour, NIL);
		int ret = sour->ch[0]->size;
		NODE *p1, *p2;
		p1 = extreme(sour->ch[0], 0);      // 防止卫兵节点翻转
		splay(p1, NIL);			   // 防止卫兵节点翻转
		splay(sour, root);		   // 防止卫兵节点翻转
		sour->ch[0]->reverse ^= 1;
		splay(sour, NIL);
		p1 = extreme(sour->ch[0], 1);
		p2 = extreme(sour->ch[1], 0);
		splay(p1, NIL);
		splay(p2, root);
		p2->ch[0] = NIL;
		push_up(p2);
		push_up(p1);
		return ret;
	}
};

SPLAY_TREE spt;

struct ELE
{
	int num, rank;
	SPLAY_TREE::NODE *ptr; 
	bool operator < (const ELE &op)
	{
		if(num == op.num)
			return rank < op.rank;
		else
			return num < op.num;
	}
};

ELE ele[MAXN];

int main()
{
	int n;
	while(scanf("%d", &n), n)
	{
		spt.init();
		for(int i = 0; i < n; ++i)
		{
			scanf("%d", &ele[i].num);
			ele[i].rank = i;
			ele[i].ptr = spt.insert();
		}
		spt.insert();
		sort(ele, ele+n);
		bool print_s(false);
		for(int i = 0; i < n; ++i)
		{
			if(print_s)
				printf(" ");
			printf("%d", spt.find(ele[i].ptr)+i);
			print_s = true;
		}
		printf("\n");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值