• 树状数组——一个简单的整数问题2


    树状数组——一个简单的整数问题_北岭山脚鼠鼠的博客-CSDN博客的升级版 

    传送门:243. 一个简单的整数问题2 - AcWing题库

    思路:原本简化版的是区间增加和单点查询,先在变成了去区间增加+区间查询,难度瞬间上升

    在原本的问题里面,b数组的前缀和\sum_{i=1}^{x} b[i]就是增加过后a[x]增加的值。

    到这里后对于某一个区间[1,x]增加的值就是\sum_{i=1}^{x}\sum_{j=1}^{i} b[j]

    又可以改写成\sum_{i=1}^{x}(x-i+1)*b[i]==(x+1)\sum_{i=1}^{x}b[i]-\sum_{i=1}^{x}i*b[i]

    具体推导过程如下图:

     结合上述的全部需要做的操作就是,建两个树状数组c0和c1,一个用来存上图中红加黑的部分,一个用来存红色的部分。

    对于每条增加指令有如下2步

    1.在c0中 ,c0[l]+=d ,  c0[r+1]- = d;

    2.在c1中,c1[l]+=l*d, c1[r+1]- =(r+1)*d;

     靠c1和c0就可以做到(x+1)\sum_{i=1}^{x}b[i]-\sum_{i=1}^{x}i*b[i],这里求的是区间内整体增加的数值。

    对原序列a改造成前缀和数组a即可。

    代码:
     

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. typedef long long ll;
    8. const int N=1e5+10;
    9. ll c[2][N];
    10. ll a[N];
    11. ll sum[N];
    12. int n,m;
    13. int lowbit(int x)//作用:得到x的二进制下最小的2的次幂
    14. {
    15. return x&(-x);
    16. }
    17. void add(int k ,int x,int y)
    18. {
    19. for(;x<=n;x+=lowbit(x)) c[k][x]+=y;
    20. }
    21. ll ask(int k,int x)
    22. {
    23. ll ans=0;
    24. for(;x;x-=lowbit(x)) ans+=c[k][x];
    25. return ans;
    26. }
    27. int main()
    28. {
    29. scanf("%d%d",&n,&m);
    30. for(int i=1;i<=n;i++)
    31. {
    32. scanf("%lld",&a[i]);
    33. a[i]+=a[i-1];
    34. }
    35. while(m--)
    36. {
    37. char op[2];
    38. int l,r;
    39. scanf("%s%d%d",op,&l,&r);
    40. if(op[0]=='Q')
    41. {
    42. ll ans=a[r]-a[l-1];
    43. ans+=(r+1)*ask(0,r)-l*ask(0,l-1);
    44. ans-=ask(1,r)-ask(1,l-1);
    45. printf("%lld\n",ans);
    46. }else
    47. {
    48. int x;
    49. scanf("%d",&x);
    50. add(0,l,x);
    51. add(0,r+1,-x);
    52. add(1,l,l*x);
    53. add(1,r+1,-(r+1)*x);
    54. }
    55. }
    56. return 0;
    57. }

    线段树做法:

    思路:众所周知,线段树可以支持O(logn)的时间复杂度的区间查询,但如果要进行区间修改的话会导致所有区间的在该区间内的节点的子树下的子节点的信息都要被修改,时间复杂度度为O(N).

    如果之后却根本没有用到修改后的区间的信息则前面的修改操作都是浪费时间的,所以这里我们要给当前节点的区间都在修改区间内的节点都加上一个懒标记,并完成当前节点的修改,而至于该节点下的子树的修改则是留到下一次查询或者区间修改的时候将懒标记下传。

    代码:
     

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. typedef long long ll;
    8. typedef pair<int,int> PII;
    9. const int N=1e5+10;
    10. struct tree
    11. {
    12. int l, r;
    13. ll sum,add;
    14. }t[N<<2];
    15. ll a[N];
    16. int n,m;
    17. void pushdown(int p)
    18. {
    19. if(t[p].add)
    20. {
    21. t[p*2].sum+=t[p].add*(t[p*2].r-t[p*2].l+1);
    22. t[p*2+1].sum+=t[p].add*(t[p*2+1].r-t[p*2+1].l+1);
    23. t[p*2].add+=t[p].add;
    24. t[p*2+1].add+=t[p].add;
    25. t[p].add=0;
    26. }
    27. }
    28. void build(int p,int l,int r)
    29. {
    30. t[p].l=l;
    31. t[p].r=r;
    32. if(l==r) {t[p].sum=a[l];return ;}
    33. int mid=(l+r)/2;
    34. build(2*p,l,mid);
    35. build(2*p+1,mid+1,r);
    36. t[p].sum=t[p*2].sum+t[p*2+1].sum;
    37. }
    38. void change (int p,int l,int r,int d)
    39. {
    40. if(l<=t[p].l&&t[p].r<=r)
    41. {
    42. t[p].sum+=(ll) d*(t[p].r-t[p].l+1);
    43. t[p].add+=d;
    44. return;
    45. }
    46. pushdown(p);
    47. int mid=(t[p].l+t[p].r)/2;
    48. if(l<=mid) change(2*p,l,r,d);
    49. if(r>mid) change(2*p+1,l,r,d);
    50. t[p].sum=t[p*2].sum+t[p*2+1].sum;
    51. }
    52. ll ask(int p,int l,int r)
    53. {
    54. if(l<=t[p].l&&t[p].r<=r) return t[p].sum;
    55. pushdown(p);
    56. int mid=(t[p].r+t[p].l)>>1;
    57. ll sum=0;
    58. if(l<=mid) sum+=ask(2*p,l,r);
    59. if(r>mid) sum+=ask(2*p+1,l,r);
    60. return sum;
    61. }
    62. int main()
    63. {
    64. scanf("%d%d",&n,&m);
    65. for(int i=1;i<=n;i++)
    66. scanf("%lld",&a[i]);
    67. build(1,1,n);
    68. while(m--)
    69. {
    70. char op[2];
    71. int l,r,d;
    72. scanf("%s",op);
    73. if(op[0]=='Q')
    74. {
    75. scanf("%d%d",&l,&r);
    76. printf("%lld\n",ask(1,l,r));
    77. }else
    78. {
    79. scanf("%d%d%d",&l,&r,&d);
    80. change(1,l,r,d);
    81. }
    82. }
    83. return 0;
    84. }

  • 相关阅读:
    Python语句和循环
    【计算机网络】P1 计算机网络概念、组成、功能、分类、标准化工作以及性能评估指标
    Lattice库联合ModelSim仿真FIFO
    Java数组
    创建一个Django项目
    【leetcode】【2022/8/18】1224. 最大相等频率
    腾讯面试真题 | 没在我八股文列表里。。。
    java IO模型(BIO,NIO,AIO)
    《web课程设计》基于HTML+CSS+JavaScript典的中医药大学网(11个页面)
    [plugin:vite:css] [sass] Undefined mixin.
  • 原文地址:https://blog.csdn.net/m0_62327332/article/details/126898106