树状数组与线段树
树状数组与线段树
树状数组
看着这个视频学的。
想象一下,我们以这样的方式存储元素:把与a[i]之前的部分元素合存在我们的数组t[i]中,与a[i]无关的元素存在t[j]( j < i),这样,需要求前i个元素合时,需要用t[i]加上前j个元素合,而求取前j个元素就要用t[j]加上前面的无关元素,以此类推。是不是很像前缀合呢?确实很像,前缀和存储前面全部的元素,而树状数组存储部分元素,比起前缀合O(1)的时间得出区间合的优势,树状数组则需要O(logN)的时间,但是后者修改单个元素也只需要O(logN)的时间(稍后细索),稳定的时间是其最大的优势。
1. 前置知识
上面说了依照部分元素去存储,那怎么判断存储多少呢?LOW-BIT个元素。
简单的来说:low-bit,将一个数化为二进制后,最后一个1与后面的0构成其low-bit。
sample:
| 原数字 | 二进制 | low-bit | 十进制low-bit |
|---|---|---|---|
| 1 | 01 | 1 | 1 |
| 2 | 10 | 10 | 2 |
| 5 | 101 | 1 | 1 |
| 8 | 1000 | 1000 | 8 |
| 7 | 111 | 1 | 1 |
有趣的是,low-bit存在快速计算方法,以5为例:
二进制:010,反码:101,反码加1:110,计算其low-bit只需二进制并反码加一
即:
\[lowbit(x) = x\&(-x)
\]
2.原理
分成两种实现方式,前缀和与差分,前缀和用于单项修改,区间查找,差分用于区间修改、单项查找。
前缀和
这里的前缀合是指t(n)存放的是若干的元素的合
我们需要两个操作:查找元素前缀和,单项修改。
首先是查找元素前缀和,假设数组t[n],对于其中元素t[i],存放它前low-bit个的元素和,需要使用时,递加减去low-bit的t[n]
//需要前x个数字的合
ans = 0
for(; x ; x -= lowbit(x))
ans+=t[x]
return ans
//无非就是把前缀和分成logN个部分嘛
(先写到这儿)

浙公网安备 33010602011771号