题意:给出[1,n]区间内每个点的数值,让你执行下面的操作:
1. C a b w : 区间[a,b]上所有点的数值加上w。
2. Q a b : 输出区间[a,b]上所有点的数值之和。
思路:经典线段树。静态建树,成段修改,区间求和。用普通的线段树去做肯定超时,因为成段修改的时候会是o(n)。关键在于用add记录对应区间内所有元素的增量,并对查询函数进行相应的修改。注意修改和查询的一个很关键的性质:区间[node[u].left,node[u].right]必定包含区间[left,right]。
//7088K 2219MS
#include <stdio.h>
#include <string.h>
#define N 100050
#define MAX(X,Y) ( (X) > (Y) ? (X) : (Y) )
#define MIN(X,Y) ( (X) < (Y) ? (X) : (Y) )
#define L(X) ( (X) <<1 )
#define R(X) ( ( (X) << 1 )| 1 )
#define MID(X) ( (X)>>1 )
struct node
{
int left , right ;
double sum , add ; // sum存储区间数值之和,add存储区间内所有数的增量。
}node[4*N];
double num[N] ;
double ans ;
void BuildTree ( int const left , const int right , int n )
{
node[n].left = left ;
node[n].right = right ;
node[n].add = 0 ;
if ( left == right )
{
node[n].sum = num[left] ;
}
else
{
int mid ;
mid = MID ( left + right ) ;
BuildTree ( left , mid , L(n)) ;
BuildTree ( mid + 1 , right , R(n) ) ;
node[n].sum = node[L(n)].sum + node[R(n)].sum ;
}
}
void Update ( int const left , int const right , double const val , int n )
{
if ( node[n].left == left && node[n].right == right )
{
node[n].add += val ; // 情况1:两区间完全匹配,新增的值记录为区间的add。
return ;
}
node[n].sum += ( right - left + 1 ) * val ; // 情况2:区间要继续分割,大区间的sum加上小区间所有数值新增的总和。
if ( left <= node[L(n)].right ) // 区间分割要考虑全面。
{
int temp_r ;
temp_r = MIN( node[L(n)].right , right ) ;
Update ( left , temp_r , val , L(n) ) ;
}
if ( right >= node[R(n)].left ) // 区间分割要考虑全面。
{
int temp_l ;
temp_l = MAX( left , node[R(n)].left ) ;
Update ( temp_l , right , val , R(n) ) ;
}
}
void Query ( int const left , int const right , int const n )
{
ans += ( right - left + 1 ) * node[n].add ; // 先加上区间[left,right]记录在[node[i].l,node[i].r]的总增量。
if ( node[n].left == left && node[n].right == right ) // 情况1:两区间完全匹配。
{
ans += node[n].sum ;
}
else if ( right <= node[L(n)].right ) // 情况2:小区间被大区间的左子区间包含。
{
Query ( left , right , L(n) ) ;
}
else if ( left >= node[R(n)].left) // 情况3:小区间被大区间的右子区间包含。
{
Query ( left , right , R(n) ) ; // 情况4:小区间被大区间的两个子区间分割。
}
else
{
int mid ;
mid = MID ( node[n].left + node[n].right ) ;
Query ( left , mid , L(n) ) ;
Query ( mid + 1 , right , R(n) ) ;
}
}
int
main ( )
{
int n , m ;
scanf ("%d%d" , & n , & m ) ;
int i ;
for ( i = 1 ; i <=n ; i ++ )
{
scanf ("%lf" , & num[i] ) ;
}
getchar ( ) ;
BuildTree ( 1 , n , 1 ) ;
while ( m -- )
{
char oper ;
int left , right ;
scanf ("%c" , & oper ) ;
if ( oper == 'Q' )
{
scanf ("%d%d" , & left , & right ) ;
ans = 0 ;
Query ( left , right , 1 ) ;
printf ("%.0f\n" , ans ) ;
}
else
{
double val ;
scanf ("%d%d%lf" , & left , & right , & val ) ;
Update ( left , right , val , 1 ) ;
}
getchar( ) ;
}
return 0 ;
}