[NOI2005] 维护数列

题目

点这里看题目。

分析

思路大概就是那样:平衡树加花式 tag ,求最大子段和的方法都是老方法了。

写一些细节:

  1. 常用的方法是把要维护的统一的信息给封装起来,这样可以重载运算符方便编写。
  2. 插入一大段序列的时候,使用 Splay 可以快速地建树,但是在 Treap 里面有(小根)堆性质的限制,因此如果暴力建树就是 \(O(\sum L\log_2 L)\) 的。为了加速这一过程,我们可以尝试根据树形构造出辅助值,即在递归建树的时候,取左右儿子的较小值并再减去一个随机值。虽然随机值会相对丑一些,但是的确会快一些。

代码

#include <cstdio>
#include <cstdlib>

#define rep( i, a, b ) for( int (i) = (a) ; (i) <= (b) ; (i) ++ )
#define per( i, a, b ) for( int (i) = (a) ; (i) >= (b) ; (i) -- )

const int INF = 1e3 + 1;
const int MAXN = 5e5 + 5, LIM = 4.5e6 + 5;

template<typename _T>
void read( _T &x )
{
	x = 0;char s = getchar();int f = 1;
	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
	while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
	x *= f;
}

template<typename _T>
void write( _T x )
{
	if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
	if( 9 < x ){ write( x / 10 ); }
	putchar( x % 10 + '0' );
}

template<typename _T>
_T MAX( const _T a, const _T b )
{
	return a > b ? a : b;
}

template<typename _T>
_T MIN( const _T a, const _T b )
{
	return a < b ? a : b;
}

template<typename _T>
void swapp( _T &x, _T &y )
{
	_T t = x; x = y, y = t;
}

struct Data
{
	int mx, lmx, rmx, su;
	
	Data() { mx = lmx = rmx = -INF, su = 0; }
	Data( const int nVal ) { mx = lmx = rmx = su = nVal; }
	Data& operator += ( const Data &b ) { return *this = *this + b; }
	
	Data operator + ( const Data &b ) const 
	{
		Data ret;
		ret.su = su + b.su;
		ret.lmx = MAX( lmx, su + b.lmx );
		ret.rmx = MAX( rmx + b.su, b.rmx );
		ret.mx = MAX( MAX( mx, b.mx ), rmx + b.lmx );
		return ret;
	}
};

int seq[MAXN], len; // ÐòÁеĻº´æ 
int stk[MAXN], top; // ÄÚ´æ»ØÊÕÕ¾ 

Data dat[MAXN]; int val[MAXN];                  // ÕâÀïÊÇÊ÷µÄÖµÐÅÏ¢ 
int ch[MAXN][2], siz[MAXN], aux[MAXN], rt, tot; // ÕâÀïÊÇÊ÷µÄ½á¹¹ÐÅÏ¢ 
int same[MAXN]; bool rev[MAXN];                 // ÕâÀïÊÇÊ÷µÄ±ê¼ÇÐÅÏ¢ 

int N, M;

int Alloc( const int nVal )
{
	int c = top ? stk[top --] : ++ tot;
	ch[c][0] = ch[c][1] = 0;
	siz[c] = 1, aux[c] = rand() * rand();
	val[c] = nVal, dat[c] = Data( nVal );
	same[c] = INF, rev[c] = 0;
	return c;
}

void Upt( const int x )
{
	if( ! x ) return ;
	siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;
	dat[x] = dat[ch[x][0]] + val[x] + dat[ch[x][1]];
}

void Reverse( const int x ) 
{
	if( ! x ) return ;
	swapp( ch[x][0], ch[x][1] );
	swapp( dat[x].lmx, dat[x].rmx );
	rev[x] ^= 1;
}

void Cover( const int x, const int v )
{
	if( ! x ) return ;
	dat[x].su = v * siz[x];
	dat[x].lmx = dat[x].rmx = dat[x].mx = MAX( v, v * siz[x] );
	val[x] = v, same[x] = v;
}

void Normalize( const int x )
{
	if( ! x ) return ;
	if( rev[x] ) Reverse( ch[x][0] ), Reverse( ch[x][1] ), rev[x] = 0;
	if( same[x] < INF ) Cover( ch[x][0], same[x] ), Cover( ch[x][1], same[x] ), same[x] = INF;
}

/*<---------- Here is a thin line between the tag operations(above) and the structural operations(below) ---------->*/

void SplitRnk( const int u, const int k, int &x, int &y )
{
	if( ! u ) return void( x = y = 0 ); Normalize( u );
	if( k <= siz[ch[u][0]] ) y = u, SplitRnk( ch[u][0], k, x, ch[u][0] ), Upt( y );
	else x = u, SplitRnk( ch[u][1], k - siz[ch[u][0]] - 1, ch[u][1], y ), Upt( x );
}

int Merge( const int u, const int v )
{
	if( ! u || ! v ) return u | v;
	Normalize( u ), Normalize( v );
	if( aux[u] < aux[v] ) return ( ch[u][1] = Merge( ch[u][1], v ), Upt( u ), u );
	return ( ch[v][0] = Merge( u, ch[v][0] ), Upt( v ), v );
}

// С¸ù¶ÑºÏ²¢ 

int Build( const int l, const int r )
{
	if( l > r ) return 0;
	int mid = l + r >> 1, lch = Build( l, mid - 1 );
	int cur = Alloc( seq[mid] );
	ch[cur][0] = lch, ch[cur][1] = Build( mid + 1, r );
	aux[cur] = MIN( aux[ch[cur][0]], aux[ch[cur][1]] ) - rand() - 1, Upt( cur );
	return cur;
}

void Remove( const int x )
{
	if( ! x ) return;
	Remove( ch[x][0] ), Remove( ch[x][1] );
	stk[++ top] = x;
}

/*<---------- Here is a thin line between the basic operations(above) and the required operations(below) ---------->*/

void Print( const int x )
{
	if( ! x ) return ;
	Normalize( x );
	Print( ch[x][0] );
	write( val[x] ), putchar( ' ' );
	Print( ch[x][1] );
}

#define Show ( Print( rt ), putchar( '\n' ) )

void Insert()
{
	int beg; read( beg ), read( len );
	rep( i, 1, len ) read( seq[i] );
	int tmp = Build( 1, len ), x;
	SplitRnk( rt, beg, rt, x );
	rt = Merge( rt, Merge( tmp, x ) );
}

void Delete()
{
	int beg, x, y; read( beg ), read( len );
	SplitRnk( rt, beg - 1, x, rt );
	SplitRnk( rt, len, rt, y );
	Remove( rt ), rt = Merge( x, y );
}

void MakeSame()
{
	int beg, nw, x, y; read( beg ), read( len ), read( nw );
	SplitRnk( rt, beg - 1, x, rt );
	SplitRnk( rt, len, rt, y );
	Cover( rt, nw ), rt = Merge( x, Merge( rt, y ) );
}

void SReverse()
{
	int beg, x, y; read( beg ), read( len );
	SplitRnk( rt, beg - 1, x, rt );
	SplitRnk( rt, len, rt, y );
	Reverse( rt ), rt = Merge( x, Merge( rt, y ) );
}

int GetSum()
{
	int beg, x, y; read( beg ), read( len );
	SplitRnk( rt, beg - 1, x, rt );
	SplitRnk( rt, len, rt, y );
	int ret = dat[rt].su; rt = Merge( x, Merge( rt, y ) );
	return ret;
}

int MaxSum() { return dat[rt].mx; }

int main()
{
	srand( 998244353 );
	read( N ), read( M );
	rep( i, 1, N ) read( seq[i] );
	rt = Build( 1, N );
	
	char opt[15];
	while( M -- ) { 
		scanf( "%s", opt );
		if( opt[0] == 'I' ) Insert();
		if( opt[0] == 'D' ) Delete();
		if( opt[0] == 'R' ) SReverse();
		if( opt[0] == 'G' ) write( GetSum() ), putchar( '\n' );
		if( opt[0] == 'M' && opt[2] == 'K' ) MakeSame();
		if( opt[0] == 'M' && opt[2] == 'X' ) write( MaxSum() ), putchar( '\n' );
	}
	return 0;
}
posted @ 2021-01-27 17:18  crashed  阅读(99)  评论(0编辑  收藏  举报