[NOI2005]维修数列

立flag以后滚去复习会考

然后会考一坨翔

然后边颓边写,边颓边改......然后就过了

然后发现跑的还挺快

顺便YM在THU虐场的faebdc

----------------------------------------------------------

Splay对于区间的操作就是用子树来表示区间

然后一个很好的性质是无论怎么转小的总是在左边

于是用相对位置来表示在数组中的下标

最大子段和比较蛋疼

要考虑好多情况

Reverse的时候一定不要忘记swap(LMax, RMax)!!!!!!!!!!

建树用了递归(我很弱)

如果还有问题或者觉得代码风格鬼畜请在下面留言

说实话数据结构题的题解真的不必要......

被坑的地方还是要发出来的

还有GET-SUM的区间长度可能是0

Code:

#include <cstdio>
#include <queue>
using namespace std;
queue<int> Q;
struct Splay_Tree
{
	Splay_Tree *F, *Ls, *Rs;
	int Size, Reverse, All, Sum, Key, LMax, RMax, Max;
	inline void Clear()
	{
		Size = Reverse = Sum = Key = LMax = RMax = Max = 0;
		F = Ls = Rs = NULL;
		All = 23333;
	}
	inline void Init(int x)
	{
		Key = Sum = LMax = RMax = Max = x;
		Size = 1;
	}
	inline void Update()
	{
		Pushdown();
//		puts("");
//		Debug();
		Sum = Key, Size = 1;
		Max = LMax = RMax = Key;
		if (Ls && Rs)
		{
			Ls->Pushdown();
			Rs->Pushdown();
			Size += Ls->Size, Sum += Ls->Sum;
			Size += Rs->Size, Sum += Rs->Sum;
			LMax = max(max(max(Ls->LMax, Ls->Sum+Key), Ls->Sum+Key+Rs->LMax), Ls->Sum+Key+Rs->Sum);
			RMax = max(max(max(Rs->RMax, Rs->Sum+Key), Rs->Sum+Key+Ls->RMax), Rs->Sum+Key+Ls->Sum);
			Max = max(max(max(max(max(max(max(Key, Ls->RMax+Key+Rs->LMax), Ls->RMax+Key), Ls->Max), Rs->Max), Key+Rs->LMax), LMax), RMax);
			return;
		}
		if (Ls)
		{
			Ls->Pushdown();
			Size += Ls->Size, Sum += Ls->Sum;
			LMax = max(Ls->LMax, Ls->Sum+Key);
			RMax = max(max(Ls->RMax+Key, Ls->Sum+Key), Key);
			Max = max(max(Ls->Max, RMax), LMax);
			return;
		}
		if (Rs)
		{
			Rs->Pushdown();
			Size += Rs->Size, Sum += Rs->Sum;
			RMax = max(Rs->RMax, Rs->Sum+Key);
			LMax = max(max(Rs->LMax+Key, Rs->Sum+Key), Key);
			Max = max(max(Rs->Max, RMax), LMax);
			return;
		}
	}
	inline void Zig()
	{
		Pushdown();
		if (F)
		{
			Splay_Tree *p = F;
			p->Ls = Rs;
			if (Rs)Rs->F = p;
			Rs = p;
			F = p->F;
			p->F = this;
			p->Update();
			Update();
			if (F)
			{
				if (p == F->Ls)
					F->Ls = this;
				else
					F->Rs = this;
				F->Update();
			}
		}
		else
			puts("´óɵ±Æ");
	}
	inline void Zag()
	{
		Pushdown();
		if (F)
		{
			Splay_Tree *p = F;
			p->Rs = Ls;
			if (Ls)Ls->F = p;
			Ls = p;
			F = p->F;
			p->F = this;
			p->Update();
			Update();
			if (F)
			{
				if (p == F->Ls)
					F->Ls = this;
				else
					F->Rs = this;
				F->Update();
			}
		}
		else
			puts("´óɵ±Æ");
	}
	inline void Pushdown()
	{
		if (Reverse)
		{
			Reverse = 0;
			swap(Ls, Rs);
			swap(LMax, RMax);
			if (Ls)Ls->Reverse ^= 1;
			if (Rs)Rs->Reverse ^= 1;
		}
		if (All != 23333)
		{
			Key = All;
			Sum = Size * All;
			if (All > 0)
				LMax = RMax = Max = Sum;
			else
				LMax = RMax = Max = All;
			if (Ls)Ls->All = All;
			if (Rs)Rs->All = All;
			All = 23333;
		}
	}
	inline void Debug()
	{
		Pushdown();
		if (Ls)Ls->Debug();
		printf("%d ", Key);
		if (Rs)Rs->Debug();
	}
}*Root, T[500001];
int n, m, Number[200001];
inline Splay_Tree *New(int x)
{
	if (Q.empty())
	{
		puts("´óɵ±Æ");
		return NULL;
	}
	Splay_Tree *p = &T[Q.front()];
	Q.pop();
	p->Clear();
	p->Init(x);
	return p;
}
inline void Splay(Splay_Tree *s, Splay_Tree *t)
{
	if (!s || s == t)return;
	if (t == NULL)Root = s;
	while (s->F != t)
	{
		s->Pushdown();
		if (s->F->F == t)
		{
			if (s == s->F->Ls)
				s->Zig();
			else
				s->Zag();
		}
		else
		{
			if (s->F->F->Ls == s->F)
			{
				if (s->F->Ls == s)
					s->F->Zig(), s->Zig();
				else
					s->Zag(), s->Zig();
			}
			else
			{
				if (s->F->Ls == s)
					s->Zig(), s->Zag();
				else
					s->F->Zag(), s->Zag();
			}
		}
	}
}
inline Splay_Tree *Select(Splay_Tree *p, int x)
{
	if (!p)return p;
	p->Pushdown();
	int now(1);
	if (p->Ls)now += p->Ls->Size;
	if (x == now)
		return p;
	if (x > now)
		return Select(p->Rs, x-now);
	return Select(p->Ls, x);
}
inline Splay_Tree *Build(int l, int r, int *a)
{
	if (l > r)return 0;
	int mid = (l + r) >> 1;
	Splay_Tree *p = New(a[mid]);
	p->Ls = Build(l, mid-1, a), p->Rs = Build(mid+1, r, a);
	if (p->Ls)p->Ls->F = p;
	if (p->Rs)p->Rs->F = p;
	p->Update();
	return p; 
}
inline void Insert(int x, int len, int *a)
{
	n += len;
	if (!Root)
	{
		Root = Build(1, len, a);
		return;
	}
	if (!x)
	{
		Splay(Select(Root, 1), Root->F);
		Root->Ls = Build(1, len, a);
		Root->Update();
		Root->Ls->F = Root;
		return;
	}
	if (x == n-len)
	{
		Splay(Select(Root, x), Root->F);
		Root->Rs = Build(1, len, a);
		Root->Update();
		Root->Rs->F = Root;
		return;
	}
	Splay(Select(Root, x), Root->F), Splay(Select(Root, x+1), Root);
	Root->Rs->Ls = Build(1, len, a);
	Root->Rs->Ls->F = Root->Rs;
	Root->Pushdown();
	Root->Rs->Pushdown();
	//Splay(Root->Rs->Ls, Root->F);
	Root->Rs->Update();
	Root->Update();
}
inline void Delete(Splay_Tree *s)
{
	if (s->Ls)
		Delete(s->Ls), s->Ls = NULL;
	if (s->Rs)
		Delete(s->Rs), s->Rs = NULL;
	Q.push(s-&T[0]);
	n--;
}
inline void Delete(int l, int r)
{
	if (l == 1 && r == n)
	{
		Delete(Root);
		Root = NULL;
		return;
	}
	if (l == 1)
	{
		Splay(Select(Root, r+1), Root->F);
		Delete(Root->Ls);
		Root->Ls = NULL;
		Root->Update();
		return;
	}
	if (r == n)
	{
		Splay(Select(Root, l-1), Root->F);
		Delete(Root->Rs);
		Root->Rs = NULL;
		Root->Update();
		return;
	}
	Splay(Select(Root, l-1), Root->F);
	Splay(Select(Root, r+1), Root);
	Delete(Root->Rs->Ls);
	Root->Rs->Ls = NULL;
	Root->Rs->Update();
	Root->Update();
}
inline void MakeSame(int l, int r, int x)
{
	if (l == 1 && r == n)
	{
		Root->All = x;
		return;
	}
	else
	if (l == 1)
	{
		Splay(Select(Root, r+1), Root->F);
		Root->Ls->All = x;
		Splay(Root->Ls, Root->F);
		return;
	}
	else
	if (r == n)
	{
		Splay(Select(Root, l-1), Root->F);
		Root->Rs->All = x;
		Splay(Root->Rs, Root->F);
		return;
	}
	Splay(Select(Root, l-1), Root->F);
	Splay(Select(Root, r+1), Root);
	Root->Rs->Ls->All = x;
	Splay(Root->Rs->Ls, Root->F);
}
inline void Reverse(int l, int r)
{
	if (l == 1 && r == n)
	{
		Root->Reverse ^= 1;
		return;
	}
	else
	if (l == 1)
	{
		Splay(Select(Root, r+1), Root->F);
		Root->Ls->Reverse ^= 1;
		Splay(Root->Ls, Root->F);
		return;
	}
	else
	if (r == n)
	{
		Splay(Select(Root, l-1), Root->F);
		Root->Rs->Reverse ^= 1;
		Splay(Root->Rs, Root->F);
		return;
	}
	Splay(Select(Root, l-1), Root->F);
	Splay(Select(Root, r+1), Root);
	Root->Rs->Ls->Reverse ^= 1;
	Splay(Root->Rs->Ls, Root->F);
}
inline int GetSum(int l, int r)
{
	if (l == 1 && r == n)
		return Root->Sum;
	else
	if (l == 1)
	{
		Splay(Select(Root, r+1), Root->F);
		return Root->Ls->Sum;
	}
	else
	if (r == n)
	{
		Splay(Select(Root, l-1), Root->F);
		return Root->Rs->Sum;
	}
	Splay(Select(Root, l-1), Root->F);
	Splay(Select(Root, r+1), Root);
	return Root->Rs->Ls->Sum;
}
inline int MaxSum()
{
	Root->Pushdown();
	return Root->Max;
}
inline void Debug(){if (Root)Root->Debug(), puts("");}
char c, ch[100];
inline void read(int &x)
{
	int opt(1);
	for (c = getchar();c > '9' || c < '0';c = getchar())
		if (c == '-')opt = -1;
	for (x = 0;c >= '0' && c <= '9';c = getchar())
		x = (x << 3) + (x << 1) + c - '0';
	x *= opt;
}
int main()
{
//	freopen("a.in", "r", stdin);
//	freopen("a.out", "w", stdout);
	int i, j, l, r, mid, len, pos;
	for (i = 0;i < 500001; ++i)Q.push(i);
	read(n), read(m);
	for (i = 1;i <= n;read(Number[i]), ++i);
	Root = Build(1, n, Number);
	for (c = getchar();m;m--, c = getchar())
	{
//		Debug();
		switch (c)
		{
			case ('I') : 
			{
				read(pos), read(len);
				for (i = 1;i <= len;read(Number[i]), ++i);
				Insert(pos, len, Number);
//				printf("INSERT %d %d\n", pos, len);
				break;
			}
			case ('D') : 
			{
				read(pos), read(len);
				Delete(pos, pos+len-1);
//				printf("DELETE %d %d\n", pos, len);
				break;
			}
			case ('M') : 
			{
				c = getchar();
				if (getchar() == 'K')
				{
					for (c = getchar();c != '-';c = getchar());
					read(pos), read(len), read(mid);
					MakeSame(pos, pos+len-1, mid);
//					printf("MAKE-SAME %d %d %d\n", pos, len, mid);
				}
				else
				{
					for (c = getchar();c != '\n';c = getchar());
					printf("%d\n", MaxSum());
				}
				break;
			}
			case ('R') : 
			{
				read(pos), read(len);
				Reverse(pos, pos+len-1);
//				printf("REVERSE %d %d\n", pos, len);
				break;
			}
			case ('G') : 
			{
				for (c = getchar();c != '-';c = getchar());
				read(pos), read(len);
				if (!len)
				{
					puts("0");
					continue;
				}
//				printf("GET-SUM %d %d ", pos, len);
				printf("%d\n", GetSum(pos, pos+len-1));
				break;
			}
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值