[NOI2005] 维护数列
题目
点这里看题目。
分析
思路大概就是那样:平衡树加花式 tag ,求最大子段和的方法都是老方法了。
写一些细节:
- 常用的方法是把要维护的统一的信息给封装起来,这样可以重载运算符方便编写。
- 插入一大段序列的时候,使用 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;
}