树状数组

  • 树状数组是一个查询和修改复杂度都为 \(log\left(n\right)\) 的数据结构

  • 所有树状数组能够完成的线段树都能够完成,而线段树能够完成的树状数组

  • 那么既然线段树能够完成所有树状数组能够完成的,树状数组有什么用呢?

  • 因为树状数组简洁,内存小,常数小

  • 没有听说过树状数组的,可以先百度一下树状数组了解树状数组

以下的树状数组都以求和为例

  • 【单点修改,区间查询】

后面要讲的所有的树状数组操作都是建立在这个基础上的,那么利用容斥原理
\[ \sum\limits_{i=l}^rA_i\\=\sum\limits_{i=1}^rA_i-\sum\limits_{i=1}^{l-1}A_i\\=Query(r)-Query(l-1) \]

#include <cstdio>
using namespace std;
void Update(int i,int x){
    while (i<=MAX_TREE_SIZE) tr[i]+=x,i+=lowbit(i);
}
int Query(int i){
    int sum=0;
    while (i!=0) sum=sum+tr[i],i-=lowbit(i);
    return sum;
}
  • 【区间修改,单点查询】

利用差分的原理(不是差分约束系统)
先不要考虑树状数组,因为可能会搞混
\(A\) 是当前的数组
\(B\) 是差分的数组
\(B_i=A_i-A_{i-1}\),这里把 \(A_0\) 看成 \(0\)
\(A_i=\sum\limits_{j=1}^iB_j=Query(j)\)
\(B_i\) 增加 \(x\),则计算出来的 \(A_i\)\(A_{MAX\_TREE\_SIZE}\) 就会增加 \(x\)
\([l,r]\) 这段区间增加 \(x\),就是将 \(B_l\) 增加 \(x\),\(B_{r+1}\) 减去 \(x\),计算出来的 \(A\) 数组的值
如果以上能够理解的话考虑使用树状数组优化,相当于给 \(B\) 数组套上一个树状数组,每一次单点更新 \(B_l\)\(B_{r+1}\),则 \(Query_{i}\) 就是 \(A_i\) 的值

void Update(int i,int x){
    while (i<=MAX_TREE_SIZE) tr[i]+=x,i+=lowbit(i);
}
int Query(int i){
    int sum=0;
    while (i!=0) sum=sum+tr[i],i-=lowbit(i);
    return sum;
}
for (int i=1;i<=n;i++){
    scanf("%d",&A[i]);
    Update(i,A[i]-A[i-1]);
}
for (int i=1;i<=m;i++){
    scanf("%d",&type);
    if (type==1){
        scanf("%d%d%d",&L,&R,&w);
        Update(L,w),Update(R+1,-w);
    } else{
        scanf("%d",&x);
        printf("%d\n",Query(x));
    }
}
  • 【区间修改,区间查询】

还是差分,先不考虑树状数组
\(A,B\) 的定义和上边一样
\[ \sum\limits_{i=1}^nA_i\\=\sum\limits_{i=1}^n\sum\limits_{j=1}^iB_j\\=\sum\limits_{i=1}^nB_i\times(n-i+1)\\=(\sum\limits_{i=1}^nB_i)\times n-\sum\limits_{i=1}^nB_i\times(i-1) \]
显然可以用树状数组维护 \(B_i\)\(B_i\times (i-1)\)

时间复杂度 \(O(nlogn)\)

for (int i=1;i<=n;i++){
    scanf("%d",&A[i]);
    Update0(i,A[i]-A[i-1]);
    Update1(i,(A[i]-A[i-1])*(i-1))
}
scanf("%d",&type);
if (type==1){
    scanf("%d%d%d",&L,&R,&w);
    Update0(L,w),Update0(R+1,-w);
    Update1(L,k*(L-1)),Update1(R+1,-k*R);
} else{
    scanf("%d%d%d",&L,&R,&x);
    printf("%d\n",R*Query0(y)-Query1(c[1])-(L-1)*Query0(L-1)+Query1(L-1));
}
posted @ 2018-03-16 23:07 xay5421 阅读(...) 评论(...) 编辑 收藏