UVA 11922 Permutation Transformer 伸展树

Write a program to transform the permutation 1, 2, 3,..., n according to m instructions. Each instruction(ab) means to take out the subsequence from the a-th to the b-th element, reverse it, then append it to the end.

Input 

There is only one case for this problem. The first line contains two integers n and m ( 1$ \le$nm$ \le$100, 000). Each of the next m lines contains an instruction consisting of two integers a and b ( 1$ \le$a$ \le$b$ \le$n).

Output 

Print n lines, one for each integer, the final permutation.


Explanation of the sample below

Instruction (2,5): Take out the subsequence {2,3,4,5}, reverse it to {5,4,3,2}, append it to the remaining permutation {1,6,7,8,9,10}

Instruction (4,8): The subsequence from the 4-th to the 8-th element of {1,6,7,8,9,10,5,4,3,2} is {8,9,10,5,4}. Take it out, reverse it, and you'll get the sample output.


Warning: Don't use cincout for this problem, use faster i/o methods e.g scanfprintf.

Sample Input 

10 2
2 5
4 8

Sample Output 

1
6
7
3
2
4
5
10
9
8

转载请注明出处:http://blog.csdn.net/scut_pein/article/details/19935423
题意:给出排列1到n,每条指令(a,,b)表示取出第a到第b个元素,翻转后添加到排列的尾部。

思路:用两个辅助结点将1到n夹在root 和 ch[root][1] 之间。

            比如翻转l,r,只需要将l旋转为根,r+2旋转为根的儿子。那么ch[ch[root][1]][0] 就是 l + 1 到 r + 1。因为前面有一个辅助结点,所以这个区间才是要翻转的。

            删除只需要将最后一个结点旋转为根,其后面只有一个辅助结点。那么ch[root][1] 就是辅助结点。

            将删除区间放在ch[ch[root][1]][0] 即可。注意pre[]数组得更新。。。查错半天。。。

            

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100080
#define Key_value ch[ch[root][1]][0]
int n,m;
struct SplayTree
{
	int pre[maxn],key[maxn],ch[maxn][2],size[maxn],flip[maxn],root,cnt,flag;
	
	void Treaval(int x)
	{
		if(x)
		{
			PushDown(x);
			Treaval(ch[x][0]);
			printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d,key = %2d \n",x,ch[x][0],ch[x][1],pre[x],size[x],key[x]);
			Treaval(ch[x][1]);
		}
	}

	void debug()
	{
		printf("根节点:%d\n",root);
		Treaval(root);
	}
	void init()
	{
		flag = 0;
		cnt = root = 0;
		ch[0][0] = ch[0][1] = pre[0] = flip[0] = size[0] = 0;
		NewNode(root,0,0);
		NewNode(ch[root][1],0,root);
		PushUp(root);
		Buildtree(Key_value,1,n,ch[root][1]);
		PushUp(ch[root][1]);
		PushUp(root);
	}

	void NewNode(int & r,int k,int father)
	{
		r = ++cnt;
		ch[r][0] = ch[r][1] = 0;
		pre[r] = father;
		key[r] = k;
		size[r] = 1;
		flip[r] = 0;
	}

	void Update_Rev(int r)
	{
		if(!r)	return;
		swap(ch[r][0],ch[r][1]);
		flip[r] ^= 1;
	}

	void PushUp(int x)
	{
		size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
	}

	void PushDown(int x)
	{
		int l = ch[x][0],r = ch[x][1];
		if(flip[x])
		{
			Update_Rev(l);
			Update_Rev(r);
			flip[x] = 0;
		}
	}

	void Buildtree(int & r,int L,int R,int father)
	{
		if(L > R)	return;
		int mid = (L + R) >> 1;
		NewNode(r,mid,father);
		Buildtree(ch[r][0],L,mid-1,r);
		Buildtree(ch[r][1],mid+1,R,r);
		PushUp(r);
	}

	void Rotate(int x,int kind)
	{
		int y = pre[x];
		PushDown(y);
		PushDown(x);
		ch[y][!kind] = ch[x][kind];
		pre[ch[x][kind]] = y;
		if(pre[y])
			ch[pre[y]][ch[pre[y]][1] == y] = x;
		pre[x] = pre[y];
		ch[x][kind] = y;
		pre[y] = x;
		PushUp(y);
	}

	void Splay(int r,int goal)
	{
		PushDown(r);
		while(pre[r] != goal)
		{
			if(pre[pre[r]] == goal)
				Rotate(r,ch[pre[r]][0] == r);
			else 
			{
				int y = pre[r];
				int kind = (ch[pre[y]][0] == y);
				if(ch[y][kind] == r)
				{
					Rotate(r,!kind);
					Rotate(r,kind);
				}
				else 
				{
					Rotate(y,kind);
					Rotate(r,kind);
				}
			}
		}
		PushUp(r);
		if(goal == 0)	root = r;
	}

	int Get_Kth(int r,int k)
	{
		PushDown(r);
		int t = size[ch[r][0]] + 1;
		if(t == k)
			return r;
		if(t > k)
			return Get_Kth(ch[r][0],k);
		else return Get_Kth(ch[r][1],k-t);
	}

	int Get_Min(int r)
	{
		PushDown(r);
		while(ch[r][0])
		{
			r = ch[r][0];
			PushDown(r);
		}
		return r;
	}
	
	int Get_Max(int r)
	{
		PushDown(r);
		while(ch[r][1])
		{
			r = ch[r][1];
			PushDown(r);
		}
		return r;
	}

	void Reversal(int l,int r)
	{
		int x = Get_Kth(root,l);
		Splay(x,0);
		int y = Get_Kth(root,r+2);
		Splay(y,root);
		Update_Rev(Key_value);
		//printf("旋转到key_value为操作区间时:\n");
		//debug();
		int tmp = Key_value;
		Key_value = 0;//这样就删除了这段区间
		PushUp(ch[root][1]);
		PushUp(root);//更新删除
		//接下来要插入末尾。
		//printf("删除操作区间:\n");
		//debug();
		int len = r - l + 1;
		int xx = Get_Kth(root,n-len+1);
		Splay(xx,0);
		//int yy = Get_Kth(root,n-len+2);
		//Splay(yy,root);
		Key_value = tmp;
		pre[Key_value] = ch[root][1];
		PushUp(ch[root][1]);
		PushUp(root);
		//printf("插入尾部后:\n");
		//debug();
	}

	void Print(int r)
	{
		PushDown(r);
		if(ch[r][0])
			Print(ch[r][0]);
		if(key[r] != 0) 
		{
			if(!flag)	
			printf("%d",key[r]);
			else printf("\n%d",key[r]);
			flag = true;
		}
		if(ch[r][1])
			Print(ch[r][1]);
	}

	void solve()
	{
		init();
		while(m--)
		{
			int l,r;
			scanf("%d%d",&l,&r);
			Reversal(l,r);
			//printf("第一次操作后:\n");
			//debug();
		}
		Print(root);
		printf("\n");
	}
}spt;

int main()
{
	while(scanf("%d%d",&n,&m)==2)
	{
		spt.solve();
	}
	return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值