题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3065
刚开始想用splay维护,但是死活想不出旋转时维护信息的方法,果断放弃,然后又打算用分块的思想,插入了sqrt(m)个数后再次分治重建树。ORZ了VFK的博客之后才发现,貌似带根号的会TLE,果断放弃。对于这道题,虽然依赖于旋转的平衡树无法达到要求,但是不依赖或者是依赖旋转程度很小(比如treap)的重量平衡树可以满足套上线段树这个要求,所以我选择了相对比较好写的替罪羊树,然后每次询问就在树上找到相应的一组节点,沿着权值线段树走就好啦。。。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std ;
#define MAXN 80010
#define MAXL 70010
#define a 0.80
#define inf 0x7fffffff
#define check( ch ) ( ch >= '0' && ch <= '9' )
#define L( t ) Left[ t ]
#define R( t ) Right[ t ]
#define K( t ) Key[ t ]
#define S( t ) Size[ t ]
#define T( t ) Tree[ t ]
void getint( int &t ) {
int ch ; for ( ch = getchar( ) ; ! check( ch ) ; ch = getchar( ) ) ;
t = ch - '0' ;
for ( ch = getchar( ) ; check( ch ) ; ch = getchar( ) ) t *= 10 , t += ch - '0' ;
}
void putint( int t ) {
if ( ! t ) putchar( '0' ) ; else {
int ans[ 20 ] ; ans[ 0 ] = 0 ;
for ( ; t ; t /= 10 ) ans[ ++ ans[ 0 ] ] = t % 10 ;
for ( ; ans[ 0 ] ; ans[ 0 ] -- ) putchar( '0' + ans[ ans[ 0 ] ] ) ;
}
putchar( '\n' ) ;
}
struct node {
node *left , *right ;
int sum ;
node ( ) {
sum = 0 ;
left = right = NULL ;
}
} *blank = new( node ) ;
void Add( int l , int r , int k , node* &t) {
if ( t == blank ) t = new( node ) , t -> left = t -> right = blank ;
t -> sum ++ ;
if ( l == r ) return ;
int mid = ( l + r ) >> 1 ;
if ( k <= mid ) Add( l , mid , k , t -> left ) ; else Add( mid + 1 , r , k , t -> right ) ;
}
void Del( int l , int r , int k , node* &t) {
t -> sum -- ;
if ( l == r ) return ;
int mid = ( l + r ) >> 1 ;
if ( k <= mid ) Del( l , mid , k , t -> left ) ; else Del( mid + 1 , r , k , t -> right ) ;
}
int Left[ MAXN ] , Right[ MAXN ] , Key[ MAXN ] , Size[ MAXN ] , V = 0 , roof ;
node *Tree[ MAXN ] ;
int n , m , w[ MAXN ] ;
int dfn[ MAXN ] , Index ;
void build( int l , int r , int &t ) {
if ( l > r ) {
t = 0 ; return ;
}
int mid = ( l + r ) >> 1 ;
t = dfn[ mid ] ;
T( t ) = blank , S( t ) = r - l + 1 ;
for ( int i = l ; i <= r ; i ++ ) {
Add( 0 , MAXL , K( dfn[ i ] ) , T( t ) ) ;
}
build( l , mid - 1 , L( t ) ) , build( mid + 1 , r , R( t ) ) ;
}
node *Range[ MAXN ] ;
int P[ MAXN ] , nr , np ;
void ranging( int l , int r , int t ) {
if ( r < S( L( t ) ) ) ranging( l , r , L( t ) )
; else if ( l > S( L( t ) ) ) ranging( l - S( L( t ) ) - 1 , r - S( L( t ) ) - 1 , R( t ) )
; else {
if ( ! l && r == S( t ) - 1 ) Range[ ++ nr ] = T( t )
; else {
P[ ++ np ] = K( t ) ;
if ( l < S( L( t ) ) ) ranging( l , S( L( t ) ) - 1 , L( t ) ) ;
if ( r > S( L( t ) ) ) ranging( 0 , r - S( L( t ) ) - 1 , R( t ) ) ;
}
}
}
void getrange( int l , int r ) {
nr = np = 0 ;
ranging( l - 1 , r - 1 , roof ) ;
}
void dfs( int t ) {
if ( L( t ) ) dfs( L( t ) ) ;
dfn[ ++ Index ] = t ;
if ( R( t ) ) dfs( R( t ) ) ;
}
void Recycle( node *t ) {
if ( ! t -> sum ) return ;
if ( t -> left ) Recycle( t -> left ) ;
if ( t -> right ) Recycle( t -> right ) ;
delete( t ) ;
}
void rebuild( int &t ) {
Index = 0 ;
dfs( t ) ;
for ( int i = 0 ; i ++ < Index ; ) Recycle( T( dfn[ i ] ) ) ;
build( 1 , Index , t ) ;
}
bool Insert( int r , int k , int h , int &t ) {
if ( ! t ) {
t = ++ V ;
S( t ) = 1 , K( t ) = k , L( t ) = R( t ) = 0 , T( t ) = blank ;
Add( 0 , MAXL , k , T( t ) ) ;
return h > log( V ) / log( 1 / a ) ;
}
bool flag ;
if ( r <= S( L( t ) ) ) flag = Insert( r , k , h + 1 , L( t ) )
; else flag = Insert( r - S( L( t ) ) - 1 , k , h + 1 , R( t ) ) ;
S( t ) = S( L( t ) ) + S( R( t ) ) + 1 ;
Add( 0 , MAXL , k , T( t ) ) ;
if ( flag && ( max( S( L( t ) ) , S( R( t ) ) ) > a * S( t ) ) ) {
rebuild( t ) ;
return false ;
}
return flag ;
}
int Change( int r , int k , int t ) {
if ( S( L( t ) ) == r ) {
Del( 0 , MAXL , K( t ) , T( t ) ) ;
int v = K( t ) ; K( t ) = k ;
Add( 0 , MAXL , k , T( t ) ) ;
return v ;
}
int v ;
if ( r < S( L( t ) ) ) v = Change( r , k , L( t ) )
; else v = Change( r - S( L( t ) ) - 1 , k , R( t ) ) ;
Del( 0 , MAXL , v , T( t ) ) ;
Add( 0 , MAXL , k , T( t ) ) ;
return v ;
}
int Query( int l , int r , int k ) {
k -- ;
getrange( l , r ) ;
int L = 0 , R = MAXL ;
while ( L < R ) {
int mid = ( L + R ) >> 1 , sum = 0 ;
for ( int i = 0 ; i ++ < nr ; ) sum += Range[ i ] -> left -> sum ;
for ( int i = 0 ; i ++ < np ; ) sum += ( P[ i ] >= L && P[ i ] <= mid ) ? 1 : 0 ;
if ( k < sum ) {
for ( int i = 0 ; i ++ < nr ; ) Range[ i ] = Range[ i ] -> left ;
R = mid ;
} else {
k -= sum ;
for ( int i = 0 ; i ++ < nr ; ) Range[ i ] = Range[ i ] -> right ;
L = mid + 1 ;
}
}
return L ;
}
int main( ) {
blank -> left = blank -> right = blank ;
getint( n ) ; for ( int i = 0 ; i ++ < n ; ) getint( w[ i ] ) ;
L( 0 ) = R( 0 ) = S( 0 ) = 0 ;
for ( int i = 0 ; i ++ < n ; ) {
dfn[ i ] = ++ V ; K( V ) = w[ i ] ;
}
build( 1 , n , roof ) ;
getint( m ) ;
int last = 0 ;
while ( m -- ) {
int ch ; for ( ch = getchar( ) ; ! ( ch >= 'A' && ch <= 'Z' ) ; ch = getchar( ) ) ;
if ( ch == 'Q' ) {
int x , y , k ; getint( x ) , getint( y ) , getint( k ) ;
x ^= last , y ^= last , k ^= last ;
putint( last = Query( x , y , k ) ) ;
} else if ( ch == 'I' ) {
int x , y ; getint( x ) , getint( y ) ;
x ^= last , y ^= last ;
Insert( x - 1 , y , 0 , roof ) ;
} else {
int x , y ; getint( x ) , getint( y ) ;
x ^= last , y ^= last ;
Change( x - 1 , y , roof ) ;
}
}
return 0 ;
}