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]。
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 ; }
相关文章推荐
- 线段树 POJ 3468 A Simple Problem with Integers
- POJ 3468 A Simple Problem with Integers 线段树区间更新 (值在基础上相加或相减)
- poj 3468 A Simple Problem with Integers (线段树区间更新入门)
- POJ 3468 A Simple Problem with Integers (线段树成段更新) 解题报告
- poj - 3468 - A Simple Problem with Integers(线段树(区间更新))
- poj 3468 A Simple Problem with Integers(线段树——区间更新)
- poj 3468 A Simple Problem with Integers(线段树、延迟更新)
- poj 3468 A Simple Problem with Integers 线段树
- [线段树] POJ 3468 A Simple Problem with Integers
- POJ3468——线段树成段更新——A Simple Problem with Integers
- POJ 3468 A Simple Problem with Integers (线段树 区间共加)
- POJ 3468 A Simple Problem with Integers(线段树)
- POJ 3468 A Simple Problem with Integers(线段树)
- poj 3468 A Simple Problem with Integers 线段树
- poj 3468 A Simple Problem with Integers 线段树成段更新模板
- POJ--3468 A Simple Problem with Integers(线段树)
- POJ 3468 A Simple Problem with Integers(线段树功能:区间加减区间求和)
- poj 3468 A Simple Problem with Integers(数据结构:线段树)
- POJ 3468 A Simple Problemwith Integers(线段树:区间add,区间查询)
- POJ 3468 A Simple Problem with Integers 线段树 区间修改