You have N integers, A1A2, ... , 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 A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+1, ... , Ab.

Output

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

Sample Input

  1. 10 5
  2. 1 2 3 4 5 6 7 8 9 10
  3. Q 4 4
  4. Q 1 10
  5. Q 2 4
  6. C 3 6 3
  7. Q 2 4

Sample Output

  1. 4
  2. 55
  3. 9
  4. 15

题意:

  • [1,n]区间每个点有初始值,C(x,y,z)操作再[x,y]区间每个点加值z; Q(x,y)询问[x,y]区间的和。

思路:

  • 显然,线段树+lazy可以很好地解决区间修改问题。

那么问题来了:

  • 如果非要用树状数组呢?当然可以对修改区间[x,y]的没一个点进行操作,但是一次修改的复杂度就是长度L*lgn,显然是不行的。

我们从前缀和的思路来解决这个问题,我们以前都用过差分来记录前缀和,然后O(1)地得到区间和:

例如,[L,R]区间+x ,则sum[L]+=x;  xum[R+1]-=x;最后sum[i]+=sum[i-1];就可以做差得到区间和了。

但是这里有修改操作,每次询问都sum[i]+=sum[i-1]累加一次肯定是不行的,正确方法如下。

  • STEP1:更新操作:把[l,r]所有的数加上x,可以看做把[l,n]所有数加上x,再把[r+1,n]所有数 减去d。那我们引入一个新的数组delta[n],delta[i]记录了       [i,n]每个数的增量。操作就转化为了 delta[l]+=x,delta[r+1]-=x;
  • STEP2:查询操作:求[l,r]的和,当然是看做求sum[1,r]-sum[1,l-1]啦。就是求sum(x)。 首先,要加上原数组的基数前缀和origin[x],这个一开始就能求出来:   sum[x]=origin[x]=Σa[i];
  • STEP3,考虑delta数组,delta[1]为[1,x]贡献了x个delta[1],delta[2]为[2,x]贡献了x-1个delta[2], 以此类推,delta[i]贡献了(x+1-i)个delta[i]。那么               sum[x]=origin[x]+delta[1]*x+delta[2]*(x-1)+...delta[x] = origin[x]+(x+1)*Σdelta[i]-Σ(i*delta[i]);

这样就转化为了三个树状数组:orgin可以预处理得到,后面两个可以单点更新得到。

对比:

虽然总的来说,线段树能实现的东西比树状数组多。但是能用树状数组解决的方案一般会再空间时间代码量上优于线段树,而且不容易写错,不要问我为什么知道,QwQ。而且二维树状数组也很好写,而线段树。。。。

线段树代码:

  1. #include<cmath>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<iostream>
  6. #include<algorithm>
  7. using namespace std;
  8. #define ll long long
  9. const int maxn=;
  10. int n,m;int a[maxn];
  11. struct TREE
  12. {
  13. ll sum[maxn<<];int lazy[maxn<<];
  14. void build(int Now,int l,int r)
  15. {
  16. lazy[Now]=;
  17. if(l==r) { sum[Now]=a[l]; return;}
  18. int Mid=(l+r)>>;
  19. build(Now<<,l,Mid);
  20. build(Now<<|,Mid+,r);
  21. pushup(Now);
  22. }
  23. void add(int Now,int l,int r,int x,int y,int val)
  24. {
  25. if(x<=l&&y>=r) { sum[Now]+=(ll)(r-l+)*val;lazy[Now]+=val; return ;}
  26. pushdown(Now,l,r); int Mid=(l+r)>>;
  27. if(y<=Mid) add(Now<<,l,Mid,x,y,val);
  28. else if(x>Mid) add(Now<<|,Mid+,r,x,y,val);
  29. else add(Now<<,l,Mid,x,Mid,val),add(Now<<|,Mid+,r,Mid+,y,val);
  30. pushup(Now);
  31. }
  32. ll query(int Now,int l,int r,int x,int y)
  33. {
  34. if(x<=l&&y>=r) return sum[Now];
  35. pushdown(Now,l,r); int Mid=(l+r)>>;
  36. if(y<=Mid) return query(Now<<,l,Mid,x,y);
  37. else if(x>Mid) return query(Now<<|,Mid+,r,x,y);
  38. else return query(Now<<,l,Mid,x,Mid)+query(Now<<|,Mid+,r,Mid+,y);
  39. pushup(Now);
  40. }
  41. void pushup(int Now) { sum[Now]=sum[Now<<]+sum[Now<<|];}
  42. void pushdown(int Now,int l,int r)
  43. {
  44. int Mid=(l+r)>>;
  45. lazy[Now<<]+=lazy[Now];sum[Now<<]+=(ll)(Mid-l+)*lazy[Now];
  46. lazy[Now<<|]+=lazy[Now];sum[Now<<|]+=(ll)(r-Mid)*lazy[Now];
  47. lazy[Now]=;
  48. }
  49. }Tree;
  50. int main()
  51. {
  52. while(~scanf("%d%d",&n,&m)){
  53. for(int i=;i<=n;i++) scanf("%d",&a[i]);
  54. Tree.build(,,n);
  55. for(int i=;i<=m;i++){
  56. char opt[];int x,y,z;
  57. scanf("%s",opt);
  58. if(opt[]=='Q') scanf("%d%d",&x,&y),printf("%lld\n",Tree.query(,,n,x,y));
  59. else scanf("%d%d%d",&x,&y,&z),Tree.add(,,n,x,y,z);
  60. }
  61. } return ;
  62. }

树状数组代码:

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<iostream>
  4. #include<algorithm>
  5. #define ll long long
  6. using namespace std;
  7. const int maxn=;
  8. ll a[maxn],b[maxn],c[maxn];
  9. char opt[];int n,m;
  10. int lowbit(int x) {return x&(-x);}
  11. void add(int x,int val)
  12. {
  13. for(int i=x;i<=n+;i+=lowbit(i))
  14. b[i]+=val,c[i]+=x*val;
  15. }
  16. ll query(int x)
  17. {
  18. ll res=a[x];
  19. for(int i=x;i;i-=lowbit(i)) res+=b[i]*(x+);
  20. for(int i=x;i;i-=lowbit(i)) res-=c[i];
  21. return res;
  22. }
  23. int main()
  24. {
  25. while(~scanf("%d%d",&n,&m)){
  26. for(int i=;i<=n;i++) scanf("%lld",&a[i]),a[i]+=a[i-];
  27. for(int i=;i<=n;i++) b[i]=c[i]=;
  28. while(m--){
  29. scanf("%s",opt); int x,y,z;
  30. if(opt[]=='Q')scanf("%d%d",&x,&y),printf("%lld\n",query(y)-query(x-));
  31. else scanf("%d%d%d",&x,&y,&z),add(x,z),add(y+,-z);
  32. }
  33. } return ;
  34. }

POJ3468 A Simple Problem with Integers(数状数组||区间修改的RMQ问题)的更多相关文章

  1. POJ3468 A Simple Problem With Integers 树状数组 区间更新区间询问

    今天学了很多关于树状数组的技巧.一个是利用树状数组可以简单的实现段更新,点询问(二维的段更新点询问也可以),每次修改只需要修改2个角或者4个角就可以了,另外一个技巧就是这题,原本用线段树做,现在可以用 ...

  2. 线段树---poj3468 A Simple Problem with Integers:成段增减:区间求和

    poj3468 A Simple Problem with Integers 题意:O(-1) 思路:O(-1) 线段树功能:update:成段增减 query:区间求和 Sample Input 1 ...

  3. A Simple Problem with Integers(树状数组HDU4267)

    A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others) Memory Limit: 32768/32768 K (J ...

  4. POJ3468 A Simple Problem with Interger [树状数组,差分]

    题目传送门 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 1 ...

  5. poj 3468 A Simple Problem with Integers【线段树区间修改】

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 79137   ...

  6. 题解报告:poj 3468 A Simple Problem with Integers(线段树区间修改+lazy懒标记or树状数组)

    Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...

  7. HDU 4267 A Simple Problem with Integers --树状数组

    题意:给一个序列,操作1:给区间[a,b]中(i-a)%k==0的位置 i 的值都加上val  操作2:查询 i 位置的值 解法:树状数组记录更新值. 由 (i-a)%k == 0 得知 i%k == ...

  8. poj3468 A Simple Problem with Integers(线段树区间更新)

    https://vjudge.net/problem/POJ-3468 线段树区间更新(lazy数组)模板题 #include<iostream> #include<cstdio&g ...

  9. POJ 3468 A Simple Problem with Integers(线段树区间修改及查询)

    Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...

随机推荐

  1. iOS多线程与网络开发之多线程概述

    郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠.支持郝萌主,捐赠数额任意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 游戏官方下 ...

  2. [水]ZOJ1201

    给原排列 求 其前面有多少个数比他大. 给每一个数1...2..n前面有多少个数比他大,求原序列 第一个直接统计 第二个从1開始找出第inv[i]+1个空位置放进去就好 printf里的format ...

  3. 微服务之旅:从Netflix OSS到 Istio Service Mesh

    在这篇文章中,我们从Netflix开始,通过Envoy和Istio的崛起,快速浏览微服务的历史. 微服务是具有边界上下文的松散耦合服务,使您能够独立开发,部署和扩展服务.它还可以定义为构建独立开发和部 ...

  4. 浅谈java反序列化工具ysoserial

    前言 关于java反序列化漏洞的原理分析,基本都是在分析使用Apache Commons Collections这个库,造成的反序列化问题.然而,在下载老外的ysoserial工具并仔细看看后,我发现 ...

  5. 触发器 (Delete Update)

    --delete触发器IF(EXISTS(SELECT * FROM sysobjects WHERE name='T_PlanQtyDelete'))DROP TRIGGER T_PlanQtyDe ...

  6. Mysql 免密码登录,修改密码及忘记密码操作

    ----免密码登陆 方式一 my.cnf增加[client]标签 [client] user="root" password="你的密码" 单对定义不同的客户端 ...

  7. JavaScrip函数与声明表达式

    首先我们看下函数的两种命名方式 1.函数声明,声明一个函数 function test1(){ var a=0; console.log(a); //左一些操作... } 执行结果如下 我们看一下,无 ...

  8. 06 redis中set结构及命令详解

    集合 set 相关命令 集合的性质: 唯一性,无序性,确定性 注: 在string和link的命令中,可以通过range 来访问string中的某几个字符或某几个元素 但,因为集合的无序性,无法通过下 ...

  9. java中的 equals + hashCode

    [0]README 0.1)本文转自 core java volume 1, 旨在理清 equals + hashCode方法: [1]equals方法 1.1) Object中的 equals 方法 ...

  10. ndk javah配置

    Location: C:\Program Files\Java\jdk1.6.0_25\bin\javah.exe Working Directory: ${project_loc} Argument ...