树状数组。 数组修改某个元素的数值/求出前n个元素的和,需要在一百毫秒处理上百万个数字

Posted 安果移不动

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组。 数组修改某个元素的数值/求出前n个元素的和,需要在一百毫秒处理上百万个数字相关的知识,希望对你有一定的参考价值。

以16个数字来进行解释。

记住了为啥是16个。。

 

全部遍历求结果的话查询会很慢。

 

可以通过求和弄到同一个数组当中

这样可以计算就少了一半的时间

再一次

 

再一次

 一直这样重复。直到只剩下一个数字为止。结果不就出来了。

这样即使要求和的数字很多。我们也可以利用这些额外的数组来计算出需要的答案

 可以看到 如果我们想计算出来前15个的累加数字

那我们实际用到的数字就 31 10 9 7 四个数字

即使要计算前一百万个数字的和,我们也只需要计算十几次 二十几次的加法。大大加快了计算速度。

上面数字有些是可以完全用不到的。。

比如我们计算前2个 前 3个 前四个 前 五个。。你会发现。

完全可以不用5

所有层数的偶数个数字都是没用的。即使去掉也没有影响。

然后观察剩下的数据。。刚好16个,我们刚才说什么16个。。。。有点。。有点巧合。。

拼接起来

 组合方式也是有规律的哦

 

 

 

 求和时,我们只需要找到对应区间。将这些区间相加就可以找到答案

修改某个数据时,我们只需要向上找到包含的区间进行修改即可

 

 lowbit的使用 

lowbit 函数 精彩计算。_安果移不动的博客-CSDN博客

package com.example.learn1

fun main() 
    repeat(10) 
        println("当前是:$it 二进制是$it.toUInt().toString(radix = 2) 结果是 $lowBit2(it)")
    

fun lowBit(x: Int): Int 
    return x and (x xor (x - 1))


fun lowBit2(x: Int): Int 
    return x and (-x)

 

 

下面结合lowBit 就要进行计算了。

 

长度为1的数据。lowbit刚好为1

 第二行数据 长度为2 lowBit结果是2.

lowBit 12 结果为多少。是4 他的序号是对少 是12

 多带入几个可以发现。

lowBit(i)= 以i为结尾的序列

结论是 序号为i的序列 正好就是长度为lowBit(i) 且以i结尾的序列

有了这个规律后 计算前几个元素的和就简单多了

比如我们要计算前14个元素的和

lowBit(14) = 2

14-lowBit(14)=12

我们只需要计算前12个元素的和然后+b[14] 就对了。

我们来写一个公式

fun count(p: Int, b: List<Int>): Int 
    if (p == 0) 
        return 0
    
    println("p $p ")
    return count(p - lowBit(p), b) + b[p]
 val list = listOf(8, 6, 1, 4, 5, 5, 1, 1, 3, 2, 1, 4, 9, 0, 7, 4)
    println(count(14, list))

 

 14 12 8 然后结果是19

还有一个结论 就是 序列 b[i] 正上方的序列,正好就是 b[i+lowBit(i)]

 

所以修改值的时候只要找到上方的所有序列进行修改。

最终版来咯

fun main() 
    val list = mutableListOf(8, 6, 1, 4, 5, 5, 1, 1, 3, 2, 1, 4, 9, 0, 7, 4)
    println(count(14, list))
    println(finalCount(14, list))
    
    val res = list.subList(0, 14).sum()
    println(res)


fun lowBit(x: Int): Int 
    return x and (x xor (x - 1))


fun lowBit2(x: Int): Int 
    return x and (-x)


fun count(p: Int, b: MutableList<Int>): Int 
    if (p == 0) 
        return 0
    
    return count(p - lowBit(p), b) + b[p]


//修改某个位置的函数
fun changeIndex(p: Int, x: Int, b: MutableList<Int>, N: Int) 
    var tempP = p;
    while (tempP < N) 
        b[tempP] += x;
        tempP += lowBit(p);
    


//上方count 可以改进下。
fun finalCount(p: Int, b: MutableList<Int>): Int 
    var tempP = p;
    var result = 0;
    while (tempP > 0) 
        result += b[tempP];
        tempP -= lowBit(tempP)

    
    return result

以上是关于树状数组。 数组修改某个元素的数值/求出前n个元素的和,需要在一百毫秒处理上百万个数字的主要内容,如果未能解决你的问题,请参考以下文章

信奥一本通-树状数组模版题目-修改数列元素+求子数列元素和

Bit的树状数组

数据结构之树状数组

树状数组

c语言中如何修改数组中的元素

数组a中存放了n个整数,试求出数组中的最大元素和第二大元素的下标,并输出相应元素的值