树状数组RMQ
来源:互联网 发布:淘宝网行业分析 编辑:程序博客网 时间:2024/05/17 10:56
转载自:http://www.cnblogs.com/ambition/archive/2011/04/06/bit_rmq.html
树状数组(Binary Index Tree)利用二进制的一些性质巧妙的划分区间,是一种编程,时间和空间上都十分理想的求区间和的算法,同样我们可以利用树状数组优美的区间划分方法来求一个序列的最值
约定以 num[] 表示原数组, 以 idx[] 表示索引数组, Lowbit(x)=x&(-x)
树状数组求和时通过构造数组 idx[] 使 idx[k]=sum(num[tk]), tk [k-Lowbit(k)+1,k], 使用同样的方法构造最值索引数组:
以最大值为例, 先讨论询问过程中不对数组做任何修改的情况, 用 idx[k] 记录 [k-Lowbit(k)+1,k] 区间内的最大值, 可以仿照求和时的方法得到:
void
Init(
int
n){
for
(
int
i=1;i<=n;i++){
for
(
int
j=i;j<=n;j+=Lowbit(j)){
idx[j]=MAX(idx[j],num[i]);
}
}
}
这种方法在每次调用该函数前都必须对数组进行初始化, 这样对于数据范围比较大的时候不是很优美, 这样我们可以改为:
void
Init(
int
n){
for
(
int
i=1;i<=n;i++){
idx[i]=num[i];
for
(
int
j=1;j<Lowbit(i);j<<=1){
idx[i]=MAX(idx[i],idx[i-j]);
}
}
}
这样, 在更新到第k个数时, 所有 t(t<k) 都已经是正确的值了, 不存在上面那个函数的情况了
然后再来看查询的问题, 对于区间 [l,r] 把该区间转化为多个的小区间再进行求最值, 方法是从后往前对每一个索引数的范围进行判断, 如在进行到第k项时,该数控制的范围是 [k-Lowbit(k)+1,k], 如果k-Lowbit(k)+1在所求的范围内的话则将该区间的最值加入最值的判断,然后转至地k-Lowbit(k),否则的话就只对第k个数进行最值判断,然后转至k-1,具体实现如下:
int
Query(
int
l,
int
r){
int
ans=num[r];
while
(
true
){
ans=MAX(ans,num[r]);
if
(r==l)
break
;
for
(r-=1;r-l>=Lowbit(r);r-=Lowbit(r)){
ans=MAX(ans,idx[r]);
}
}
return
ans;
}
该查询的复杂度为log(n)
st算法的复杂度 O(nlog(n)) / O(1) , 线段树为 O(nlog(n)) / (log(n)),树状数组 O(<nlog(n)) / O(log(n))
空间复杂度 st 为 O(nlog(n)), 线段树 O(n),常数较大 , 树状数组是 O(n)
编程上 st 和 树状数组 都比较容易实现,线段树代码较长
另外线段树灵活性较大
PKU 3264 题:
st Memory: 6372K Time: 1250MS 964B
BIT Memory: 716K Time: 1282MS 933B
SegTree 未测,要比st更大
然后我们可以进一步扩展到边查询边修改的情况
每次直接去更新父亲节点自然是不行的, 为了维护索引数组的正确性,我们在对每个父亲节点进行更新时都要查询他的所有儿子节点,在其中取最优值, 得到代码如下:
void
Modify(
int
p,
int
v,
int
n){
num[p]=v;
for
(
int
i=p;i<=n;i+=Lowbit(i)){
idx[i]=v;
for
(
int
j=1;j<Lowbit(i);j<<=1){
idx[i]=MAX(idx[i],idx[i-j]);
}
}
}
复杂度为 O(log^2(n)), HDU 1754 I hate it 437MS 1776K
另外,该方法还有一个减枝, 很容易想到,在求最大值时,当某个值更新的值大于原值的时候是没有必要再去查询儿子节点的,所以内部循环可加一个判断来判定是否需要扫描儿子节点,可能是数据问题,该题时间并没有大的变化
- RMQ问题 树状数组
- 树状数组RMQ
- 树状数组&线段树&RMQ
- LCA+RMQ+树状数组poj2763
- LCA + 树状数组 + 树上RMQ
- RMQ && 树状数组 (初学)
- RMQ问题的树状数组解法
- 树状数组整理(3.RMQ问题)
- 浅谈树状数组和RMQ问题
- hdu 5869 RMQ+二分+离线树状数组
- 树状数组求区间最值(RMQ)
- HDU 4046 Panda(RMQ 线段树 树状数组)
- 线段树,树状数组,RMQ之间的区别与联系
- 树状数组求最大值 (RMQ with Shifts)
- poj 2763 Housewife Wind (LCA转RMQ+树状数组)
- 线段树,树状数组,RMQ之间的区别与联系
- hdu5869 Different GCD Subarray Query(rmq+树状数组+gcd)
- POJ 3264——Balanced Lineup(RMQ ,segment tree,树状数组)
- 用程序去判断每个人说话的真假 - 写给新手的枚举介绍
- 雪*C语言核心知识总结一
- Lua学习笔记--简单的时间操作
- PCA 原理及其在图像压缩中的应用
- 二十三种设计模式之行为型模式之命令模式
- 树状数组RMQ
- 随心杂谈
- ss
- 基于Spring4的全注解实现Restful开发
- 居中一张图片
- ios9系统无法下载应用问题分析与解决
- Xcode 7 编译cocos2dx 报libz.dylib,libsqlite3.dylib无法打开解决办法
- ASP.Net MVC 给母版页视图传递数据
- Java基础——数组的使用