[关闭]
@Chilling 2017-02-16T17:58:55.000000Z 字数 3065 阅读 1356

POJ-3468:A Simple Problem with Integers(区间更新)

线段树


Description

给出了一个序列,你需要处理如下两种询问。

"C a b c"表示给[a, b]区间中的值全部增加c (-10000 ≤ c ≤ 10000)。

"Q a b" 询问[a, b]区间中所有值的和。

Input

第一行包含两个整数N, Q。1 ≤ N,Q ≤ 100000.

第二行包含n个整数,表示初始的序列

接下来Q行询问,格式如题目描述。

Output
对于每一个Q开头的询问,你需要输出相应的答案,每个答案一行。

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)这个概念。每次不必访问到根节点,只需要到更新的区间所在的节点就可以。例如增加了某区间的每个值后,求当前区间的最大值,即用区间长度乘以当前lazy标记即可,减少了操作的次数,提高了效率。

  1. void build(int id,int l,int r)
  2. {
  3. s[id].l=l;
  4. s[id].r=r;
  5. s[id].lazy=0;
  6. if(l==r)
  7. s[id].sum=a[l];
  8. else
  9. {
  10. int mid=(l+r)/2;
  11. build(id*2,l,mid);
  12. build(id*2+1,mid+1,r);
  13. s[id].sum=s[id*2].sum+s[id*2+1].sum;
  14. }
  15. }
  1. void pushdown(int id)
  2. {
  3. s[id*2].lazy+=s[id].lazy;
  4. s[id*2+1].lazy+=s[id].lazy;
  5. s[id*2].sum+=s[id].lazy*(s[id*2].r-s[id*2].l+1); //区间长度乘以当前lazy标记
  6. s[id*2+1].sum+=s[id].lazy*(s[id*2+1].r-s[id*2+1].l+1);
  7. s[id].lazy=0; //标记向下传递后清空
  8. }
  9. void rep(int id,int l,int r,int val)
  10. {
  11. if(l<=s[id].l&&s[id].r<=r)
  12. {
  13. s[id].lazy+=val; //可能多次被标记而没有向下传递
  14. s[id].sum+=val*(s[id].r-s[id].l+1);
  15. return; //需要更新的区间完全包含了该区间,标记该区间
  16. }
  17. if(s[id].lazy!=0) //若不是完全包含,并且这个区间有标记,标记向下传递
  18. pushdown(id);
  19. int mid=(s[id].l+s[id].r)/2;
  20. if(r<=mid)
  21. rep(id*2,l,r,val);
  22. else if(l>mid)
  23. rep(id*2+1,l,r,val);
  24. else
  25. {
  26. rep(id*2,l,r,val);
  27. rep(id*2+1,l,r,val);
  28. }
  29. s[id].sum=s[id*2].sum+s[id*2+1].sum; //根据左右子树更新当前节点的和,相当于pushup
  30. }
  1. long long sum(int id,int l,int r)
  2. {
  3. if(l<=s[id].l&&s[id].r<=r)
  4. return s[id].sum;
  5. if(s[id].lazy!=0)
  6. pushdown(id);
  7. int mid=(s[id].l+s[id].r)/2;
  8. if(r<=mid)
  9. return sum(id*2,l,r);
  10. else if(l>mid)
  11. return sum(id*2+1,l,r);
  12. else
  13. return sum(id*2,l,r)+sum(id*2+1,l,r);
  14. }

  1. #include<stdio.h>
  2. int n;
  3. long long a[100005];
  4. struct node
  5. {
  6. int l,r;
  7. long long sum,lazy;
  8. }s[100005*4];
  9. void build(int id,int l,int r)
  10. {
  11. s[id].l=l;
  12. s[id].r=r;
  13. s[id].lazy=0;
  14. if(l==r)
  15. s[id].sum=a[l];
  16. else
  17. {
  18. int mid=(l+r)/2;
  19. build(id*2,l,mid);
  20. build(id*2+1,mid+1,r);
  21. s[id].sum=s[id*2].sum+s[id*2+1].sum;
  22. }
  23. }
  24. void pushdown(int id)
  25. {
  26. s[id*2].lazy+=s[id].lazy;
  27. s[id*2+1].lazy+=s[id].lazy;
  28. s[id*2].sum+=s[id].lazy*(s[id*2].r-s[id*2].l+1);
  29. s[id*2+1].sum+=s[id].lazy*(s[id*2+1].r-s[id*2+1].l+1);
  30. s[id].lazy=0;
  31. }
  32. void rep(int id,int l,int r,int val)
  33. {
  34. if(l<=s[id].l&&s[id].r<=r)
  35. {
  36. s[id].lazy+=val;
  37. s[id].sum+=val*(s[id].r-s[id].l+1);
  38. return; //需要更新的区间完全包含了该区间,标记该区间
  39. }
  40. if(s[id].lazy!=0) //若不是完全包含,并且这个区间有标记,标记向下传递
  41. pushdown(id);
  42. int mid=(s[id].l+s[id].r)/2;
  43. if(r<=mid)
  44. rep(id*2,l,r,val);
  45. else if(l>mid)
  46. rep(id*2+1,l,r,val);
  47. else
  48. {
  49. rep(id*2,l,r,val);
  50. rep(id*2+1,l,r,val);
  51. }
  52. s[id].sum=s[id*2].sum+s[id*2+1].sum;
  53. }
  54. long long sum(int id,int l,int r)
  55. {
  56. if(l<=s[id].l&&s[id].r<=r)
  57. return s[id].sum;
  58. if(s[id].lazy!=0)
  59. pushdown(id);
  60. int mid=(s[id].l+s[id].r)/2;
  61. if(r<=mid)
  62. return sum(id*2,l,r);
  63. else if(l>mid)
  64. return sum(id*2+1,l,r);
  65. else
  66. return sum(id*2,l,r)+sum(id*2+1,l,r);
  67. }
  68. int main()
  69. {
  70. int q,i,x,y,v;
  71. char ch[3];
  72. while(scanf("%d%d",&n,&q)!=EOF)
  73. {
  74. for(i=1;i<=n;i++)
  75. scanf("%lld",&a[i]);
  76. build(1,1,n);
  77. while(q--)
  78. {
  79. scanf("%s",ch);
  80. if(ch[0]=='Q')
  81. {
  82. scanf("%d%d",&x,&y);
  83. printf("%lld\n",sum(1,x,y));
  84. }
  85. if(ch[0]=='C')
  86. {
  87. scanf("%d%d%d",&x,&y,&v);
  88. rep(1,x,y,v);
  89. }
  90. }
  91. }
  92. return 0;
  93. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注