首页 > 其他分享 >树状数组

树状数组

时间:2023-02-20 11:36:52浏览次数:46  
标签:树状 差分 查询 数组 区间 我们

树状数组介绍

首先我们需要知道树状数组可以维护一些什么值,树状数组主要维护的值就是区间的前缀和。因此普通的树状数组需要满足结合律和可差分的性质。比如乘法、加法、异或。
然后就是树状数组是怎么把区间差分为不重不漏的子区间的呢。
首先我们假设一个数x的二进制位里面包含1的位置为\(a_{i_1},a_{i_2}...a_{i_n\).也就是\(x=2^{i_1}+2^{i_2}+...+2^{i_n}\)所以我们可以将这个区间[1,x]拆分为:
1.长度是\(2^{i_1}的小区间[1,2^{i_1}]\)
2.长度是\(2^{i_2}\)的小区间\([2^{i_1+1},2^{i_1}+2^{i_2}]\)
.......
n.长度为\(2^{i_n}\)的小区间\([2^{i_1}+2^{i_2}+....2^{i_{n-1}}+1,2^{i_1}+2^{i_2}+...+2^{i_n}]\)
然后比如求区间长度就可以使用lowbits函数就好了,因此我们可以得出来c[x]管辖的去区间是[l(x),x].其中\(l(x)=x-lowbits(x)+1\).
因此我们如果需要查询某一个区间就可以不断地减去lowbits(x)然后得到他管辖的那个子区间。
所以区间查询就暂时搞定了。
那么单点修改呢:
单点修改其实就是区间查询的你操作,就是不断得到往前面递推出来他的其他的管辖区间。也就是一个是减,一个是加。我们可以看下下面这张图:

我们一定需要注意的是单点修改才是建树的过程,查询的一个过程并不是哦。我们可以发现通过这样子的建树使得管辖的区间并没有重复和遗漏。
这里我们可以知道一个很重要的性质:

也就是上面所说的管辖的区间是没有重复和遗漏的,这也就使得我们在修改的时候并不会出现某一个点对其他的区间重复贡献了的问题。
一定要注意我们查询和我们的建树过程是不一样,比如查询7(111)->6(110)->4(100)->0.我们可以发现这是不会出现查询了4还会查询他的子区间2的情况的
这还是很神奇的,其实主要是我们第一步也就是将x划分\(2_i\)的子区间是正确的,而我们建树的过程就是划分区间的一个逆过程,也就是从后面往前面递推。所以这个也是正确的,并且修改和查询出来的结果都是不重复不遗漏的。


相关用途

下面讲述下他的一个用途:
(1)求区间的前缀和,异或和。还有一个需要知道的地方就是如果是区间修改,那么我们就需要看可不可以转换为对应的差分操作。
(2)树上做差分,以及差分和dp相结合。
(3)就是转换为对应的权值树状数组。
什么是权值树状数组呢:

其实权值树状数组维护的是一个相对的关系,所以一般都需要使用离散化。
离散化
这个的用途一般有求逆序对....

特殊性质

其实树状数组也是可以维护不可以差分的情况的,具体的看这篇博客把。
不可差分

时间复杂分析

这个我们理解了算法的本质之后就可以发现建树也就是add操作和ask都是logn的时间度,但是因为需要查询n个点所以总的时间复杂度是O(nlogn).

标签:树状,差分,查询,数组,区间,我们
From: https://www.cnblogs.com/xyh-hnust666/p/17136694.html

相关文章

  • react中类组件和函数组件的理解?有什么区别
    react中类组件和函数组件的理解?有什么区别一、类组件类组件,顾名思义,也就是通过使用ES6类的编写形式去编写组件,该类必须继承React.Component如果想要访问父组件传递过来......
  • 指针和数组基础知识
    /*数组元素的访问方式1、数组名[下标]2、指针量名[下标]3、*(p+i)p+1,指针+1,则指针指向的地址加4*/#include"stdafx.h"voidchangeNum(int*array);intmain(intargc,char......
  • acwing 数组元素的目标和
    原题链接题解代码双指针#include"iostream"usingnamespacestd;constintN=100010;inta[N],b[N];intmain(){intn,m,x;cin>>n>>m>>x;for(i......
  • 代码随想录-数组理论基础
    数组理论基础二分查找代码随想录(programmercarl.com)二分查找前提条件:有序数组且无重复元素,想好是用左闭右闭还是左闭右开!如果是前者,while(left<=right),left==r......
  • 第三章 字符串、向量和数组
    第三章字符串、向量和数组using声明使用某个命名空间:例如usingstd::cin表示使用命名空间std中的名字cin。头文件中不应该包含using声明。这样使用了该头文件的源码......
  • golang 数组
    1.概念golang中的数组是具有固定长度及相同数据类型的序列集合2.初始化数组var数组名[数组大小]数据类型packagemainimport"fmt"funcmain(){ //第一种 v......
  • 【算法】数组的前缀和 Prefix Sum
    算法中有前缀和这样一种很好的数据结构,它能极大地降低区间查询的时间复杂度前缀和-PrefixSum 它是这样的,假如有这样一个数组(序列), A=[a1,a2,a3,a4,a5,a6,......
  • 4. 寻找两个正序数组的中位数
    给定两个大小分别为m和n的正序(从小到大)数组 nums1和 nums2。请你找出并返回这两个正序数组的中位数。算法的时间复杂度应该为O(log(m+n))。 题解:采用了遍......
  • F - 树状数组 2【GDUT_22级寒假训练专题五】
    F-树状数组2原题链接思路在树状数组1中我们可以得知单点修改,区间查询(区间和)对原数组进行单点修改,对区间和进行树状数组维护利用差分和前缀和我们可以推导出区......
  • LeetCode-53. 最大子数组和(Java)
    一、前言:......