树状数组(Fenwick tree)

树状数组(Fenwick tree)

树状数组简介


树状数组主要用于查询任意两位之间的所有元素之和,而传统方法求区间和的方法如下:

 用一个sum数组来储存1-i之间的区间和,那么如果要求从i到j的区间和的话,就用sum[i]-sum[j],此时算法复杂度为n.


但是传统方法中,如果要更新一个元素值,那么此时更新就要把所有包含这个元素的区间全部遍历一遍,即算法复杂度为n

那么整个算法的复杂度为n^2

所以我们发现了树状数组这个算法,将更新与查找的算法复杂度降低至logn

lowbit函数


lowbit函数的工作是算出x的二进制的从右往左数第一个数的值

例如lowbit(6)要做的,就是:

  1. 把6转换为二进制数110
  2. 从左往右数第一个1的位置
  3. 此时lowbit(6)就=二进制的10
  4. 将(10)2转换为十进制
  5. 返回2

lowbit函数如下:

点击来查看代码

 那么这个代码是什么意思呢?

&是按位与,按位与的运算为:如果两个数均为1,则返回1,否则,返回0.

那么x&(-x)是怎么做到我们想要的预期的呢?

在电脑中的运算是这样的:

例如lowbit(6)

  1. 输入2788,并将其保存入x中
  2. 将x转换为二进制码101011100100
  3. 计算出1011的补码为0101011100100
  4. 通过补码计算出-x为1010100011100
  5. 按位与运算0000000000100

因此,我们得出按位与的运算和lowbit的运算时一样的。

树状数组的保存


我们用两个数组来保存树状数组的结构:

tree数组和ans数组

其中,ans数组为输入的元素值

而tree数组的生成就要靠ans数组了

如图,即为tree数组

如何更新树状数组


上文说过,如果用传统方法来更新ans数组中的元素的话,会耗费大量的时间。那么我们不禁有个疑问了:树状数组是怎么缩短这个时间的呢?

例如,我们将ans[2]+3

那么我们将要更新1所在的所有区间。即:

我们需要更新所有的tree[2],tree[4],tree[8]的值

也就是说,当我们要对最底层的值进行更新时,那么它相应的父情节点储蓄的和也需要进行更新。

点击展开代码

 此代码复杂度为logn

如何生成树状数组


在tree数组中,tree[i]并不表示1-i的区间和,而表示从i开始往前数lowbit(i)个数的区间和。

所以,我们需要一个算法来生成树状数组。

例如:查询从1-10的区间和:

这时,我们需要查找tree[8]+tree[10]的和

点击来查看代码

此操作的算法复杂度为logn

如何查找树状数组


如果我们要计算tree中i-j的区间和,怎么办呢?

点击来查看代码

算法复杂度为logn

例题


题目描述:

Farmer John's cows have discovered that the clover growing along the ridge of the hill (which we can think of as a one-dimensional number line) in his field is particularly good.

Farmer John has N cows (we number the cows from 1 to N). Each of Farmer John's N cows has a range of clover that she particularly likes (these ranges might overlap). The ranges are defined by a closed interval [S,E].

But some cows are strong and some are weak. Given two cows: cow i and cow j, their favourite clover range is [Si, Ei] and [Sj, Ej]. If Si <= Sj and Ej <= Ei and Ei - Si > Ej - Sj, we say that cow i is stronger than cow j.

For each cow, how many cows are stronger than her? Farmer John needs your help!

输入

The input contains multiple test cases.
For each test case, the first line is an integer N (1 <= N <= 10 5), which is the number of cows. Then come N lines, the i-th of which contains two integers: S and E(0 <= S < E <= 10 5) specifying the start end location respectively of a range preferred by some cow. Locations are given as distance from the start of the ridge.

The end of the input contains a single 0.

输出

The input contains multiple test cases.
For each test case, the first line is an integer N (1 <= N <= 10 5), which is the number of cows. Then come N lines, the i-th of which contains two integers: S and E(0 <= S < E <= 10 5) specifying the start end location respectively of a range preferred by some cow. Locations are given as distance from the start of the ridge.

The end of the input contains a single 0.

样例输入

3
1 2
0 3
3 4
0

样例输出

1 0 0

提示

Huge input and output,scanf and printf is recommended.

源码:

点击来查看源码

猜你喜欢

转载自www.cnblogs.com/Wolfbeyond/p/9451926.html