树状数组BIT

树状数组BIT

现多用于计算前缀和,区间和,可在O(logN)时间内得到任意前缀和 。并且支持在O(logN)时间内动态单点修改

树状数组BIT

C1=A1
C2=A1+A2
C3=A3
C4=A1+A2+A3+A4
C5=A5
C6=A5+A6
C7=A7
C8=A1+A2+A3+A4+A5+A6+A7+A8

其中 C[i] = A[i - 2k+1] + A[i - 2k+2] + ... + A[i]; //k为i的二进制中从最低位到高位连续零的长度

例如i = 8(1000)时候,k = 3,可自行验证。

应用

针对一个数组A,有A0到An个元素,经过W次修改,每次修改一个元素的值,如何快速求其中任意区间内的和问题?

如何求和?

求和

以7为例,sum求和0-7的计算方法,C的下标数值如何确定,即7开始不断的取lowbit(具体实现见代码lbt)

实现

package main

import "fmt"

type Bit struct {
	BitTree []int
}
// 该函数也可写成 x&(-x)
//函数意义:求x中从最低位开始剔除一个1的数值,例如6(110),剔除最低位1转为4(100)需要减2(10),即lbt(6)=2
func (b *Bit) lbt(x int) int {
	return x - (x & (x - 1))
}

func (b *Bit) Update(x int, v int) {
	for i := x+1; i < len(b.BitTree); i += b.lbt(i) {
		b.BitTree[i] += v
	}
}

func (b *Bit) GetSum(x int) int {
	sum := 0
	for i := x+1; i > 0; i -= b.lbt(i) {
		sum += b.BitTree[i]
	}
	return sum
}

func Init(a []int) Bit {
	b := Bit{BitTree: make([]int, len(a)+1)}
	for i := 0; i < len(a); i++ {
		b.Update(i, a[i])
	}
	return b
}

func main(){
	a := []int{1,1,1,1}
	b := Init(a)
	fmt.Println(b)
}

参考

原文地址:https://www.cnblogs.com/weiweng/p/12604247.html