树状数组+二分
考虑一个简单的问题,维护一个数组,支持每次修改一个数的值,保证每时每刻每个数都为非负数。每次查询求第一个前缀和≥ k k k的下标。
对于修改,可以用树状数组、线段树等数据结构维护。
二分查找
可以在
[
l
,
r
]
[l,r]
[l,r]的范围上二分答案,
m
i
d
=
⌊
l
+
r
2
⌋
mid = \lfloor \frac{l+r}{2} \rfloor
mid=⌊2l+r⌋,验证
m
i
d
mid
mid的前缀和是否大于
k
k
k,并调整
m
i
d
mid
mid。时间复杂度
O
(
l
o
g
2
2
n
)
O(log^2_2n)
O(log22n)
如果用线段树来做,维护区间和,每次判断 x x x在左儿子还是右儿子中,若在右儿子中, x x x变为 x x x减去左儿子的区间和。时间复杂度 O ( l o g 2 n ) O(log_2n) O(log2n)
树状数组上二分
由于树状数组的特性,每个节点维护的区间长度均为
2
2
2的整数次幂,因此考虑使查询区间和时区间长度为
2
2
2的整数次幂且有节点维护。
设现在维护的树状数组
s
s
s,二分查找的区间为
(
l
,
r
]
(l,r]
(l,r]的区间,
l
l
l位置的前缀和为
l
s
u
m
lsum
lsum。
l
l
l初值为0,
r
r
r二分初值为二分上限。
当
r
−
l
r-l
r−l的值为
2
2
2的整数次幂时,
m
i
d
=
⌊
l
+
r
2
⌋
mid = \lfloor \frac{l+r}{2} \rfloor
mid=⌊2l+r⌋,否则
m
i
d
=
l
mid = l
mid=l加
(
0
,
r
−
l
)
(0,r-l)
(0,r−l)中最大的
2
2
2的整数次幂。
当
k
>
s
[
m
i
d
]
+
l
s
u
m
k > s[mid] + lsum
k>s[mid]+lsum时,
l
=
m
i
d
l = mid
l=mid,
l
s
u
m
=
l
s
u
m
+
s
[
m
i
d
]
lsum = lsum + s[mid]
lsum=lsum+s[mid],否则
r
=
m
i
d
r = mid
r=mid。
这样一直迭代,直到
l
=
r
−
1
l = r -1
l=r−1时退出。

这张图中k=
11
11
11,二分上界为
13
13
13。
补充说明:http://codeforces.com/blog/entry/71992
时间复杂度
O
(
l
o
g
2
n
)
O(log_2n)
O(log2n)。
此算法优点:速度快
局限性:只能处理从下标一开始的前缀问题,不如线段树强大。
本文介绍了如何在树状数组上使用二分查找解决数组维护与查询问题。具体场景为:维护一个非负数数组,支持修改操作,查询前缀和大于等于k的第一个下标的算法。二分查找的时间复杂度为O(log2n),并通过实例解释了树状数组在二分查询中的应用及其局限性。
753

被折叠的 条评论
为什么被折叠?



