题意:N个数字,Q个操作,Q表示询问[s,t]中的数据和,C表示从s到t中的每个数据都加上x;
思路:简单的线段树,把每一段放入和存入结构体中,但是如果每次更新都更新到叶子节点的话,会超时,因此在结构体中加入一个标记,记录每个区间的增加量,这样不用再更新到叶子节点,当查询的时候加上即可。
代码:
View Code
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> #include <queue> #include <math.h> #define N 100004 using namespace std ; typedef __int64 lx ; struct node { int ll , rr ; lx ss , v ;//ss表示区间和,v 表示区间增量 }p[4*N] ; lx dat[N] ; int n , m ; //建树 void built( int id , int l , int r ) { p[id].ll = l ; p[id].rr = r ; p[id].v = 0 ; if ( l == r ) { p[id].ss = dat[l] ; return ; } else { int mid = ( l + r )/ 2 ; built( 2*id , l , mid ); built( 2*id+1 , mid+1 , r ); } p[id].ss = p[2*id].ss + p[2*id+1].ss ; } //询问 lx query( int id , int l , int r ) { if( p[id].ll == l && p[id].rr == r )//如果查到这个区间,将区间和加上增量返回 { return ( p[id].ss + ( r - l + 1 ) * p[id].v ); } else//否则的话,将这个区间的增量加到子节点上。 { p[2*id].v += p[id].v ; p[2*id+1].v += p[id].v ; p[id].ss += ( p[id].rr - p[id].ll + 1 ) * p[id].v ; p[id].v = 0 ; } int mid = ( p[id].ll + p[id].rr ) /2 ; if ( l > mid ) return query( 2*id+1 , l , r ); else if ( r <= mid ) return query ( 2*id , l , r ); else { return query( 2 * id , l , mid ) + query( 2 * id + 1 , mid + 1 , r ); } } //更新 void update( int id , int l , int r , lx v ) { //找到要更新区间,将这个区间增量加上,然后返回,不必到叶子节点 if ( p[id].ll == l && p[id].rr == r ) { p[id].v += v ; return ; } p[id].ss += ( r - l + 1 ) * v ; int mid = ( p[id].ll + p[id].rr ) / 2 ; if ( l > mid ) update( 2*id+1 , l , r , v ); else if ( r <= mid ) update( 2*id , l , r , v ); else { update( 2*id , l , mid , v ); update( 2*id+1 , mid +1 , r , v ); } //p[id].ss = p[2*id].ss + p[2*id+1].ss ; } int main() { int i , x , y ; lx v ; char c ; while( scanf( "%d%d" , &n , &m ) != EOF ) { for ( i = 1 ; i <= n ; i++ ) scanf( "%I64d" , &dat[i] ); built( 1 , 1 , n ); while( m-- ) { getchar(); scanf( "%c%d%d" , &c , &x , &y ); if ( c == 'Q' ) { lx sx = query( 1 , x , y ); cout<<sx<<endl; } else { scanf( "%I64d" , &v ); update( 1 , x , y , v ); } } } return 0 ; }