POJ 3468 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

线段树区间查询的核心思想是Lazy原则,顾名思义,懒!!
就是当修改某区间的值是,现将修改的值记录下来,暂不修改。
此时如果查询区间与上一个修改区间没有交集,那么对结果也没有影响。我等用到这个修改过的区间的值时,再将它的值向下更新。
而且只用向下更新一层,因为递归时我们是根据区间的位置情况连续向下找左右子节点的,所以只更新一层就行,更新多了没用(如果更新到底,就变成单点更新了,复杂度爆炸)

代码如下:
  1 #include <cstdio>
  2 #include <algorithm>
  3 
  4 using namespace std;
  5 #define M 100005
  6 struct segTree
  7 {
  8     int l,r;
  9     long long int sum,add;
 10     int mid()
 11     {
 12         return (l+r)>>1;
 13     }
 14 }tree[M<<2];
 15 int n,m;
 16 void PushUp (int now)//向上更新:当前节点的sum等于其左右儿子的sum的和
 17 {
 18     tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;
 19 }
 20 void buildTree (int now,int l,int r)
 21 {
 22     tree[now].l=l,tree[now].r=r;
 23     tree[now].add=0;
 24     if (l==r)
 25     {
 26         scanf("%lld",&tree[now].sum);
 27         return;
 28     }
 29     int m=tree[now].mid();
 30     buildTree(now<<1,l,m);//递归建树
 31     buildTree(now<<1|1,m+1,r);
 32     PushUp(now);//向上更新
 33 }
 34 void PushDown (int now,int m)
 35 //向下更新:当前节点的add值需要加到自己左右儿子的add与sum上
 36 {
 37     if (tree[now].add)
 38     {
 39         tree[now<<1].add+=tree[now].add;
 40         tree[now<<1|1].add+=tree[now].add;
 41         tree[now<<1].sum+=tree[now].add*(m-(m>>1));
 42         tree[now<<1|1].sum+=tree[now].add*(m>>1);
 43         tree[now].add=0;
 44     }
 45 }
 46 void UpDate (int now,int l,int r,int change)
 47 //区间[l,r]需要增加值change,now是当前节点
 48 {
 49 if (tree[now].l==l&&r==tree[now].r)
 50 //如果恰好now代表的区间就是更新的区间,一步更新,暂不向下继续更新到其子节点 ,等用到这个节点再向下更新
 51     {
 52         tree[now].add+=change;
 53         tree[now].sum+=(__int64)change*(r-l+1);
 54         return ;
 55     }
 56     if (tree[now].l==tree[now].r)
 57     return;//区间长度为1,return
 58 PushDown(now,tree[now].r-tree[now].l+1);
 59 //用到了当前节点,当前节点向下更新
 60     int m=tree[now].mid();
 61 if (r<=m)
 62 //==============|==============tree[now]的区间
 63 //    ********                 要更新的区间
 64     UpDate(now<<1,l,r,change);
 65 else if (l>m)
 66 //==============|==============tree[now]的区间
 67 //                  ********   要更新的区间
 68     UpDate(now<<1|1,l,r,change);
 69 else
 70 //==============|==============tree[now]的区间
 71 //         *************          要更新的区间
 72     {
 73         UpDate(now<<1,l,m,change);
 74         UpDate(now<<1|1,m+1,r,change);
 75     }
 76     PushUp(now);
 77 }
 78 long long int query (int now,int l,int r)
 79 {
 80     if(l==tree[now].l &&r==tree[now].r)
 81     {
 82         return tree[now].sum;
 83     }
 84     PushDown(now,tree[now].r-tree[now].l+1);//用到了当前节点,向下更新
 85     int m = tree[now].mid();
 86     long long int res = 0;
 87 if(r<=m)
 88 //==============|==============tree[now]的区间
 89 //    ********                 要查询的区间
 90 res += query(now<<1,l,r);
 91 else if(l > m)
 92 //==============|==============tree[now]的区间
 93 //                  ********   要查询的区间
 94 res += query(now<<1|1,l,r);
 95 //==============|==============tree[now]的区间
 96 //         *************          要更新的区间
 97     else
 98     {
 99        res+=query(now<<1,l,m);
100        res+=query(now<<1|1,m+1,r);
101     }
102     return res;
103 }
104 int main()
105 {
106     //freopen("de.txt","r",stdin);
107     while (~scanf("%d%d",&n,&m))
108     {
109         buildTree(1,1,n);
110         while (m--)
111         {
112             char op[5];
113             scanf("%s",op);
114             int x,y,z;
115             if (op[0]=='Q')
116             {
117                 scanf("%d%d",&x,&y);
118                 printf("%lld
",query(1,x,y));
119             }
120             else
121             {
122                 scanf("%d%d%d",&x,&y,&z);
123                 UpDate(1,x,y,z);
124             }
125         }
126     }
127     return 0;
128 }
 
原文地址:https://www.cnblogs.com/agenthtb/p/5876415.html