【POJ3468】【zkw线段树】A Simple Problem with Integers

Description

You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5

1 2 3 4 5 6 7 8 9 10

Q 4 4

Q 1 10

Q 2 4

C 3 6 3

Q 2 4

Sample Output

4

55

9

15

Hint

The sums may exceed the range of 32-bit integers.

Source

【分析】
很不错的数据结构,真的很不错....
跟树状数组有点像..
相比与普通线段树,zkw线段树具有标记永久化,简单好写的特点。
但zkw线段树占用的空间会相对大些,毕竟是2的阶乘...,然后应该不能可持久化吧(别跟我说用可持久化线段树维护可持久化数组....)
这样就不能动态分配内存了。。不过总体来说还是有一定的实用价值...
  1 /*

  2 宋代陆游

  3 《临安春雨初霁》

  4 

  5 世味年来薄似纱,谁令骑马客京华。

  6 小楼一夜听春雨,深巷明朝卖杏花。

  7 矮纸斜行闲作草,晴窗细乳戏分茶。

  8 素衣莫起风尘叹,犹及清明可到家。 

  9 */

 10 #include <iostream>

 11 #include <cstdio>

 12 #include <algorithm>

 13 #include <cstring>

 14 #include <vector>

 15 #include <utility>

 16 #include <iomanip>

 17 #include <string>

 18 #include <cmath>

 19 #include <queue>

 20 #include <assert.h>

 21 #include <map>

 22 #include <ctime>

 23 #include <cstdlib>

 24 #include <stack>

 25 #define LOCAL

 26 const int INF = 0x7fffffff;

 27 const int MAXN = 100000 + 10;

 28 const int maxnode = 300000;

 29 using namespace std;

 30 struct Node{

 31     int l, r;

 32     long long sum, d;    

 33 }tree[maxnode];

 34 int data[MAXN], M;//M为总结点个数        

 35 

 36 //初始化线段树 

 37 void build(int l, int r){

 38     for (int i = 2 * M - 1; i > 0; i--){

 39         if (i >= M){

 40             tree[i].sum = data[i - M];

 41             tree[i].l = tree[i].r = (i - M);//叶子节点 

 42         }

 43         else {

 44             tree[i].sum = tree[i<<1].sum + tree[(i<<1)+1].sum;

 45             tree[i].l = tree[i<<1].l;

 46             tree[i].r = tree[(i<<1)+1].r;

 47         }

 48     }

 49 }

 50 long long query(int l, int r){

 51     long long sum = 0;//sum记录和 

 52     int numl = 0, numr = 0;

 53     l += M - 1;

 54         r += M + 1;

 55     while ((l ^ r) != 1){

 56           if (~l&1){//l取反,表示l是左节点 

 57               sum += tree[l ^ 1].sum;

 58               numl += (tree[l ^ 1].r - tree[l ^ 1].l + 1);

 59            }

 60            if (r & 1){

 61               sum += tree[r ^ 1].sum;

 62               numr += (tree[r ^ 1].r - tree[r ^ 1].l + 1);

 63            }

 64            l>>=1;

 65            r>>=1;

 66            //numl,numr使用来记录标记的 

 67            sum += numl * tree[l].d;

 68            sum += numr * tree[r].d;

 69     }

 70     for (l >>= 1; l > 0; l >>= 1)  sum += (numl + numr) * tree[l].d; 

 71     return sum;

 72 }

 73 

 74 void add(int l, int r, int val){

 75      int numl = 0, numr = 0;

 76      l += M - 1;

 77      r += M + 1;

 78      while ((l ^ r) != 1){

 79            if (~l&1){//l取反 

 80               tree[l ^ 1].d += val;

 81               tree[l ^ 1].sum += (tree[l ^ 1].r - tree[l ^ 1].l + 1) * val;

 82               numl += (tree[l ^ 1].r - tree[l ^ 1].l + 1);

 83            }

 84            if (r & 1){

 85               //更新另一边 

 86               tree[r ^ 1].d += val;

 87               tree[r ^ 1].sum += (tree[r ^ 1].r - tree[r ^ 1].l + 1) * val;

 88               numr += (tree[r ^ 1].r - tree[r ^ 1].l + 1);

 89            }

 90            l>>=1;

 91            r>>=1;

 92            tree[l].sum += numl * val;

 93            tree[r].sum += numr * val;

 94      }

 95      //不要忘了往上更新 

 96      for (l >>= 1; l > 0; l >>= 1)  tree[l].sum += (numl+numr) * val; 

 97 }

 98 int    n, m;

 99 

100 void init(){

101      scanf("%d%d", &n, &m);

102      for (int i = 1; i <= n; i++) scanf("%d", &data[i]);

103      M = 1;while (M < (n + 2)) M <<= 1;//找到最大的段 

104      build(0, M - 1);

105 }

106 void work(){

107      while (m--){

108             char str[2];

109             scanf("%s", str);

110             if (str[0] == 'Q'){

111             int l, r;

112             scanf("%d%d", &l, &r);

113             printf("%lld\n", query(l, r));

114         }

115         else{

116             int val, l, r;

117             scanf("%d%d%d", &l, &r, &val);

118             if (val != 0) add(l, r, val);

119         }

120      }

121 }

122 

123 int main(){

124     

125     init();

126     work();

127     return 0;

128 }
View Code

 

你可能感兴趣的:(Integer)