1. 程式人生 > 其它 >萌萌板子題大全

萌萌板子題大全

替罪羊樹

均攤 $ O( logn ) $。


const double Alpha = 0.7;

struct Node{
	Node * l , * r;
	int v , siz , esiz;
	bool ex;
	
	bool judge(){ return 1.0 * l -> siz > Alpha * siz || 1.0 * r -> siz > Alpha * siz; }
	
	void update(){
		siz = ex + l -> siz + r -> siz;
		esiz = ex + l -> esiz + r -> esiz;
	}
} * NIL , * root;
	
void dfs( Node * u , vector< Node * > & vec ){
	if( u == NIL ) return;
	dfs( u -> l , vec );
	if( u -> ex ) vec . push_back( u );
	dfs( u -> r , vec );
	if( ! u -> ex ) delete u; 
}

Node * build( vector< Node * > & vec , int l , int r ){
	if( l >= r ) return NIL;
	int mid = l + r >> 1;
	Node * u = vec[ mid ];
	u -> l = build( vec , l , mid );
	u -> r = build( vec , mid + 1 , r );
	u -> update();
	return u;
}
	
void rebuild( Node * & u ){
	vector< Node * > vec;
	dfs( u , vec );
	u = build( vec , 0 , vec . size() );
}

void insert( Node * & u , int v ){		
	if( u == NIL ){
		u = new Node;
		u -> l = u -> r = NIL;
		u -> ex = 1;
		u -> siz = u -> esiz = 1;
		u -> v = v;
		return;
	}
	++ u -> siz , ++ u -> esiz;
	if( v >= u -> v ) insert( u -> r , v );
	else insert( u -> l , v );
	if( u -> judge() ) rebuild( u );
}

int rk( Node * u , int v ){
	int ans = 1;
	while( u != NIL ){
		if( v <= u -> v ) u = u -> l;
		else ans += u -> l -> esiz + u -> ex , u = u -> r; 
	}
	return ans;	
}	

int kth( Node * u , int k ){
	while( u != NIL ){
		if( u -> ex && u -> l -> esiz + 1 == k ) return u -> v;
		if( u -> l -> esiz >= k ) u = u -> l;
		else k -= u -> l -> esiz + u -> ex , u = u -> r;		
	}
}
		
void del( Node * u , int k ){		
	if( u -> ex && k == u -> l -> esiz + 1 ){
		u -> ex = 0;
		-- u -> esiz;
		return;
	}
	-- u -> esiz;
	if( u -> l -> esiz + u -> ex >= k ) del( u -> l , k );
	else del( u -> r , k - u -> l -> esiz - u -> ex );	
}

void solve(){
	for( int i = 1 ; i <= q ; ++ i ){
		int opt = read();
		int v = read();
		if( opt == 1 ) insert( root , v );
		else if( opt == 2 ) del( root , rk( root , v ) );
		else if( opt == 3 ) printf( "%d\n" , rk( root , v ) );
		else if( opt == 4 ) printf( "%d\n" , kth( root , v ) );
		else if( opt == 5 ) printf( "%d\n" , kth( root , rk( root , v ) - 1 ) );
		else if( opt == 6 ) printf( "%d\n" , kth( root , rk( root , v + 1 ) ) ); 
		
	}
}


重鏈剖分

$ O( log^2 n ) $,可可愛愛


void modify( int u , int v ){
	while( tp[ u ] != tp[ v ] ){
		if( dep[ tp[ u ] ] < dep[ tp[ v ] ] ) swap( u , v );
		T . update( 1 , 1 , n , dfsr[ tp[ u ] ] , dfsr[ u ] );
		u = fa[ tp[ u ] ];
	}
	if( dep[ u ] > dep[ v ] ) swap( u , v );
    
	//T . update( 1 , 1 , n , dfsr[ u ] + 1 , dfsr[ v ] ); //邊權
    
 	T . update( 1 , 1 , n , dfsr[ u ] , dfsr[ v ] );
}

void dfs2( int u , int top ){
	tp[ u ] = top;
	dfsr[ u ] = ++ cnt;
	tr[ cnt ] = u;
	if( ch[ u ] ) dfs2( ch[ u ] , top );
	for( int i = head[ u ] ; i ; i = edge[ i ] . nxt ){
		int v = edge[ i ] . to;
		if( v == fa[ u ] || v == ch[ u ] ) continue;
		dfs2( v , v ); 
	}
}

void dfs1( int u , int fath ){
	fa[ u ] = fath;
	siz[ u ] = 1;
	dep[ u ] = dep[ fath ] + 1;
	for( int i = head[ u ] ; i ; i = edge[ i ] . nxt ){
		int v = edge[ i ] . to;
		if( v == fath ) continue;
        
		//e[ ( int ) ceil( 1.0 * i / 2 ) ] = v; //如果是邊權的話
		//a[ v ] = edge[ i ] . w;
        
		dfs1( v , u );
		siz[ u ] += siz[ v ];
		if( siz[ v ] > siz[ ch[ u ] ] ) ch[ u ] = v;
	}
}

void pre(){
	dfs1( root , 0 );
	dfs2( root , root );
}

printf( "%d\n" , query( 1 , 1 , n , dfsr[ u ] , dfsr[ u ] + siz[ u ] - 1 )
//子樹詢問

倍增LCA

$ O( nlogn ) - O( logn ) $,可愛,並且也不會被卡,還好寫欸

void dfs( int u , int fath ){
	fa[ u ][ 0 ] = fath;
	dep[ u ] = dep[ fath ] + 1;
	for( int i = 1 ; i <= lgN ; i ++ ) fa[ u ][ i ] = fa[ fa[ u ][ i - 1 ] ][ i - 1 ];
	for( int i = head[ u ] ; i ; i = edge[ i ] . nxt ){
		int v = edge[ i ] . to;
		if( v == fath ) continue;
		dfs( v , u );
	} 
}
                            
int lca( int u , int v ){
	if( dep[ u ] < dep[ v ] ) swap( u , v );
	for( int i = lgN ; i >= 0 ; i -- ) if( dep[ fa[ u ][ i ] ] >= dep[ v ] ) u = fa[ u ][ i ];
	if( u == v ) return u;
	for( int i = lgN ; i >= 0 ; i -- )
		if( fa[ u ][ i ] != fa[ v ][ i ] ) u = fa[ u ][ i ] , v = fa[ v ][ i ];
	return fa[ u ][ 0 ]; 
}
     

主席樹區間 K 小

$ O( nlogn ) - O( logn ) $ hjt orz

int update( int u , int pre , int l , int r , int p ){
	u = ++ cnt;
	t[ u ] = t[ pre ];
	if( l == r ){
		++ t[ u ] . v;
		return u;
	}
	int mid = l + r >> 1;
	if( p <= mid ) t[ u ] . lc = update( t[ u ] . lc , t[ pre ] . lc , l , mid , p );
	else t[ u ] . rc = update( t[ u ] . rc , t[ pre ] . rc , mid + 1 , r , p );
	push_up( u );
	return u; 
}

int query( int u , int v , int l , int r , int k ){
	if( l == r ) return l;
	int mid = l + r >> 1;
	int val = t[ t[ v ] . lc ] . v - t[ t[ u ] . lc ] . v;
	if( k <= mid ) return query( t[ u ] . lc , t[ v ] . lc , l , mid , k );
	else return query( t[ u ] . rc , t[ v ] . rc , mid + 1 , r , k - val );
}

整體二分割槽間 K 小

$ O( nlog^2n ) $,好寫

struct Bit{
	# define lowbit( x ) x & ( -x )
	int t[ N << 3 ];
	
	void update( int u , int v ){
		while( u <= n ) t[ u ] += v , u += lowbit( u ); 
	}
	
	int query( int u ){
		int ret = 0;
		while( u ) ret += t[ u ] , u -= lowbit( u );
		return ret;
	}
}T;

struct Opt{
	int op , l , r , k , ord;
}o[ N ] , lo[ N ] , ro[ N ];

void solve( int l , int r , int ql , int qr ){
	if( ql > qr ) return;
	if( l == r ){
		for( int i = ql ; i <= qr ; i ++ )
			if( o[ i ] . op ) ans[ o[ i ] . ord ] = l;
		return;
	}
	int mid = l + r >> 1;
	int lp = 0 , rp = 0;
	for( int i = ql ; i <= qr ; i ++ ){
		if( ! o[ i ] . op )
			if( o[ i ] . k <= mid ) lo[ ++ lp ] = o[ i ] , T . update( o[ i ] . l , o[ i ] . r );
			else ro[ ++ rp ] = o[ i ];
		else{
			int tot = T . query( o[ i ] . r ) - T . query( o[ i ] . l - 1 );
			if( o[ i ] . k <= tot ) lo[ ++ lp ] = o[ i ];
			else o[ i ] . k -= tot , ro[ ++ rp ] = o[ i ];
		}
	}
	for( int i = 1 ; i <= lp ; i ++ )
		if( ! lo[ i ] . op ) T . update( lo[ i ] . l , - lo[ i ] . r );
	for( int i = 1 ; i <= lp ; i ++ ) o[ ql + i - 1 ] = lo[ i ];
	for( int i = 1 ; i <= rp ; i ++ ) o[ ql + lp + i - 1 ] = ro[ i ];
	solve( l , mid , ql , ql + lp - 1 );
	solve( mid + 1 , r , ql + lp , qr );
}

void input(){
	n = read();
	q = read();
	for( int i = 1 ; i <= n ; i ++ ){
		o[ ++ cnt ] . l = i;
		o[ cnt ] . r = 1;
		o[ cnt ] . op = 0;
		o[ cnt ] . k = a[ i ] = read();
	}
	for( int i = 1 ; i <= q ; i ++ ){
		char opt;
		scanf( " %c" , & opt );
		if( opt == 'C' ){
			int u = read();
			int v = read();
			o[ ++ cnt ] . l = u;
			o[ cnt ] . r = -1;
			o[ cnt ] . op = 0;
			o[ cnt ] . k = a[ u ];
			a[ u ] = v;
			o[ ++ cnt ] . l = u;
			o[ cnt ] . r = 1;
			o[ cnt ] . op = 0;
			o[ cnt ] . k = v;
		}
		else{
			o[ ++ cnt ] . l = read();
			o[ cnt ] . r = read();
			o[ cnt ] . k = read();
			o[ cnt ] . op = 1;
			o[ cnt ] . ord = i;
		}
	}
}

線段樹合併

$ O( mlogn ) $,離線寫法

int merge( int u , int v , int l , int r ){
	if( ! u ) return v;
	if( ! v ) return u;
	if( l == r ){
		t[ u ] . v += t[ v ] . v;
		t[ u ] . id = l;
		return u;
	}
	int mid = l + r >> 1;
	t[ u ] . lc = merge( t[ u ] . lc , t[ v ] . lc , l , mid );
	t[ u ] . rc = merge( t[ u ] . rc , t[ v ] . rc , mid + 1 , r );
	push_up( u );
	return u;
}

樹狀陣列

$ O(logn) $

struct Bit{
	int t[ N << 2 ];
	
	void update( int x , int v ){
		while( x <= n ) t[ x ] += v , x += lowbit( x );
	}
	
	int query( int x ){
		int ret = 0;
		while( x ) ret += t[ x ] , x -= lowbit( x );
		return ret;
	}
}T;