Splay tree 区间翻转 模板

Splay作为二叉平衡树与其他二叉平衡树不同的是,Splay能够支持区间操作。最然可持续化Treap也可以做到,但是代码量实在是难以同日而语。

放一个模板,只支持区间翻转。想看其他操作的可以看我的 维修数列 的博客:http://blog.csdn.net/jiangyuze831/article/details/39098481


PS:还是1A的,有点小开心……


CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

struct Complex{
	int val,size;
	bool reverse;
	Complex *son[2],*father;

	bool Check() {
		return father->son[1] == this;
	}
	void Combine(Complex *a,bool dir) {
		son[dir] = a;
		a->father = this;
	}
	void Reverse() {
        reverse ^= 1;
		swap(son[0],son[1]);
	}
}none,*nil = &none,*root = nil;

int cnt,asks;
int last;

Complex *BuildTree(int l,int r);
Complex *NewComplex(Complex *f,int x);
Complex *FindK(Complex *a,int k);
inline void Rotate(Complex *a,bool dir);
inline void Splay(Complex *a,Complex *aim);
inline void Work(int x,int y);
inline void PushUp(Complex *a);
inline void PushDown(Complex *a);
void Print(Complex *a);

int main()
{
	cin >> cnt >> asks;
	root = BuildTree(0,cnt + 1);
	root->father = nil;
	for(int x,y,i = 1;i <= asks; ++i) {
        scanf("%d%d",&x,&y);
		Work(x,y);
	}
    last = FindK(root,cnt + 1)->val;
	Print(root);
	return 0;
}

Complex *NewComplex(Complex *f,int val)
{
    Complex *re = new Complex();
    re->father = f;
    re->val = val;
    re->son[0] = re->son[1] = nil;
    re->reverse = false;
    return re;
}

Complex *BuildTree(int l,int r)
{
	if(l > r)	return nil;
	int mid = (l + r) >> 1;
	Complex *re = NewComplex(re,mid);
	re->Combine(BuildTree(l,mid - 1),false);
	re->Combine(BuildTree(mid + 1,r),true);
	PushUp(re);
	return re;
}

Complex *FindK(Complex *a,int k)
{
	PushDown(a);
	if(k <= a->son[0]->size)	return FindK(a->son[0],k);
	k -= a->son[0]->size;
	if(k == 1)	return a;
	return FindK(a->son[1],k - 1);
}

inline void Rotate(Complex *a,bool dir)
{
	Complex *f = a->father;
	PushDown(f),PushDown(a);
	f->son[!dir] = a->son[dir];
	f->son[!dir]->father = f;
	a->son[dir] = f;
	a->father = f->father;
	f->father->son[f->Check()] = a;
	f->father = a;
	PushUp(f);
    if(root == f)   root = a;
}

inline void Splay(Complex *a,Complex *aim)
{
	while(a->father != aim) {
		if(a->father->father == aim) 
			Rotate(a,!a->Check());
		else if(!a->father->Check()) {
			if(!a->Check()) {
				Rotate(a->father,true);
				Rotate(a,true);
			}
			else {
				Rotate(a,false);
				Rotate(a,true);
			}
		}
		else {
			if(a->Check()) {
				Rotate(a->father,false);
				Rotate(a,false);
			}
			else {
				Rotate(a,true);
				Rotate(a,false);
			}
		}
	}
	PushUp(a);
}

inline void Work(int x,int y)
{
	x++,y++;
	Splay(FindK(root,x - 1),nil);
	Splay(FindK(root,y + 1),root);
	root->son[1]->son[0]->Reverse();
}

inline void PushUp(Complex *a)
{
    if(a == nil)    return ;
    a->size = a->son[0]->size + a->son[1]->size + 1;
}

inline void PushDown(Complex *a)
{
    if(a->reverse) {
        a->son[0]->Reverse();
        a->son[1]->Reverse();
        a->reverse = false;
    }
}

void Print(Complex *a)
{
	if(a == nil)	return ;
    PushDown(a);
	Print(a->son[0]);
    if(a->val && a->val != cnt + 1) {
        printf("%d",a->val);
        if(a->val != last)  putchar(' ');
    }
	Print(a->son[1]);
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值