[NOI 2005] 维护数列 splay

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1500

写的比较小心,还好没有经历虐心的wa。。

数据结构的经典神题。。敲完才发现搞了200行。。


思路还是很简单的,和线段树的求最大子段和一样,左连续右连续什么的,,


对于区间操作都把这个区间转到根的右子树的左子树下。。

1、这题需要搞个内存池,开始tle还以为是姿势不对,,

2、注意NULL节点的值应该赋为-inf,还有虚拟节点1、2的值也要赋为-inf,这样才不会对其他值有影响。




#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>

using namespace std;
inline int Mid(int a,int b){return (a+b)>>1;}
#define inf 100000000
#define N 510000
#define L(x) tree[x].ch[0]
#define R(x) tree[x].ch[1]
#define Siz(x) tree[x].siz
#define Father(x) tree[x].fa
#define Val(x) tree[x].val
#define Lsum(x) tree[x].lsum
#define Rsum(x) tree[x].rsum
#define Sum(x) tree[x].sum
#define Subsum(x) tree[x].subsum
#define Filp(x) tree[x].filp
#define Cha(x) tree[x].change
struct node{
	int ch[2], siz, fa;
	int val, lsum, rsum, sum, subsum, filp;
	bool change;
}tree[N];
int tot, root;
int num[N], hehe;//内存池
void Newnode(int &id, int val, int fa, int siz = 1){
	if(hehe)id = num[hehe--];
	else
	id = ++tot;
	L(id) = R(id) = 0;
	Father(id) = fa;
	Siz(id) = siz;
	Val(id) = Sum(id) = Subsum(id) = Lsum(id) = Rsum(id) = val;
	Cha(id) = Filp(id) = 0;
}
void Change(int id, int v){
	if(id == 0)return;
	Cha(id) = 1;
	Val(id) = v;
	Sum(id) = v*Siz(id);
	Lsum(id) = Rsum(id) = Subsum(id) = max(v,Sum(id));
}
void Filp_id(int id){
	if(id == 0)return ;
	Filp(id) ^= 1;
	swap(Lsum(id), Rsum(id));
	swap(L(id), R(id));
}

void push_up(int id){
	Siz(id) = Siz(L(id)) + Siz(R(id)) +1;
	Sum(id) = Sum(L(id)) + Sum(R(id)) + Val(id);
	Lsum(id) = max(Lsum(L(id)), Sum(L(id)) + Val(id));
	Lsum(id) = max(Lsum(id), Sum(L(id)) + Val(id) + Lsum(R(id)));

	Rsum(id) = max(Rsum(R(id)), Sum(R(id)) + Val(id));
	Rsum(id) = max(Rsum(id), Sum(R(id)) + Val(id) + Rsum(L(id)));

	Subsum(id) = max(Val(id), max(Subsum(L(id)), Subsum(R(id))));
	Subsum(id) = max(Subsum(id), max(Lsum(R(id))+Val(id), Rsum(L(id))+Val(id)));

	Subsum(id) = max(Subsum(id), Lsum(R(id)) + Rsum(L(id))+Val(id));
}
void push_down(int id){
	if(Filp(id)){
		Filp(id) = 0;
		Filp_id(L(id));
		Filp_id(R(id));
	}
	if(Cha(id)){
		Cha(id) = 0;
		Change(L(id), Val(id));
		Change(R(id), Val(id));
	}
}

void Rotate(int id, int kind){
	int y = Father(id);
	push_down(y); push_down(id); //here
	tree[y].ch[kind^1] = tree[id].ch[kind];
	Father(tree[id].ch[kind]) = y;
	if(Father(y))
		tree[Father(y)].ch[R(Father(y))==y] = id;
	Father(id) = Father(y);
	Father(y) = id;
	tree[id].ch[kind] = y;
	push_up(y);
}
void splay(int id, int goal){
	push_down(id);
	while(Father(id) != goal){
		int y = Father(id);
		if(Father(y) == goal)
			Rotate(id, L(y)==id);
		else
		{
			int kind = L(Father(y)) == y;
			if(tree[y].ch[kind] == id)
			{
				Rotate(id, kind^1);
				Rotate(id, kind);
			}
			else
			{
				Rotate(y, kind);
				Rotate(id,kind);
			}
		}
	}
	push_up(id);
	if(goal == 0)root = id;
}
int Get_kth(int kth, int sor){//找到在sor后面的第k个数
	push_down(sor);
	int id = sor;
	while(Siz(L(id)) != kth){
		if(Siz(L(id)) > kth)
			id = L(id);
		else 
		{
			kth -= (Siz(L(id))+1);
			id = R(id);
		}
		push_down(id);
	}
	return id;
}
void Get_sec(int l, int r){//把区间[l,r]转到L(R(root))
	splay(Get_kth(l-1,root), 0);
	splay(Get_kth(r+1, root), root);
}
//------------------------------------------
int a[N], top;
void build(int l, int r, int &id, int fa, int *a){
	if(l>r)return;
	int mid = Mid(l, r);
	Newnode(id, a[mid], fa);
	build(l, mid-1, L(id), id, a);
	build(mid+1, r, R(id), id, a);
	push_up(id);
}
//--------------------------------------------
void Insert(int kth){//把Stack加到kth下
	Get_sec(kth+1,kth);
	build(0, top-1, L(R(root)), R(root), a);
	push_up(R(root));
	push_up(root);
}
void Filp_sec(int l, int r){
	Get_sec(l, r);
	Filp_id(L(R(root)));
	push_up(R(root));
	push_up(root);
}
void Erase(int id){//内存回收
	if(!id)return;
	num[++hehe] = id;
	Erase(L(id));
	Erase(R(id));
}
void Del_sec(int l, int r){//删除这个区间
	Get_sec(l,r);
	Erase(L(R(root)));
	L(R(root)) = 0;
	push_up(R(root));
	push_up(root);
}
void Change_sec(int l, int r, int v){
	Get_sec(l,r);
	Change(L(R(root)), v);
	push_up(R(root)); 
	push_up(root);
}
int Max_sum(){
	return Subsum(root);
}
int Get_sum(int l, int r){
	Get_sec(l, r);
	return Sum(L(R(root)));
}
char s[20];
int n, m;

void init(){
	hehe = 0;
	tot = root = 0;
	L(0) = R(0) = Siz(0) = Father(0) = 0;
	Val(0) = Sum(0) =  0;
	Subsum(0) = Lsum(0) = Rsum(0) = -inf;
	Newnode(root, -inf, 0);
	Newnode(R(root), -inf, root);
	build(1, n, L(R(root)), R(root), a);
	push_up(R(root));	push_up(root);
}
int main(){
	int i, j, k;
	while(~scanf("%d %d",&n,&m)){
		for(i = 1; i <= n; i++)scanf("%d",&a[i]);
		init();
		while(m--)
		{
			scanf("%s",s);
			if(s[0] == 'I')
			{
				scanf("%d %d",&i,&top);
				for(j = 0; j < top; j++)scanf("%d",&a[j]);
				Insert(i);
			}
			else if(s[0] == 'D')
			{
				scanf("%d %d",&i,&j);
				Del_sec(i, i+j-1);
			}
			else if(s[2] == 'K')
			{
				scanf("%d %d %d",&i,&j,&k);
				Change_sec(i,i+j-1,k);
			}
			else if(s[0] == 'R')
			{
				scanf("%d %d",&i,&j);
				Filp_sec(i,i+j-1);
			}
			else if(s[0] == 'G')
			{
				scanf("%d %d",&i,&j);
				printf("%d\n",Get_sum(i,i+j-1));
			}
			else
				printf("%d\n",Max_sum());
		}
	}
	return 0;
}
/*
9 8

2 -6 3 5 1 -5 -3 6 3

GET-SUM 5 4

MAX-SUM

INSERT 8 3 -5 7 2

DELETE 12 1

MAKE-SAME 3 3 2

REVERSE 3 6

GET-SUM 5 4

MAX-SUM

*/


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值