算法模板——高级数据结构(未完待更)

1. 树状数组

名曰树状数组,那么究竟它是树还是数组呢?数组在物理空间上是连续的,而树是通过父子关系关联起来的,而树状数组正是这两种关系的结合,首先在存储空间上它是以数组的形式存储的,即下标连续;其次,对于两个数组下标 x , y ( x < y ) x,y(x < y) ,如果 x + 2 k = y x + 2^k = y ( k k 等于 x x 的二进制表示中末尾0的个数),那么定义 ( y , x ) (y, x) 为一组树上的父子关系,其中 y y 为父结点, x x 为子结点。

在这里插入图片描述
然后我们来看树状数组上的结点Ci具体表示什么,这时候就需要利用树的递归性质了。我们定义Ci的值为它的所有子结点的值 和 Ai 的总和,之前提到当i为奇数时Ci一定为叶子结点,所以有Ci = Ai ( i为奇数 )。

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

我们从中可以发现,其实Ci还有一种更加普适的定义,它表示的其实是一段原数组A的连续区间和。

树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)作为一个查询和修改复杂度都为 O ( l o g n ) O(logn) 的数据结构。下面我们就看一下这两个操作的具体实现:

求和操作

查询 [ l , r ] [l, r] 的和,即为 s u m ( r ) s u m ( l 1 ) sum(r)-sum(l-1)

int sum(int x){
	int s = 0;
	for(int i=x;i;i-=lowbit(i))
		s += c[i];
	return s;
}

更新操作

void add(int x, int v){
	for(int i=x;i<=n;i+=lowbit(i)) 
		c[i] += v;
}

lowbit函数实现

int lowbit(int x){
	return x&(-x);
}

1.1 PUIQ模型

单点更新,区域查询(标准的树状数组)

1.2 降维

1.3 二分模型

1.1 Reference

发布了176 篇原创文章 · 获赞 32 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_38204302/article/details/105389938