【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

POJ Monthly--2007.11.25, Yang Yi

【分析】

很不错的数据结构,真的很不错....

跟树状数组有点像..

相比与普通线段树,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 }

时间: 2024-08-04 19:32:43

【POJ3468】【zkw线段树】A Simple Problem with Integers的相关文章

POJ3468 A Simple Problem with Integers 【线段树】+【成段更新】

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 57666   Accepted: 17546 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

POJ-3468 A Simple Problem with Integers(线段树)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 94899   Accepted: 29568 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

POJ-3468 A Simple Problem with Integers(线段树、段变化+段查询、模板)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 116441   Accepted: 36178 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type o

poj3468 A Simple Problem with Integers 线段树区间更新

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 97722   Accepted: 30543 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

POJ3468 A Simple Problem with Integers ( 线段树)

题目: A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 55817   Accepted: 16839 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One typ

A Simple Problem with Integers(POJ-3468)(线段树)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 71540   Accepted: 22049 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

poj 3468 A Simple Problem with Integers(线段树+区间更新+区间求和)

题目链接:id=3468http://">http://poj.org/problem? id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 83959   Accepted: 25989 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. Yo

poj3468A Simple Problem with Integers(线段树的区域更新)

http://poj.org/problem?id=3468 真心觉得这题坑死我了,一直错,怎么改也没戏,最后tjj把q[rt].lz改成了long long 就对了,真心坑啊. 线段树的区域更新. 线段树功能:update:成段增减 query:区间求和 #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> using namespace std; #d

POJ 3468 A Simple Problem with Integers(线段树)

题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 56005   Accepted: 16903 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with