【hdu3487】【splay】Play with Chain

本文详细介绍了一种基于Splay树的数据结构实现方法及其在解决特定类型问题中的应用。通过具体的例子,阐述了如何利用Splay树进行区间操作,包括区间提取、插入以及翻转等。同时提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意是一串链子,要求支持两项操作:

1、从链子中切下a-b区间,然后整体插入位置k的数的后面(注意这里的k是对于切下之后的位置k)。

2、翻转a-b这个区间的数

这道题是典型的splay题目

具体操作就是:先提取出a-b这一段区间,然后记录一下区间位置,并且清除,然后再提取出第k个数,插入即可。

第二个操作则是使用lazy标记,不断交换左右子树,实现翻转。

代码:

#include<cstdio>
#include<cstring>
#define keyTree ch[ ch[root][1] ][0]
using namespace std;
const int maxn = 300000 + 10;
int n,m;
int num;
int root,top;
struct SplayTree
{
	int ch[maxn][2],pre[maxn];
	int val[maxn],sz[maxn];
	bool reserve[maxn];
	void push_up(int x)
	{
		sz[x] = sz[ ch[x][0] ] + sz[ ch[x][1] ] + 1;
	}
	void swap(int &a,int &b)
	{
		int t = a;a = b;b = t;
	}
	void push_down(int x)
	{
		if(reserve[x])
		{
			if(ch[x][0])reserve[ ch[x][0] ] = !reserve[ ch[x][0] ];
			if(ch[x][1])reserve[ ch[x][1] ] = !reserve[ ch[x][1] ];
			swap(ch[x][0],ch[x][1]);
			reserve[x] = false;
		}
	}
	void Rotate(int x,int f)
	{
		int y = pre[x];
		push_down(y);
		push_down(x);
		ch[y][!f] = ch[x][f];
		pre[ ch[x][f] ] = y;
	    pre[x] = pre[y];
		if(pre[x])ch[ pre[x] ][ ch[pre[x]][1] == y ] = x;
		ch[x][f] = y;
		pre[y] = x;
		push_up(y);	
	}
	void Splay(int x,int goal)
	{
		push_down(x);
		while(pre[x] != goal)
		{
			if(pre[pre[x]] == goal)Rotate(x,ch[pre[x]][0] == x);
			else
			{
				int y = pre[x],z = pre[y];
				int f = (ch[z][0] == y);
				if(ch[y][f] == x)Rotate(x, !f),Rotate(x ,f);
				else Rotate(y,f),Rotate(x,f);
			}
		}
		push_up(x);
		if(goal == 0)root = x;
	}
	void RotateTo(int k,int goal)
	{
		int x = root;
		push_down(x);
		while(sz[ ch[x][0] ] != k)
		{
			if(k < sz[ ch[x][0] ])x = ch[x][0];
			else
			{
				k -= (sz[ ch[x][0] ] + 1);
				x = ch[x][1];
			}
			push_down(x);
		}
		Splay(x,goal);
	}
	void work(int l,int r,int k)
	{
		RotateTo(l - 1,0);
		RotateTo(r + 1,root);
		int tmp = keyTree;
		keyTree = 0; 
		push_up(ch[root][1]);
		push_up(root);
		RotateTo(k,0);
		RotateTo(k + 1,root);
		keyTree = tmp;
		pre[tmp] = ch[root][1];
		push_up(keyTree);
		push_up(root);
	}
	void res(int l,int r)
	{
		RotateTo(l - 1,0);
		RotateTo(r + 1,root);
		reserve[ keyTree ] = !reserve[ keyTree ]; 
	}
	void output(int x,int n)
	{
		push_down(x);
		if(ch[x][0])output(ch[x][0],n);
		if(val[x] >= 1 && val[x] <= n)
		{
			num++;
			if(num == 1)printf("%d",val[x]);
			else printf(" %d",val[x]);
		}
		if(ch[x][1])output(ch[x][1],n);
	}
	void Newnode(int &x,int c)
	{
		x = ++top;
		ch[x][0] = ch[x][1] = pre[x] = 0;
		reserve[x] = false;
		val[x] = c;
		sz[x] = 1;
	}
	void makeTree(int &x,int l,int r,int f)
	{
		if(l > r)return;
		int m = (l + r) >> 1;
		Newnode(x,m);
		makeTree(ch[x][0],l,m - 1,x);
		makeTree(ch[x][1],m + 1,r,x);
		pre[x] = f;
		push_up(x);
	}
	void init()
	{
		memset(ch,0,sizeof(ch));
		memset(pre,0,sizeof(pre));
		memset(val,0,sizeof(val));
		ch[0][0] = ch[0][1] = pre[0] = sz[0] = 0;
		root = top = 0;
		Newnode(root,-1);
		Newnode(ch[root][1],-1);
		pre[ch[root][1]] = root;
		makeTree(keyTree,1,n,ch[root][1]);
		push_up(ch[root][1]);
		push_up(root);
	}
}Spt;
void init()
{
	freopen("hdu3487.in","r",stdin);
	freopen("hdu3487.out","w",stdout);
}

void readdata()
{
	while(scanf("%d%d",&n,&m) != EOF)
	{
		if(n == -1 && m == -1)continue;
		Spt.init();
		for(int i = 1;i <= m;i++)
		{
			char op[2];
			int l,r;
			scanf("%s",op);
			if(op[0] == 'C')
			{
				int k;
				scanf("%d%d%d",&l,&r,&k);
				Spt.work(l,r,k);
			}
			else
			{
				scanf("%d%d",&l,&r);
				Spt.res(l,r);
			}
		}
		num = 0;
		Spt.output(root,n);
		printf("\n");
	}
}

int main()
{
	init();
	readdata();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值