什么是树状数组???
解决数据压缩里的累积频率(Cumulative Frequency)的计算问题,现多用于高效计算数列的前缀和, 区间和,这样的问题可以使用树状数组算法来解决。
我们现在通过修改数组,往数组中某一个位置增加或减小一个值,从而导致前缀和数组会发生变化,因此我们不可以使用普通前缀和这一思路来做。
考虑一下:我们求静态数组的前缀和时,如果我们使用暴力法,使用两个for循环来枚举子区间之和,从而得到静态数组的区间和,但是这一复杂度会达到O(N^2),因此使用普通的前缀和可以将复杂度达到O(N)。但是当我们在动态数组中修改元素时,每次修改元素会导致原来的前缀和发生变化,因此我们还需要维护前缀和,这样的时间复杂度也会达到O( N^2)。
但是如果我们使用树状数组这一算法,时间复杂度将会降为O(nlog2n),接下来我将详细解释一下树状数组
树状数组包含三个基本的功能:
首先定义tree数组表示一个树状数组 ,tree[i]表示第i个位置的区间的和,区间[l,r]的和即为tree[r]-tree[l-1]
//维护
void update(int i,int x)
{
/*
i:下标
x:增量
维护:在末尾的1上加1
*/
while (i <= n)
{
tree[i] += x;
i += lowbit(i);
}
}
//求和
int sum(int i)
{
/*
求和(查询):去除末尾的1
*/
int num = 0;
while (i)
{
num += tree[i];
i -= lowbit(i);
}
return num;
}
inline int lowbit(int x)
{
return ((x) & (-x));
}
接下来详细解释一个这三个函数基本功能:
引用《百度百科》的一张图来解释
对于查询的过程:每次去掉二进制的最后的1,例如我们查询sum(7):
所以说查询sum(7)就等于:sum(7) = sum(6)+sum(4),如上图的蓝色表示。
对于维护的过程:每次在二进制数最后的1上加1,例如我们更新update(1,2):
所以说当维护(修改一个位置的元素值)时,我们会自动动态的维护整个树状数组,修改tree[1]+=2 ,tree[2] tree[4] tree[8] … 都会跟着修改。,一直到整个数组的大小N为止。
对于lowbit运算的过程:
lowbit运算可以得到二进制最后一个1的位置,同时也可以根据lowbit确定tree数组的构成
首先我们需要理解tree数组的意思:tree数组本质是前缀和,即tree[i]=a[1]+a[2]+…+a[i]的区间的和。
接下来我们枚举1-7数字的二进制以及lowbit运算的结果,看看lowbit运算是如何影响tree数组的
首先我们可以了解到:
因此:tree数组的每一项的值:
即我们可以得到这样一张图:
请仔细理解这张图代表的意义!!!!!!!!!
#include <bits/stdc++.h>
using namespace std;
/*
树状数组:常用于对动态区间的查询操作,即求动态数组求前缀和的操作
三大基本功能:
1. 维护 update
2. 求和 sum
3. lowbit运算
*/
const int N = 10005;
int tree[N]{
0 };
int n; //当前tree数组的最大元素个数
inline int lowbit(int x)
{
return ((x) & (-x));
}
//维护
void update(int i,int x)
{
/*
i:下标
x:增量
维护:在末尾的1上加1
*/
while (i <= n)
{
tree[i] += x;
i += lowbit(i);
}
}
//求和
int sum(int i)
{
/*
求和(查询):去除末尾的1
*/
int num = 0;
while (i)
{
num += tree[i];
i -= lowbit(i);
}
return num;
}
int main()
{
n = 5;
for (int i = 1; i <= 5; i++)
{
update(i, 3);
}
// 3 6 9 12 15
cout << "S[2,4]: " << sum(4) - sum(1) << endl;
//更新数组元素
// 3 6 15 18 21
update(3, 6);
cout << "S[2,4]: " << sum(4) - sum(1) << endl;
return 0;
}
在树状数组中可以用前 i 项的和来表示第 i 个数.
差分原理:a数组是一个原始数组,b数组是差分数组
a数组: 1,2,3,4,5
b数组: 1,1,1,1,1
所以可以得到:b[i]=a[i] - a[i-1]
通过差分数组b可以得到a数组的元素值:
a[4]=b[1]+b[2]+b[3]+b[4](易得)
对a数组的 2到4区间的元素都加 3:
a数组:1,5,6,7,5
不妨把b数组的2位置与4+1位置的元素加3和减3,其他位置元素不变
b数组:1,4,1,1,-2
则a[4]= b[1]+b[2]+b[3]+b[4]= 7 仍然等于对a数组的值。
因此对a数组的[x,y]区间操作,其实就是对 b差分数组执行两个位置的操作即可:
那么当对 x ~ y 的区间进行修改的时候需要在树状数组中的第 x 个位置 + k, 第 y + 1 个位置 -k
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e5+10;
int n,m;
int nums[N],tree[N];
inline int lowbit(int i){
return ((i)&(-i));
}
void update(int i,int num){
while (i<=n){
tree[i]+=num;
i+=lowbit(i);
}
}
int query(int i){
int ans=0;
while (i){
ans+=tree[i];
i-=lowbit(i);
}
return ans;
}
signed main(){
cin>>n>>m;
for (int i=1;i<=n;i++){
cin>>nums[i];
update(i,nums[i]-nums[i-1]); //维护差分值
}
while (m--){
int a,b,c,d;
cin>>a;
if (a==1){
//[b,c]+d
cin>>b>>c>>d;
update(b,d); //b[i]+=d
update(c+1,-d); //d[i+1]-=d
}
else if (a==2){
//query b
cin>>b;
cout<<query(b)<<'\n';
}
}
return 0;
}
文章浏览阅读1.4w次,点赞19次,收藏214次。原文链接:https://blog.csdn.net/jiaoyangwm/article/details/80011656 文章目录1、卷积神经网络的概念2、 _cnn
文章浏览阅读3.6k次。“嘉兴制造”,全球最大手机ODM工厂探秘 在短短的几年时间,闻泰通讯公司从只有三十几个人的设计团队,“蝶变”成为小米、华为、联想等全球知名手机厂商合作伙伴,企业总产值超80亿元。如今,闻泰通讯不仅是南湖区信息产业的龙头企业,更是成为全球最大的手机ODM企业之一,为全球知名手机厂商提供产品定义、方案设计、生产制造、软件开发等服务。……以下是闻泰通讯宣传视频……▼▼闻泰通讯有别于其他设计公司与_odm厂
文章浏览阅读1.4w次,点赞2次,收藏17次。刚刚有看到一篇文章写的是COOLMOS管与常规MOS管的区别,这是一篇名为《初学者必备知识——功率场效应晶体管MOS管》里面有介绍很多MOS管知识,在这我就不说别的,我们来说说COOLMOS管,因为本公司-深圳市凯泰电子有限公司也有这样的MOS管,但是不叫COOLMOS管,我们的叫超结MOS管(Super Junction MOSFET Series)。下面我先介绍下COOLMOS管与常规MO_超结mos和coolmos区别
文章浏览阅读837次。一、下载 erlang-20.2.2-1.el7.centos.x86_64.rpm 并安装二、下载rabbit安装:rpm --import https://www.rabbitmq.com/rabbitmq-release-signing-key.asc; yum install rabbitmq-server-3.7.2-1.el7.noarch.rpm三、设置开机启动:chkcon_erlang-20.2.2-1.el7.centos.arch64.rpm
文章浏览阅读167次。转载:https://mochajs.cn_mocha api
文章浏览阅读948次。JVM结构.内存分配,垃圾回收,调优参数等._java jvm
文章浏览阅读1.4k次。【天极网IT新闻频道】【Yesky新闻频道消息】 今日凌晨,苹果不仅正式发布了新一代操作系统iOS 9,还发布了一款应用移植工具Move to iOS。据悉,这款应用可以帮助用户将应用由Android迁移到iOS,同时这也是苹果开发的首款Android应用。据了解,Move to iOS是一款免费应用,只支持Android 4.0及更高的Android版本。苹果推出免费安卓应用移植工具Move t..._安卓开发的应用转换为苹果
文章浏览阅读1.8w次,点赞4次,收藏24次。介绍如何校准Linux服务器时间_linux时间校准
文章浏览阅读145次。Maven高级1.基础知识回顾:1.1Maven的核心依赖管理和一键构建(基础知识)1.2Maven仓库类型和仓库关系1.3Maven常见命令:1.4.maven生命周期2.Maven工程导入jar包坐标,必须考虑解决jar包冲突解决jar包冲突的方式一:解决jar包冲突的方式二:解决jar包冲突的方式三【推荐使用】:SSM框架不冲突的依赖包:3.Maven的拆分和聚合思想1.背景:2.工程、模块、项目的关系4.父子工程3种启动方式1.基础知识回顾:1.1Maven的核心依赖管理和一键构建(基础知识)
文章浏览阅读1.2k次。代码控制shader的自发光的开关mat.EnableKeyword("_EMISSION");//开 mat.DisableKeyword("_EMISSION");//关_unity shader enablekeyword
文章浏览阅读385次。Underscore.js是一个JavaScript实用库,提供了一整套函数式编程的实用功能,但是没有扩展任何JavaScript内置对象。弥补了部分jQuery没有实现的功能,同时又是Backbone.js必不可少的部分Underscore提供了100多个函数,包括常用的: map, filter, invoke — 当然还有更多专业的辅助函数,如:函数绑定, JavaScript模板功能,创建快速索引, 强类型相等测试Underscore是DocumentCloud的一个开源组件。.._unders js
文章浏览阅读4.8k次,点赞2次,收藏13次。R包【安装包】#指令下载R安装包install.packages("packge-name")#通过以下步骤安装点击右下方页面窗口中的“packages”--“install”进行安装,输入所要安装的R包名,默认从官网上下载#对于版本不合适的使用bioconductor安装if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager")BiocManager::install_下载r语言中的数据集