zoukankan      html  css  js  c++  java
  • [NOI2005] 维护数列

    题目

    点这里看题目。

    分析

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

    写一些细节:

    1. 常用的方法是把要维护的统一的信息给封装起来,这样可以重载运算符方便编写。
    2. 插入一大段序列的时候,使用 Splay 可以快速地建树,但是在 Treap 里面有(小根)堆性质的限制,因此如果暴力建树就是 (O(sum Llog_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( '
    ' ) )
    
    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( '
    ' );
    		if( opt[0] == 'M' && opt[2] == 'K' ) MakeSame();
    		if( opt[0] == 'M' && opt[2] == 'X' ) write( MaxSum() ), putchar( '
    ' );
    	}
    	return 0;
    }
    
  • 相关阅读:
    Python3 日期与时间戳相互转换
    PHP 二维数组排序保持键名不变
    C# Command命令(行为型模式)+队列 实现事务,带异步命令重试机制和生命周期
    领域驱动系列五模型驱动设计的构造块
    领域驱动系列四之模型驱动
    领域驱动系列三
    领域驱动系列二策略模式的应用
    领域驱动系列一基本概念介绍
    Redis学习系列七分布式锁
    Redis学习系列六ZSet(有序列表)及Redis数据结构的过期
  • 原文地址:https://www.cnblogs.com/crashed/p/14335956.html
Copyright © 2011-2022 走看看