传送门:【HDU】4973 A simple simulation problem.
题目分析:比赛的时候是队友写的,赛后自己重新写了一发。
本题只要我们给每个节点保存他的元素个数以及相同元素的最大数量即可。
每个区间元素个数翻倍的传递就用mul[]保存,记录翻倍的次数,最后乘以2^mul[]即可,2^mul[]可以预处理。
update注意因为是根据左儿子区间的元素个数来决定接下来的走向,如果两个儿子都要走上一遭,又因为先走左儿子会改变左儿子的元素个数,所以应该先走右边,然后再走左边。
其他就和普通的线段树一样了,我就因为没有发现先走左儿子会改变左儿子的元素个数,所以wa了无数发,还是造了数据才发现的。。。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define REP( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REV( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define CLR( a , x ) memset ( a , x , sizeof a )
#define CPY( a , x ) memcpy ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define rt o , l , r
#define root 1 , 1 , n
#define lson ls , l , m
#define rson rs , m + 1 , r
#define mid ( ( l + r ) >> 1 )
typedef long long LL ;
const int MAXN = 50005 ;
LL sum[MAXN << 2] , cnt[MAXN << 2] ;
int mul[MAXN << 2] , pow[30] ;
void pushup ( int o ) {
sum[o] = sum[ls] + sum[rs] ;
cnt[o] = max ( cnt[ls] , cnt[rs] ) ;
}
void pushdown ( int o ) {
if ( mul[o] ) {
sum[ls] *= pow[mul[o]] ;
sum[rs] *= pow[mul[o]] ;
cnt[ls] *= pow[mul[o]] ;
cnt[rs] *= pow[mul[o]] ;
mul[ls] += mul[o] ;
mul[rs] += mul[o] ;
mul[o] = 0 ;
}
}
void build ( int o , int l , int r ) {
if ( l == r ) {
sum[o] = cnt[o] = 1 ;
return ;
}
int m = mid ;
build ( lson ) ;
build ( rson ) ;
pushup ( o ) ;
}
void update ( LL L , LL R , int o , int l , int r ) {
if ( l == r ) {
cnt[o] = sum[o] += R - L + 1 ;
return ;
} else if ( R - L + 1 == sum[o] ) {
sum[o] <<= 1 ;
cnt[o] <<= 1 ;
mul[o] ++ ;
return ;
}
pushdown ( o ) ;
int m = mid ;
if ( R <= sum[ls] ) update ( L , R, lson ) ;
else if ( sum[ls] < L ) update ( L - sum[ls] , R - sum[ls] , rson ) ;
else {
update ( 1 , R - sum[ls] , rson ) ;
update ( L , sum[ls] , lson ) ;
}
pushup ( o ) ;
}
LL query ( LL L , LL R , int o , int l , int r ) {
if ( l == r ) return R - L + 1 ;
if ( R - L + 1 == sum[o] ) return cnt[o] ;
pushdown ( o ) ;
int m = mid ;
if ( R <= sum[ls] ) return query ( L , R , lson ) ;
if ( sum[ls] < L ) return query ( L - sum[ls] , R - sum[ls] , rson ) ;
return max ( query ( L , sum[ls] , lson ) , query ( 1 , R - sum[ls] , rson ) ) ;
}
void scanf ( LL& x , char c = 0 ) {
while ( ( c = getchar () ) < '0' || c > '9' ) ;
x = c - '0' ;
while ( ( c = getchar () ) >= '0' && c <= '9' ) x = x * 10 + c - '0' ;
}
void solve () {
int n , m ;
char c ;
LL L , R ;
scanf ( "%d%d" , &n , &m ) ;
build ( root ) ;
CLR ( mul , 0 ) ;
while ( m -- ) {
c = getchar () ;
scanf ( L ) , scanf ( R ) ;
if ( c == 'D' ) update ( L , R , root ) ;
else printf ( "%I64d\n" , query ( L , R , root ) ) ;
}
}
int main () {
int T , cas = 0 ;
pow[0] = 1 ;
REP ( i , 1 , 30 ) pow[i] = pow[i - 1] << 1 ;
scanf ( "%d" , &T ) ;
while ( T -- ) {
printf ( "Case #%d:\n" , ++ cas ) ;
solve () ;
}
return 0 ;
}