POJ 3580 SuperMemo Splay 区间维护

题目大意:维护一种数据结构,它支持以下功能:

1.ADD:从第x个点到第y个点每个点加z。

2.REVERSE:将序列的x到y翻转。

3.REVOLVE:处理序列x到y,把它的最后一个值放在第一个位置。重复这样的操作z次。

4.INSERT:在第x个数后面加入一个数p

5.DELETE:把序列第x个数删除。

6.MIN:求出序列x到y中的最小值。


思路:除了REVOLVE以外的操作都是SPLAY的常规操作,正常写就可以。REVOLVE也十分简单。只要算好两边端点的值,把它提到root->son[1]->son[0]上拿出来,再进行一些Splay操作,把刚才从树中取出的序列插入到树中就可以。

关于负数取模:REVOLVE中给出的值有可能是负的,只需要((a % MO) + MO) % MO就可以得到正确的正值


CODE:


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 100010
#define INF 0x3f3f3f3f
using namespace std;

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

	int c;
	bool reverse;

	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]);
	}
	void Plus(int num) {
		val += num;
		c += num;
		_min += num;
	}
}none,*nil = &none,*root;

int cnt;
int src[MAX];
	 
char s[20];

void Pretreatment();

Complex *BuildTree(int l,int r);
inline Complex *NewComplex(int val);
Complex *Kth(Complex *a,int k);

inline void PushUp(Complex *a);
inline void PushDown(Complex *a);

inline void Rotate(Complex *a,bool dir);
inline void Splay(Complex *a,Complex *aim);
inline void SplaySeg(int l,int r);

int main()
{
	Pretreatment();
	cin >> cnt;
	for(int i = 1;i <= cnt; ++i)
		scanf("%d",&src[i]);
	src[0] = src[cnt + 1] = INF;
	root = BuildTree(0,cnt + 1);
	root->father = nil;
	cin >> cnt;
	for(int x,y,z,i = 1;i <= cnt; ++i) {
		scanf("%s",s);
		if(!strcmp(s,"ADD")) {
			scanf("%d%d%d",&x,&y,&z);
			SplaySeg(x,y);
			root->son[1]->son[0]->Plus(z);
			PushUp(root->son[1]),PushUp(root);
		}
		if(!strcmp(s,"REVERSE")) {
			scanf("%d%d",&x,&y);
			SplaySeg(x,y);
			root->son[1]->son[0]->Reverse();
		}
		if(!strcmp(s,"REVOLVE")) {
			scanf("%d%d%d",&x,&y,&z);
			int cnt = y - x + 1;
			z =  ((z % cnt) + cnt) % cnt;
			SplaySeg(y - z + 1,y);
			Complex *temp = root->son[1]->son[0];
			root->son[1]->son[0]->father = nil;
			root->son[1]->son[0] = nil;
			PushUp(root->son[1]),PushUp(root);
			Splay(Kth(root,x),nil);
			Splay(Kth(root,x + 1),root);	
			root->son[1]->Combine(temp,false);
			PushUp(root->son[1]),PushUp(root);
		}
		if(!strcmp(s,"INSERT")) {
			scanf("%d%d",&x,&y);
			Splay(Kth(root,x + 1),nil);
			Splay(Kth(root,x + 2),root);
			root->son[1]->Combine(NewComplex(y),false);
			PushUp(root->son[1]),PushUp(root);
		}
		if(!strcmp(s,"DELETE")) {
			scanf("%d",&x);
			SplaySeg(x,x);
			root->son[1]->son[0]->father = nil;
			root->son[1]->son[0] = nil;
			PushUp(root->son[1]),PushUp(root);
		}
		if(!strcmp(s,"MIN")) {
			scanf("%d%d",&x,&y);
			SplaySeg(x,y);
			printf("%d\n",root->son[1]->son[0]->_min);
		}
	}
	return 0;
}

void Pretreatment()
{
	nil->son[0] = nil->son[1] = nil->father = nil;
	nil->_min = INF;
}

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

inline Complex *NewComplex(int val)
{
	Complex *re = new Complex();
	re->son[0] = re->son[1] = nil;
	re->reverse = false;
	re->c = 0;
	re->size = 1;
	re->_min = re->val = val;
	return re;
}

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

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

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 SplaySeg(int l,int r)
{
	l++,r++;
	Splay(Kth(root,l - 1),nil);
	Splay(Kth(root,r + 1),root);
}

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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值