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

来源:互联网 发布:c语言判断数字大小 编辑:程序博客网 时间:2024/06/05 18:44

题意:给出[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) ) ;    }}intmain ( ){    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 ;}


原创粉丝点击