Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
halfrost committed Apr 20, 2021
1 parent 370ec68 commit 4e6a1e3
Showing 1 changed file with 49 additions and 4 deletions.
53 changes: 49 additions & 4 deletions website/content/ChapterThree/Binary_Indexed_Tree.md
Expand Up @@ -214,7 +214,7 @@ A_{1} + A_{2} + A_{3} + ...... + A_{n}\\

线段树求区间和,把每个小区间的和计算好,然后依次 pushUp,往上更新。把 sum 换成 max 操作,含义完全相同:取出小区间的最大值,然后依次 pushUp 得到整个区间的最大值。

树状数组求区间和,是将单点增减的增量影响更新到固定区间 {{< katex >}}[i-2^{k}+1, i]{{< /katex >}}。但是把 sum 换成 max 操作,含义就变了。此时单点的增量和区间 max 值并无直接联系。暴力的方式是将该点与区间内所有值比较大小,取出最大值,时间复杂度 O(n * log n)。仔细观察树状数组的结构,可以发现不必枚举所有区间。例如更新 {{< katex >}}A_{i}{{< /katex >}} 的值,那么受到影响的树状数组下标为 {{< katex >}}i-2^{0}, i-2^{1}, i-2^{2}, i-2^{3}, ......, i-2^{k}{{< /katex >}},其中 {{< katex >}}2^{k} < lowbit(i) <= 2^{k+1}{{< /katex >}}。需要更新至多 k 个下标,外层循环由 O(n) 降为了 O(log n)。区间内部每次都需要重新比较,需要 O(log n) 的复杂度,总的时间复杂度为 {{< katex >}}(O(log n))^2 {{< /katex >}}。
树状数组求区间和,是将单点增减的增量影响更新到固定区间 {{< katex >}}[i-2^{k}+1, i]{{< /katex >}}。但是把 sum 换成 max 操作,含义就变了。此时单点的增量和区间 max 值并无直接联系。暴力的方式是将该点与区间内所有值比较大小,取出最大值,时间复杂度 O(n * log n)。仔细观察树状数组的结构,可以发现不必枚举所有区间。例如更新 {{< katex >}}A_{i}{{< /katex >}} 的值,那么受到影响的树状数组下标为 {{< katex >}}i-2^{0}, i-2^{1}, i-2^{2}, i-2^{3}, ......, i-2^{k}{{< /katex >}},其中 {{< katex >}}2^{k} < lowbit(i) \leqslant 2^{k+1}{{< /katex >}}。需要更新至多 k 个下标,外层循环由 O(n) 降为了 O(log n)。区间内部每次都需要重新比较,需要 O(log n) 的复杂度,总的时间复杂度为 {{< katex >}}(O(log n))^2 {{< /katex >}}。

```go
func (bit *BinaryIndexedTree) Add(index int, val int) {
Expand Down Expand Up @@ -261,15 +261,60 @@ n 最多经过 {{< katex >}}(O(log n))^2 {{< /katex >}} 变化,最终 n < m。

这个问题就是经典的逆序数问题,如果采用朴素算法,就是枚举 i 和 j,并且判断 A[i] 和 A[j] 的值进行数值统计,如果 A[i] > A[j] 则计数器加一,统计完后计数器的值就是答案。时间复杂度为 {{< katex >}} O(n^{2}) {{< /katex >}},这个时间复杂度太高,是否存在 {{< katex >}} O(log n) {{< /katex >}} 的解法呢?

先把数列中的数按大小顺序转化成 1 到 n 的整数,使得原数列成为一个 1,2,...,n 的数组 B,创建一个树状数组,用来记录这样一个数组 C(下标从1算起)的前缀和:若排列中的数 i 当前已经出现,则 C[i] 的值为 1 ,否则为 0。初始时数组 C 的值均为 0,从排列中的最后一个数开始遍历,每次在树状数组中查询有多少个数小于当前的数 B[j](即用树状数组查询数组 C 中的 [1,B[j]-1] 区间前缀和)并加入计数器,之后对树状数组执行修改数组 C 的第 B[j] 个数值加 1 的操作
> 如果题目换成 {{< katex >}} A[n] \in [1,10^{10}] {{< /katex >}},解题思路不变,只不过一开始再多加一步,离散化的操作
假设第一步需要离散化。先把数列中的数按大小顺序转化成 1 到 n 的整数,将重复的数据编相同的号,将空缺的数据编上连续的号。使得原数列映射成为一个 1,2,...,n 的数组 B。注意,数组 B 中存的元素也是乱序的,是根据原数组映射而来的。例如原数组是 int[9,8,5,4,6,2,3,8,7,0],数组中 8 是重复的,且少了数字 1,将这个数组映射到 [1,9] 区间内,调整后的数组 B 为 int[9,8,5,4,6,2,3,8,7,1]

再创建一个树状数组,用来记录这样一个数组 C(下标从1算起)的前缀和:若 [1, N] 这个排列中的数 i 当前已经出现,则 C[i] 的值为 1 ,否则为 0。初始时数组 C 的值均为 0。从数组 B 第一个元素开始遍历,对树状数组执行修改数组 C 的第 B[j] 个数值加 1 的操作。再在树状数组中查询有多少个数小于等于当前的数 B[j](即用树状数组查询数组 C 中的 [1,B[j]] 区间前缀和),当前插入总数 i 减去小于等于 B[j] 元素总数,差值即为大于 B[j] 元素的个数,并加入计数器。

```go
func reversePair(s string) int {
s = "9854623870"
arr, newPermutation, bit, res := make([]Element, len(s)+1), make([]int, len(s)), BinaryIndexedTree{}, 0
bit.capacity = len(s)
for i := 0; i < len(s); i++ {
arr[i+1].data = int(s[i] - '0')
arr[i+1].pos = i + 1
}
sort.Slice(arr, func(i, j int) bool {
if arr[i].data == arr[j].data {
if arr[i].pos < arr[j].pos {
return true
} else {
return false
}
}
return arr[i].data < arr[j].data
})
index := 1
newPermutation[arr[1].pos] = 1
for i := 2; i <= len(s); i++ {
if arr[i].data == arr[i-1].data {
newPermutation[arr[i].pos] = index
} else {
index++
newPermutation[arr[i].pos] = index
}
}
for i := 1; i < len(s); i++ {
bit.Add(newPermutation[i], 1)
res += i - bit.Query(newPermutation[i])
}
return res
}
```

上述代码中的 newPermutation 就是映射调整后的数组 B。遍历数组 B,按顺序把元素插入到树状数组中。例如数组 B 是 int[9,8,5,4,6,2,3,8,7,1],现在往树状数组中插入 6,代表 6 这个元素出现了。query() 查询 [1,6] 区间内是否有元素出现,区间前缀和代表区间内元素出现次数和。如果有 k 个元素出现,且当前插入了 5 个元素,那么 5-k 的差值即是逆序的元素个数,这些元素一定比 6 大。

> 如果题目换成 {{< katex >}} A[n] \in [1,10^{10}] {{< /katex >}},解题思路不变,只不过一开始再多加一步,离散化的操作。

## 2. 求区间逆序对

给定 {{< katex >}} n {{< /katex >}} 个数的序列 {{< katex >}} A[n] \in [1,2^{31}-1] {{< /katex >}},然后给出 {{< katex >}} n \in [1,10^{5}] {{< /katex >}} 次询问 {{< katex >}} [L,R] {{< /katex >}},每次询问区间 {{< katex >}} [L,R] {{< /katex >}} 中满足 {{< katex >}} L \leqslant i < j \leqslant R {{< /katex >}} 且 {{< katex >}} A[i] > A[j] {{< /katex >}} 的下标 {{< katex >}} (i,j) {{< /katex >}} 的对数。

这个问题比上一题多了一个区间限制。这个区间的限制影响对逆序对的选择。例如:[1,3,5,2,1,1,8,9],求在 [2,5] 区间内的逆序数。元素 2 在区间内,比元素 2 打的元素有 4 个。但是元素 3 在区间外,所以这个 3 不能参与逆序数的统计。

## 3. 求树上逆序对

## 4. 求第 K 大数


## 四. 二维树状数组

0 comments on commit 4e6a1e3

Please sign in to comment.