• 树状数组 区间update/query


    Re

    【问题引入】

    对于区间修改、区间查询这样的简单问题,打一大堆线段树确实是不划算,今天来介绍一下区间查询+区间修改的树状数组

    【一些基础】

    树状数组的基本知识不再介绍,请自行百度

    我们假设sigma(r,i)表示r数组的前i项和,调用一次的复杂度是log2(i)

    设原数组是a[n],差分数组c[n],c[i]=a[i]-a[i-1],那么明显地a[i]=sigma(c,i),如果想要修改a[i]到a[j](比如+v),只需令c[i]+=v,c[j+1]-=v

    【今天的主要内容】

    我们可以实现NlogN时间的“单点修改,区间查询”,“区间修改,单点查询”,其实后者就是前者的一个变形,要明白树状数组的本质就是“单点修改,区间查询”

    怎么实现“区间修改,区间查询”呢?

    观察式子:
    a[1]+a[2]+...+a[n]

    = (c[1]) + (c[1]+c[2]) + ... + (c[1]+c[2]+...+c[n]) 

    = n*c[1] + (n-1)*c[2] +... +c[n]

    = n * (c[1]+c[2]+...+c[n]) - (0*c[1]+1*c[2]+...+(n-1)*c[n])    (式子①)

    那么我们就维护一个数组c2[n],其中c2[i] = (i-1)*c[i]

    每当修改c的时候,就同步修改一下c2,这样复杂度就不会改变

    那么

    式子①

    =n*sigma(c,n) - sigma(c2,n)

    于是我们做到了在O(logN)的时间内完成一次区间和查询

    一件很好的事情就是树状数组的常数比其他NlogN的数据结构小得多,实际上它的计算次数比NlogN要小很多,再加上它代码短,是OI中的利器

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 #define N 200100*8
     6 using namespace std;
     7 typedef long long ll;
     8 int n,m;
     9 ll a[N],c1[N],c2[N];
    10 struct io{
    11     char op[1<<26],*s;
    12     io()
    13     {
    14         fread(s=op,1,1<<26,stdin);
    15     }
    16     inline int read()
    17     {
    18         register int u=0;
    19         while(*s<48)s++;
    20         while(*s>32)u=u*10+*s++-48;
    21         return u;
    22     }
    23 }ip;
    24 #define read ip.read
    25 inline int lowbit(int x){return x&(-x);}
    26 void add(ll *r,int pos, ll v)
    27 {
    28     for(;pos<=n;pos+=lowbit(pos))r[pos]+=v;
    29 }
    30 ll getsum(ll *r,int pos)
    31 {
    32     ll re=0;
    33     for(;pos>0;pos-=lowbit(pos))re+=r[pos];
    34     return re;
    35 }
    36 ll sigma(int r)
    37 {
    38     ll sum1=r*getsum(c1,r),sum2=getsum(c2,r);
    39     return sum1-sum2;
    40 }
    41 ll query(int x,int y)
    42 {
    43     return sigma(y)-sigma(x-1);
    44 }
    45 int flag,x,y;ll k;
    46 int main()
    47 {
    48     n=read();
    49     for(int i=1;i<=n;i++)
    50     {
    51         a[i]=read();
    52         add(c1,i,a[i]-a[i-1]);
    53         add(c2,i,(i-1)*(a[i]-a[i-1]));
    54     }m=read();
    55     for(int i=1;i<=m;i++)
    56     {
    57         flag=read();
    58         if(flag==1)
    59         {
    60             x=read();y=read();k=read();
    61             add(c1,x,k);add(c1,y+1,-k);
    62             add(c2,x,(x-1)*k);add(c2,y+1,y*(-k));
    63         }
    64         else
    65         {
    66             x=read();y=read();
    67             printf("%lld
    ",query(x,y));
    68         }
    69     }
    70     return 0;
    71 }
    View Code

    230ms全场最快qaq

  • 相关阅读:
    Blazor实现高级表单功能
    VS2022设计WinForm多目标框架下界面缩放不一致问题
    Blazor自定义Input使用bindValue问题
    .NET6使用HttpContext.Current
    Blazor使用级联值实现Dialog关闭功能
    tomcat服务的原理和使用
    Linux安装nginx并配置ssl自签证书
    Xrdp Debian
    JD&qinglong
    PHP获取启始时间戳
  • 原文地址:https://www.cnblogs.com/mczhuang/p/7662968.html
Copyright © 2020-2023  润新知