[NOI2005]维护数列

题目

戳这洛谷

思路

使用带Lazy的平衡树,无旋Treap
详见注释

Code:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXM 15
#define MAXN 500005
#define LL long long
#define Int register int
#define Int_Max 2147483647
using namespace std;
inline void read(int &x)
{
	x = 0;
	int f = 1;
	char s = getchar();
	while (s < '0' || s > '9')
	{
		if (s == '-')
			f = -1;
		s = getchar();
	}
	while (s >= '0' && s <= '9')
	{
		x = (x << 3) + (x << 1) + (s ^ 48);
		s = getchar();
	}
	x *= f;
}
int Root, Num, a[MAXN], Sta[MAXN], Index_Sta;
struct node
{
	int l, r, Size, val, Cov, Xiu;
	bool Lazy, CovLazy;
	int Sum, Maxqj, MaxPre, MaxBac;
}Point[MAXN];
inline int Max(int x,int y)
{
	return x > y ? x : y;
}
inline int Min(int x,int y)
{
	return x < y ? x : y;
}
int GetHash()
{
    static int Seed = 252006;
    Seed = (int)Seed * 121725 % Int_Max;
    return Seed;
}
int NewNode(int v)
{
	Num = Sta[Index_Sta --];
	Point[Num].Size = 1;
	Point[Num].Xiu = GetHash();
	Point[Num].Maxqj = Point[Num].val = Point[Num].Sum = v;
	Point[Num].MaxPre = Point[Num].MaxBac = Max(0, v); //维护最大前缀和和最大后缀和 
	Point[Num].l = Point[Num].r = Point[Num].Cov = Point[Num].Lazy = Point[Num].CovLazy = 0;
	return Num;
}
void Push_Up(int x)
{
	if (! x)
		return ;
	Point[x].Size = Point[Point[x].l].Size + Point[Point[x].r].Size + 1; // 左加右加自己 
	Point[x].Sum = Point[Point[x].l].Sum + Point[Point[x].r].Sum + Point[x].val; // 左加右加自己 
	Point[x].MaxPre = Max(Point[Point[x].l].MaxPre, Point[Point[x].l].Sum + Point[x].val + Point[Point[x].r].MaxPre); // 维护最大前缀和 
	Point[x].MaxBac = Max(Point[Point[x].r].MaxBac, Point[Point[x].r].Sum + Point[x].val + Point[Point[x].l].MaxBac); // 维护最大后缀和 
	Point[x].Maxqj = Max(Point[x].val, Point[x].val + Point[Point[x].l].MaxBac + Point[Point[x].r].MaxPre); // 维护最大区间和 
	if (Point[x].l)
		Point[x].Maxqj = Max(Point[x].Maxqj, Point[Point[x].l].Maxqj);
	if (Point[x].r)
		Point[x].Maxqj = Max(Point[x].Maxqj, Point[Point[x].r].Maxqj);
	/*如果有左/右儿子,有可能是左/右儿子的最大区间和*/
}
void Swap(int &a,int &b)
{
	int temp = a;
	a = b;
	b = temp;
}
void Reverse(int x)
{
	if (! x)
		return ;
	Swap(Point[x].l, Point[x].r);
	Swap(Point[x].MaxPre, Point[x].MaxBac); // 交换左右儿子的同时也要交换最大前缀和 & 后缀和 
	Point[x].Lazy = ! Point[x].Lazy;
}
void Cover(int x,int c)
{
	Point[x].val = Point[x].Cov = c;
	Point[x].Sum = Point[x].Size * c;
	Point[x].CovLazy = 1;
	Point[x].MaxPre = Point[x].MaxBac = Max(0, Point[x].Sum);
	Point[x].Maxqj = Max(c, Point[x].Sum); 
}
void Push_down(int x)
{
	if (! x)
		return ;
	if (Point[x].Lazy)
	{
		if (Point[x].l)
			Reverse(Point[x].l);
		if (Point[x].r)
			Reverse(Point[x].r);
		Point[x].Lazy = 0;
	}
	if (Point[x].CovLazy)
	{
		if (Point[x].l)
			Cover(Point[x].l, Point[x].Cov);
		if (Point[x].r)
			Cover(Point[x].r, Point[x].Cov);
		Point[x].Cov = Point[x].CovLazy = 0;
	}
}
void Delete(int x)
{
	if (! x)
		return ;
	Sta[++ Index_Sta] = x;
	if (Point[x].l)
		Delete(Point[x].l);
	if (Point[x].r)
		Delete(Point[x].r);
}
void Split(int x,int &u,int &v,int k) // 按 Rank Split 
{
	if ( x )
		Push_down( x );
	if (! x)
	{
		u = v = 0;
		return ;
	}
	if (Point[Point[x].l].Size < k) // 左儿子小于 k 
	{
		u = x;
		Split(Point[x].r, Point[u].r, v, k - Point[Point[x].l].Size - 1); // 拆右子树
	}
	else
	{
		v = x;
		Split(Point[x].l, u, Point[v].l, k); // 拆左子树
	}
	Push_Up( x );
}
void Merge(int u,int v,int &x)
{
	if (! u || ! v)
	{
		x = u | v;
		return ;
	}
	if (Point[u].Xiu < Point[v].Xiu)
	{
		Push_down( u );
		x = u;
		Merge(Point[u].r, v, Point[x].r); // 并上右子树 
		Push_Up( u );
	}
	else
	{
		Push_down( v );
		x = v;
		Merge(u, Point[v].l, Point[x].l); // 并上左子树 
		Push_Up( v );
	}
}
int Build(int l,int r)
{
	int x, Mid = (l + r) / 2;
	if (l == r)
		return NewNode( a[Mid] );
	Merge(Build(l, Mid), Build(Mid + 1, r), x);
	return x;
}
int main()
{
	srand(*new unsigned);
	int n, m;
	read( n ); read( m );
	for (Int i = 1; i <= MAXN - 5; ++ i)
		Sta[++ Index_Sta] = i;
	for (Int i = 1; i <= n; ++ i)
		read( a[i] );
	Merge(Root, Build(1, n), Root);
	while (m --)
	{
		char Or[MAXM];
		scanf("%s", Or);
		switch ( Or[2] )
		{
			case 'S':
			{
				int pos, tot;
				read( pos ); read( tot );
				int x, y;
				Split(Root, x, y, pos); // 按 pos 拆成两半 
				for (Int i = 1; i <= tot; ++ i)
					read( a[i] );
				Merge(x, Build(1, tot), x); // 并入前一半 
				Merge(x, y, Root); // 并入后一半 
				break;
			}
			case 'L':
			{
				int pos, tot;
				read( pos ); read( tot );
				int x, y, z;
				Split(Root, x, y, pos - 1);
				Split(y, y, z, tot);
				Delete( y );
				Merge(x, z, Root);
				break;
			}
			case 'K':
			{
				int pos, tot, c;
				read( pos ); read( tot ); read( c );
				int x, y, z;
				Split(Root, x, y, pos - 1);
				Split(y, y, z, tot);
				Cover(y, c);
				Merge(x, y, x);
				Merge(x, z, Root);
				break;
			}
			case 'V':
			{
				int pos, tot;
				read( pos ); read( tot );
				int x, y, z;
				Split(Root, x, y, pos - 1);
				Split(y, y, z, tot);
				Reverse( y );
				Merge(x, y, y);
				Merge(y, z, Root);
				break;
			}
			case 'T':
			{
				int pos, tot;
				read( pos ); read( tot );
				int x, y, z;
				Split(Root, x, y, pos - 1);
				Split(y, y, z, tot);
				printf("%d\n", Point[y].Sum);
				Merge(x, y, y);
				Merge(y, z, Root);
				break;
			}
			case 'X':
			{
				printf("%d\n", Point[Root].Maxqj);
				break;
			}
		}
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值