[树状数组] 笔记

概要

树状数组
是指一个数组C里存储着另一组数A一部分的和
C[i]=A[i]+A[i-1]+….+A[i-2^k+1]
k指i二进制形式,末位1的位数(最后一位的位数从0开始)
ex: i = 6 = 0110, k = 1, C[ i ] = A[ 6 ] + A[ 5 ]

RT:
树状数组

我的理解它是按照二进制最低位1的位置来分层
如:
i = xxx1(奇数) 则只保存当前index的值(height = 1 )(叶子结点)
i = xx10 (2的奇数倍) 保存(包括自己的)往前两个数的和 ( height = 2 )
i = x100(2^2 的奇数倍) 保存往前四个数的和 ( height = 3 )

以此类推,来达到最快求和

计算

提取出最末位的1

方法:lowbit = k & (-k) (-k = ~k + 1 )

各位之间的关系

要想添加或计算一段数的和,就需要知道该节点与底层节点哪些节点有关系
方法:k = k + lowbit ( k )

ex:如图可以发现C[1],C[2], C[4], C[8]之间存在联系
如果改变了C[1]的值,则C[2], C[4], C[8]也要跟着修改
这种关系是怎么传递的?
依旧和lowbit有关
1 = 0001, lowbit(1) = 0001 = 1
1 + 1 = 2 就传递到了高度为2的位置
同理
2 = 0010, lowbit(2) = 0010 = 2
2 + 2 = 4 传递到h = 3

换一个C[6]
i = 6 = 0110, lowbit(6) = 0010 = 2
6 + 2 = 8 传递到h = 4

代码

#include <cstdio>
#include <iostream>
#define n 10
using namespace std;

int C[ n + 1 ];

int lowbit ( int k ) { return k & ( -k ); } //取最低位的1

void write ( int k, int a ) { //保存新的数进入数组
        while ( k <= n ) { //当k不超过数组的最大值,则不断从下到向上修改相关联的数据
                C[ k ] += a;       //修改关联值
                k += lowbit ( k ); //计算下一个k的位置
        }
}

int getsum ( int k ) { //从上到下求和
        int sum = 0;
        while ( k ) {
                sum += C[ k ];
                k -= lowbit ( k );
        }
        return sum;
}

int main () {
        for ( int i = 1; i <= n; i++ ) {
                int a;
                cin >> a;
                write ( i, a );
                printf ( "Num:%d   %d            ", i, C[ i ] );
                printf ( "Sum:%d   %d\n", i, getsum ( i ) );
        }
        return 0;
}

运行结果

1 2 3 4 5 6 7 8 9 10
Num:1    1            Sum:1    1
Num:2    3            Sum:2    3
Num:3    3            Sum:3    6
Num:4   10            Sum:4   10
Num:5    5            Sum:5   15
Num:6   11            Sum:6   21
Num:7    7            Sum:7   28
Num:8   36            Sum:8   36
Num:9    9            Sum:9   45
Num:10  19            Sum:10  55
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值