您的位置:首页 > 其它

POJ 3468 A Simple Problem with Integers (线段树—成段覆盖)

2013-08-28 00:09 330 查看
题意:给出[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
;

double ans ;

void BuildTree ( int const left , const int right , int n )
{
node
.left = left ;
node
.right = right ;
node
.add = 0 ;
if ( left == right )
{
node
.sum = num[left] ;
}
else
{
int mid ;
mid = MID ( left + right ) ;
BuildTree ( left , mid , L(n)) ;
BuildTree ( mid + 1 , right , R(n) ) ;
node
.sum = node[L(n)].sum + node[R(n)].sum ;
}
}

void Update ( int const left , int const right , double const val , int n )
{
if ( node
.left == left && node
.right == right )
{
node
.add += val ;    //  情况1:两区间完全匹配,新增的值记录为区间的add。
return ;
}
node
.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
.add ;      //  先加上区间[left,right]记录在[node[i].l,node[i].r]的总增量。
if ( node
.left == left && node
.right == right )       //  情况1:两区间完全匹配。
{
ans += node
.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
.left + node
.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 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: