前言
话说以前学竞赛真没学好啊……好多算法都学得模模糊糊的。这篇博客主要是复习。
直接开始吧。
树状数组
树状数组,即用数组达到树形结构的作用。
树状数组时间复杂度和线段树类似,但是常数会小很多,而且写起来更快。缺点是一些复杂的区间问题不能用树状数组。
讲解
上面是一棵二叉树。也是传统线段树的结构。
树状数组的结构和其类似,但是省去了一些节点以达到用数组建树。如下示例:
若称拓展数组为
C
C
C,原数组为
A
A
A,可发现:
C
[
i
]
=
A
[
i
−
2
k
+
1
]
+
A
[
i
−
2
k
+
2
]
+
.
.
.
+
A
[
i
]
C[i]=A[i-2^k+1]+A[i-2^k+2]+...+A[i]
C[i]=A[i−2k+1]+A[i−2k+2]+...+A[i]
其中
k
k
k 为
i
i
i 的二进制中最低位到高位连续
0
0
0的长度。
根据上面的式子易得:
S
u
m
[
i
]
=
C
[
i
]
+
C
[
i
−
2
k
1
]
+
C
[
(
i
−
2
k
1
)
−
2
k
2
]
+
.
.
.
Sum[i]=C[i]+C[i-2^{k1}]+C[(i-2^{k1})-2^{k2}]+...
Sum[i]=C[i]+C[i−2k1]+C[(i−2k1)−2k2]+...
问题是 2 k 2^k 2k 如何求,易得到 2 k = i 2^k = i 2k=i & ( i (i (i ^ ( i − 1 ) ) (i - 1)) (i−1))。然而结论为 2 k = i 2^k=i 2k=i & ( − i ) (-i) (−i)。具体的证明是用分类讨论,这里不多介绍。
在树状数组中,称这个 2 k 2^k 2k为 lowbit
实现
具体不多讲了,看代码即可。
#define MAXN 100005
#define lowbit(x) x & (-x)
int C[MAXN], A[MAXN];
inline void Update(LL x,LL Val) // x位置增加 Val,注意到树状数组中x位的修改只会对x位后面的位置产生影响
{
while (x <= n)
{
C[x] += Val;
x += lowbit( x );
}
}
inline LL Query(LL x) // 1-x的前缀和
{
LL Res = 0;
while (x > 0)
{
Res += C[x];
x -= lowbit( x );
}
return Res;
}
拓展
区间更新,单点查询
方法为摒弃原数组,使用差分值建树。
规定 A [ 0 ] = 0 A[0] = 0 A[0]=0, A [ i ] = ∑ j = 1 i D [ j ] A[i] = \sum_{j=1}^{i} D[j] A[i]=∑j=1iD[j]
其中, D [ j ] = A [ j ] − A [ j − 1 ] D[j] = A[j] - A[j-1] D[j]=A[j]−A[j−1]
发现当 [ x , y ] [x,y] [x,y]的值改变,只有 D [ x ] D[x] D[x]和 D [ y + 1 ] D[y+1] D[y+1]的值发生改变。于是利用这个性质对 D D D数组建立树状数组。