树状数组+二分

考虑一个简单的问题,维护一个数组,支持每次修改一个数的值,保证每时每刻每个数都为非负数。每次查询求第一个前缀和≥kk的下标。

对于修改,可以用树状数组、线段树等数据结构维护。

二分查找
可以在[l,r][l,r]的范围上二分答案,mid=l+r2mid = \lfloor \frac{l+r}{2} \rfloor,验证midmid的前缀和是否大于kk,并调整midmid。时间复杂度O(log22n)O(log^2_2n)

如果用线段树来做,维护区间和,每次判断xx在左儿子还是右儿子中,若在右儿子中,xx变为xx减去左儿子的区间和。时间复杂度O(log2n)O(log_2n)

树状数组上二分

由于树状数组的特性,每个节点维护的区间长度均为22的整数次幂,因此考虑使查询区间和时区间长度为22的整数次幂且有节点维护。
设现在维护的树状数组ss,二分查找的区间为(l,r](l,r]的区间,ll位置的前缀和为lsumlsumll初值为0,rr二分初值为二分上限。
rlr-l的值为22的整数次幂时,mid=l+r2mid = \lfloor \frac{l+r}{2} \rfloor,否则mid=lmid = l(0,rl)(0,r-l)中最大的22的整数次幂。
k>s[mid]+lsumk > s[mid] + lsum时,l=midl = midlsum=lsum+s[mid]lsum = lsum + s[mid],否则r=midr = mid
这样一直迭代,直到l=r1l = r -1时退出。
树状数组上二分
这张图中k=1111,二分上界为1313
补充说明:http://codeforces.com/blog/entry/71992
时间复杂度O(log2n)O(log_2n)

此算法优点:速度快
局限性:只能处理从下标一开始的前缀问题,不如线段树强大。

相关文章: