树状数组
定义
l
o
w
b
i
t
(
i
)
=
2
x
lowbit(i)=2^x
lowbit(i)=2x,其中
x
x
x为满足
2
x
&
i
=
2
x
2^x\& i=2^x
2x&i=2x的最小的自然数,即
i
i
i二进制表示的最低位。
定义
⊕
\oplus
⊕为满足结合律的某种运算,这里暂时将
⊕
\oplus
⊕看作加法。
定义
b
i
t
[
x
]
=
a
x
−
l
o
w
b
i
t
(
x
)
+
1
⊕
.
.
.
⊕
a
x
−
1
⊕
a
x
=
∑
i
=
x
−
l
o
w
b
i
t
(
x
)
+
1
x
a
i
bit[x]=a_{x-lowbit(x)+1}\oplus...\oplus a_{x-1}\oplus a_x=\sum\limits_{i=x-lowbit(x)+1}^xa_i
bit[x]=ax−lowbit(x)+1⊕...⊕ax−1⊕ax=i=x−lowbit(x)+1∑xai
现在我们要求
s
u
m
r
=
∑
i
=
1
r
a
i
sum_r=\sum_{i=1}^r a_i
sumr=∑i=1rai,我们有
s
u
m
r
=
∑
i
=
1
r
a
i
=
b
i
t
[
r
]
+
a
r
−
l
o
w
b
i
t
(
r
)
+
.
.
.
+
a
2
+
a
1
=
b
i
t
[
r
]
+
s
u
m
r
−
l
o
w
b
i
t
(
r
)
sum_r=\sum_{i=1}^r a_i=bit[r]+a_{r-lowbit(r)}+...+a_2+a_1\\=bit[r]+sum_{r-lowbit(r)}
sumr=i=1∑rai=bit[r]+ar−lowbit(r)+...+a2+a1=bit[r]+sumr−lowbit(r)
特别的有
s
u
m
0
=
0
sum_0=0
sum0=0。
于是有了树状数组的递归计算:
int lowbit(int x){return x&-x;}
int query(int x)
{
int ans=0;
while(x)
{
ans+=bit[x];
x-=lowbit(x);
}
return ans;
}
这里
x
&
−
x
x\&-x
x&−x就是
l
o
w
b
i
t
(
x
)
lowbit(x)
lowbit(x),可以用组成原理的知识推导。
树状数组还需要解决的问题是添加操作:
如果将
a
x
a_x
ax加上
v
v
v,那么数组该如何变化?
对于整数
i
i
i,
b
i
t
[
i
]
bit[i]
bit[i]维护的是区间
[
i
−
l
o
w
b
i
t
(
i
)
+
1
,
i
]
[i-lowbit(i)+1,i]
[i−lowbit(i)+1,i]的和,那么对于所有满足
i
−
l
o
w
b
i
t
(
i
)
+
1
≤
x
≤
i
i-lowbit(i)+1\le x\le i
i−lowbit(i)+1≤x≤i的
i
i
i要更新
b
i
t
[
i
]
=
b
i
t
[
i
]
+
v
bit[i]=bit[i]+v
bit[i]=bit[i]+v,称满足这样的条件的
i
i
i为需更新的数。
其次,这样的
i
i
i是有无限个的,我们只需要取数组的上限
n
n
n,取所有
i
≤
n
i\le n
i≤n的
i
i
i。
首先,最小的满足这样的
i
i
i是
x
x
x本身。
其次,若
y
y
y满足
x
∈
[
y
−
l
o
w
b
i
t
(
y
)
+
1
,
y
]
x\in[y-lowbit(y)+1,y]
x∈[y−lowbit(y)+1,y],我们证明
z
=
y
+
l
o
w
b
i
t
(
y
)
z=y+lowbit(y)
z=y+lowbit(y)是大于
y
y
y最小的需更新的数。
证:
设
0
<
t
<
l
o
w
b
i
t
(
y
)
0<t<lowbit(y)
0<t<lowbit(y),则
l
o
w
b
i
t
(
y
+
t
)
≤
t
lowbit(y+t)\le t
lowbit(y+t)≤t(观察二进制易证),从而
y
+
t
−
l
o
w
b
i
t
(
y
+
t
)
+
1
≥
y
+
t
−
t
+
1
=
y
+
1
>
y
y+t-lowbit(y+t)+1\ge y+t-t+1=y+1> y
y+t−lowbit(y+t)+1≥y+t−t+1=y+1>y。
故对于任意
y
<
i
<
y
+
l
o
w
b
i
t
(
y
)
=
z
y<i<y+lowbit(y)=z
y<i<y+lowbit(y)=z的
i
i
i,都不是需更新的数。
下面再证
z
z
z是需更新的数,观察二进制易发现
l
o
w
b
i
t
(
z
)
≥
l
o
w
b
i
t
(
y
)
∗
2
lowbit(z)\ge lowbit(y)*2
lowbit(z)≥lowbit(y)∗2,则
z
−
l
o
w
b
i
t
(
z
)
≤
(
y
+
l
o
w
b
i
t
(
y
)
)
−
2
∗
l
o
w
b
i
t
(
y
)
=
y
−
l
o
w
b
i
t
(
y
)
z-lowbit(z)\le (y+lowbit(y))-2*lowbit(y)=y-lowbit(y)
z−lowbit(z)≤(y+lowbit(y))−2∗lowbit(y)=y−lowbit(y),由
z
=
y
+
l
o
w
b
i
t
(
y
)
>
y
z=y+lowbit(y)>y
z=y+lowbit(y)>y,故
x
∈
[
y
−
l
o
w
b
i
t
(
y
)
,
y
]
∈
[
z
−
l
o
w
b
i
t
(
z
)
,
z
]
x\in [y-lowbit(y),y]\in [z-lowbit(z),z]
x∈[y−lowbit(y),y]∈[z−lowbit(z),z]。
从而有了树状数组的添加过程:
int lowbit(int x){return x&-x;}
void add(int x,int v)
{
while(x<=n)
{
bit[x]+=v;
x+=lowbit(x);
}
}