• 数据结构树状数组(二)


    复习笔记-树状数组(二)

    树状数组(一)

    略微进阶的操作

    在树状数组(一)中,身为懒得打线段树(有时候都未必会打)的蒟蒻,我安利了一波树状数组,并且介绍了区间查询和单点修改的基本操作。那么,对基础的树状数组进行一些修改,结合差分,就可以同时进行区间修改和单点查询。

    差分数组

    存储方式

    差分数组是相较于前缀和的一种截然相反的存储方式,前缀和的每个数表示原数组的前缀和,而差分数组的每个数表示原数组这个数和上一个数的差,也就是说

    C1=A1

    Cx=Ax-Ax-1

    那么容易推出

    C1+C2+...+Cm=Am

    也就是说,差分数组元素的前缀和等于原数组该元素的值,这就是我说它与前缀和截然相反的第一个原因。

    优势

    差分数组由于每个数存的是与上一个数的差,可以理解成存的是数据的波动。那么,需要区间修改时,也就相当于区间内波动不变,区间左端波动上升,区间右端波动下降。这样就可以用O(1)复杂度完成区间修改。也就是说

    如果把第x到第y加上k,只需要把差分数组第x个元素+k,第y+1个元素-k,就相当于完成了区间修改,只需要修改两处。

    这是差分数组的修改的基础代码

    1 void add(int x,int y,int k){
    2     c[x] += k;
    3     c[y + 1] -= k;
    4 }

    综上,差分数组可以O(1)完成区间修改。由于前缀和可以O(1)完成区间查询,这就是我说这两者相反的第二个原因

    差分数组与树状数组的结合

    上面我叭叭了半天差分数组不是瞎叭叭,而是要与树状数组进行结合。

    差分数组与树状数组特点对比:

    ————————————————————————————

    差分数组:前缀和表示原数,可以用两次单点修改完成区间修改

    树状数组:可以快速进行单点修改和查询前缀和

    ————————————————————————————

    对比以上,不难想到,如果对差分数组建立树状数组,就可以对差分数组进行前缀和查询达到单点查询的目的,运用两次单点修改来完成区间修改的目的

    例题与程序实现

    P3368

    这道模板题要求完成区间修改和单点查询

    那么利用差分数组与树状数组的结合,就可以这样完成

     1     #include<bits/stdc++.h>
     2     using namespace std;
     3     int n,m,l,r,x;
     4     long long c[500010],k,a;
     5     int lowbit(int x){
     6         return x&(-x);
     7     }
     8     void add(int x,long long y){
     9         while(x<=n){
    10             c[x]+=y;
    11             x+=lowbit(x);
    12         }
    13     }
    14     long long sum(int x){
    15         long long cnt=0;
    16         while(x){
    17             cnt+=c[x];
    18             x-=lowbit(x);
    19         }
    20         return cnt; 
    21     }
    22     int main(){
    23         scanf("%d%d",&n,&m);
    24         long long now=0;
    25         for(int i=1;i<=n;i++){
    26             scanf("%lld",&a);
    27             add(i,a-now);
    28             now=a;
    29         }
    30         while(m--){
    31             scanf("%d",&x);
    32             if(x==1){
    33                 scanf("%d%d%lld",&l,&r,&k);
    34                 add(l,k);
    35                 add(r+1,-k);
    36             }
    37             else{
    38                 int s;
    39                 scanf("%d",&s);
    40                 printf("%lld\n",sum(s));
    41             }
    42         }
    43         return 0;
    44 }
  • 相关阅读:
    一道看似简单的sql需求却难倒各路高手
    MahApps.Metro怎么调用消息窗口
    CodeSmith Generator 7.0.2激活步骤
    8款图表插件推荐
    VS的代码分析工具
    RDLC系列之六 打印纸张的大小(未解决)
    初识python
    应用程序的更新
    Expression<Func<T,TResult>>和Func<T,TResult>
    HTML5 history新特性pushState、replaceState
  • 原文地址:https://www.cnblogs.com/Juruo1103/p/9960157.html
Copyright © 2020-2023  润新知