本来不想写的 但最近新的算法也都学不进去 也答应了同学要写几个渣渣算法给他看 就顺便当作回溯吧。。。
算法顺序 无重要性难易之分 想到什么了又会的就写点什么
今天 我们一起来撸---树状数组
嗯 其实我是先接触了线段树 再去接触树状数组的 总体感觉 线段树应用范围比树状数组更广泛 但数组数组 更加有效率 代码也简洁 理解起来也不难 是个值得去好好掌握的算法 关于它的定义 我就做下大自然的搬运工 给出它在百度百科的定义
-------树状数组(Binary Indexed Tree(BIT), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值。
树状数组的用法一般分2种:
1.插点问线(也是最基础的)
直接给出它的一般用到的3个函数了这里(有任何不懂得 可以参考其他大牛de博客讲解)
int lowbit(int index)
{
return x&-x;
}
void update(int index,int num)
{
while(index<=n)
{
tree[index]+=num;
index+=lowbit(n);
}
}
int getSum(int index)
{
int sum=0;
while(index>=1)
{
sum+=tree[index];
index-=lowbit(index);
}
return sum;
}
具体解释就不给出了 今天还是想点睡了 该死的学校明天还要晨跑,关于树状数组的另一种应用 插线问点 就明天再说吧 要是状态好点 再讲讲我对树状数组的理解
悲惨的逃了思修 和辅导员在寝室邂逅…… 继续开始昨天未完成的吧
2.插线问点
其实 插线问点 与插点问线 的区别就是 区间更新与单点更新的区别 和 单点询问与区间询问的区别, 其实我们有2种写法,对应着2种不同方式的我们在main函数中的表达方式
我们先来讲第1种 3个函数完全和上面相同 这个时候我们需要更新 begin end num这3个参数 即在begin---end区间分别加上num(正负没有关系)
那么 我们就可以这样来写(这是核心步骤Key)
update(begin,num);//更新从开始点到最大值的所有节点
update(end+1,-num);//将多更新的部分 即结束点以后的所增加的全部抵消
至于查询的话 就很简单了 直接
getSum(int index)
现在再讲第2种 函数发生稍许变化的 自然main 中update的写法也将发生变化
void update(int index,int num)
{
while(index>=1)
{
tree[index]+=num;
index-=lowbit(index);
}
}
int getSum(int index)
{
int sum=0;
while( index<=n )
{
sum++tree[index];
index+=lowbit(index);
}
return sum;
}
update(begin-1,-num);
update(end,num);
其实 你仔细观察 会发现 这2种写法 如果我们将第二种的函数名改变一下 那么它又是相同的。。
只希望不要误人子弟 还是去看权威大牛博客 学习算法比较好
纯粹自娱自乐.......