萌萌板子題大全
阿新 • • 發佈:2021-12-04
替罪羊樹
均攤 $ 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;