现在的位置: 首页 > 综合 > 正文

BZOJ 1251 序列终结者 Splay

2018年01月19日 ⁄ 综合 ⁄ 共 2534字 ⁄ 字号 评论关闭

题目大意:维护区间的最大值,要求可以区间翻转和区间加减。

思路:弱化版的1500,好长时间没写带标记的Splay了,错误重重。这个题可以当作带标记的Splay模板了。

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
#define WORKPATH (root->son[1]->son[0])
using namespace std;

struct SplayTree{
	int val,size;
	int change,_max;
	bool reverse;
	SplayTree *son[2],*father;
	
	SplayTree(int _);
	bool Check() {
		return father->son[1] == this;
	}
	void Combine(SplayTree *a,bool dir) {
		son[dir] = a;
		a->father = this;
	}
	void Plus(int c);
	void Reverse();
	void PushUp();
	void PushDown();
}none(0),*nil = &none,*root;
SplayTree:: SplayTree(int _) {
	val = _;
	size = 1;
	_max = change = 0;
	reverse = false;
	son[0] = son[1] = nil;
}
void SplayTree:: Plus(int c) {
	if(this == nil)	return ;
	change += c;
	val += c;
	_max += c;
}
void SplayTree:: Reverse() {
	if(this == nil)	return ;
	reverse ^= 1;
	swap(son[0],son[1]);
}
void SplayTree:: PushUp() {
	if(this == nil)	return ;
	size = son[0]->size + son[1]->size + 1;
	_max = max(val,max(son[0]->_max,son[1]->_max));
}
void SplayTree:: PushDown() {
	if(this == nil)	return ;
	if(change) {
		son[0]->Plus(change);
		son[1]->Plus(change);
		change = 0;
	}
	if(reverse) {
		son[0]->Reverse();
		son[1]->Reverse();
		reverse = false;
	}
}

int cnt,asks;

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

void Pretreatment()
{
	nil->size = 0;
	nil->father = nil;
	nil->val = nil->_max = -INF;
	root = BuildTree(0,cnt + 1);
	root->father = nil;
}

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

inline void Splay(SplayTree *a,SplayTree *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);
		}
	}
	a->PushUp();
}

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

inline void SplaySeg(int x,int y)
{
	x++,y++;
	Splay(Kth(root,x - 1),nil);
	Splay(Kth(root,y + 1),root);
}

int main()
{
	cin >> cnt >> asks;
	Pretreatment();
	for(int flag,x,y,z,i = 1; i <= asks; ++i) {
		scanf("%d",&flag);
		if(flag == 1) {
			scanf("%d%d%d",&x,&y,&z);
			SplaySeg(x,y);
			WORKPATH->Plus(z);
			root->son[1]->PushUp();
			root->PushUp();
		}
		else if(flag == 2) {
			scanf("%d%d",&x,&y);
			SplaySeg(x,y);
			WORKPATH->Reverse();
		}
		else {
			scanf("%d%d",&x,&y);
			SplaySeg(x,y);
			printf("%d\n",WORKPATH->_max);
		}
	}
	return 0;
}

抱歉!评论已关闭.