树状数组学习

news2024/11/28 2:49:09

树状数组简介

树状数组,用于维护和查询前缀和,与线段树功能类似。树状数组代码短,常数和空间小,时间复杂度小,所以这也是一个十分优秀的算法。

在这里插入图片描述

a [ i ] a[i] a[i]为原数组上的点, s [ i ] s[i] s[i]为树状数组中各点,则

s [ 1 ] = a [ 1 ] s[1]=a[1] s[1]=a[1]
s [ 2 ] = a [ 1 ] + a [ 2 ] s[2]=a[1]+a[2] s[2]=a[1]+a[2]
s [ 3 ] = a [ 3 ] s[3]=a[3] s[3]=a[3]
s [ 4 ] = a [ 1 ] + a [ 2 ] + a [ 3 ] + a [ 4 ] s[4]=a[1]+a[2]+a[3]+a[4] s[4]=a[1]+a[2]+a[3]+a[4]
s [ 5 ] = a [ 5 ] s[5]=a[5] s[5]=a[5]
s [ 6 ] = a [ 5 ] + a [ 6 ] s[6]=a[5]+a[6] s[6]=a[5]+a[6]

可以发现, s [ x ] = ∑ i = x − 2 k + 1 x a [ i ] s[x]=\sum\limits_{i=x-2^k+1}^x a[i] s[x]=i=x2k+1xa[i],其中 k k k表示 x x x的二进制中末尾连续的0的个数。


树状数组的操作

lowbit(i)

根据上文, s [ x ] = ∑ i = x − 2 k + 1 x a [ i ] s[x]=\sum\limits_{i=x-2^k+1}^x a[i] s[x]=i=x2k+1xa[i],其中 k k k表示 x x x的二进制中末尾连续的0的个数。那应该如何求 2 k 2^k 2k呢?

我们可以用 l o w b i t lowbit lowbit来求, l o w b i t ( n ) lowbit(n) lowbit(n)的值为 n n n的二进制中最后一个1的权值,也就是 2 k 2^k 2k。而 l o w b i t ( n ) lowbit(n) lowbit(n)可以由n&(-n)得出。

为什么呢?我们可以得出 n − 1 n-1 n1是将 n n n的二进制从末尾到最后一个1全部取反,然后将 n − 1 n-1 n1的各位取反得 ~n+1。n与 ~n+1 在 n n n末尾最后一个1之前都为0,在末尾最后一个1之前都不相等。所以n&(~n+1)即为n的二进制中最后一个1的权值。
因为在补码中,~ n=-n-1。所以n&(~n+1)=n&(-n)

code

int lowbit(int n){
	return n&(-n);
}

单点修改

a [ i ] a[i] a[i]增加 v v v。由于 s [ x ] = ∑ i = x − 2 k + 1 x a [ i ] s[x]=\sum\limits_{i=x-2^k+1}^x a[i] s[x]=i=x2k+1xa[i],所以 s [ i ] , s [ i + 2 k ] , … s[i],s[i+2^k],\dots s[i],s[i+2k],都要修改。

code

void add(int i,int v){
	while(i<=n){
		s[i]+=v;i+=lowbit(i);
	}
}

时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn)


区间查询

求前 i i i个数的前缀和,可以画图理解。

code

int sum(int i){
	int re=0;
	while(i){
		re+=s[i];i-=lowbit(i);
	}
	return re;
}

若要求区间 [ l , r ] [l,r] [l,r]的和,则答案为 s u m ( r ) − s u m ( l − 1 ) sum(r)-sum(l-1) sum(r)sum(l1)

时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn)


例题

洛谷 P3374 【模板】树状数组

单点修改+区间查询

code

#include<bits/stdc++.h>
using namespace std;
int n,m,tp,x,y,tr[500005];
int lb(int i){
	return i&(-i);
}
void add(int i,int v){
	while(i<=n){
		tr[i]+=v;i+=lb(i);
	}
}
int find(int i){
	int re=0;
	while(i){
		re+=tr[i];i-=lb(i);
	}
	return re;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		add(i,x);
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&tp,&x,&y);
		if(tp==1) add(x,y);
		else printf("%d\n",find(y)-find(x-1));
	}
	return 0;
}

洛谷 P3372

区间修改+区间查询

我们可以用差分的思想,设 d i = a i − a i − 1 d_i=a_i-a_{i-1} di=aiai1,则 a i = ∑ j = 1 i a j a_i=\sum\limits_{j=1}^i a_j ai=j=1iaj

对于区间修改,设将区间 [ l , r ] [l,r] [l,r]都增加 v v v,则 d l + = v , d r + 1 − = v d_l+=v,d_{r+1}-=v dl+=v,dr+1=v即可,这样就变成了单点修改。

对于区间查询, s u m i = ∑ j = 1 i a j = ∑ j = 1 i ∑ k = 1 j d k = ∑ j = 1 i d j ∗ ( i − j + 1 ) = ( i + 1 ) ∑ j = 1 i d j − ∑ j = 1 i ( j ∗ d j ) sum_i=\sum\limits_{j=1}^ia_j=\sum\limits_{j=1}^i\sum\limits_{k=1}^jd_k=\sum\limits_{j=1}^i d_j*(i-j+1)=(i+1)\sum\limits_{j=1}^i d_j-\sum\limits_{j=1}^i(j*d_j) sumi=j=1iaj=j=1ik=1jdk=j=1idj(ij+1)=(i+1)j=1idjj=1i(jdj)

也就是说,我们只要用两个树状数组维护 d i d_i di i ∗ d i i*d_i idi的前缀和,就能求出 a i a_i ai的和。

code

#include<bits/stdc++.h>
using namespace std;
int n,m,tp,x,y,a[100005];
long long k,tr[100005][2];
int lb(int i){
	return i&(-i);
}
void add(int i,long long v,int z){
	while(i<=n){
		tr[i][z]+=v;i+=lb(i);
	}
}
long long find(int i,int z){
	long long re=0;
	while(i){
		re+=tr[i][z];i-=lb(i);
	}
	return re;
}
long long sum(int i){
	return (i+1)*find(i,0)-find(i,1);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		x=a[i]-a[i-1];
		add(i,x,0);
		add(i,x*i,1);
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&tp,&x,&y);
		if(tp==1){
			scanf("%lld",&k);
			add(x,k,0);
			add(y+1,-k,0);
			add(x,k*x,1);
			add(y+1,-k*(y+1),1);
		}
		else printf("%lld\n",sum(y)-sum(x-1));
	}
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/26938.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WordPress管理仪表板:在15分钟内成为WordPress专家

WordPress管理仪表板是内容管理系统 (CMS)的核心和灵魂。在这里&#xff0c;您可以监督网站的各个方面&#xff0c;从配置基本设置到发布内容、安装插件和主题等等。如果您不熟悉 WordPress 管理仪表板&#xff0c;您将很难管理网站。 了解如何使用仪表板比您想象的要容易。所有…

PixiJs学前篇(三):Canvas基础【下篇】

前言 在上一篇文章 PixiJs学前篇&#xff08;二&#xff09;&#xff1a;Canvas基础【中篇】 中我们了解了Canvas的基本绘制形状&#xff0c;接下来我们看一下如何在 Canvas 中绘制文本。 绘制文本 文本的绘制也是 Canvas 中也是比较常见的&#xff0c;在 Canvas 的绘制中&a…

STC51单片机36——51单片机简单分两路控制步进电机

按键控制步进电机正反转一定设置的角度&#xff0c;比如一圈360度&#xff0c;按一次30度&#xff0c;一起12档。分两路控制&#xff0c;4个加减按键&#xff0c;一个按键控制复位&#xff0c;每路控制输出tb6600驱动器驱动两个42电机同步。同时数码管显示出来每次按键加减后的…

FastDFS(分布式文件管理系统)

一、简介 解决了大容量的文件存储和高并发访问的问题&#xff0c;文件存取时实现了负载均衡。 FastDFS服务端只有两个角色&#xff0c;tracker server和storage server。 所有同角色服务器集群节点都是平等的&#xff0c;不存在主从关系&#xff08;Master-Slave&#xff09;…

golang爬虫练习-抓取行业信息分类

抓取框架介绍 gathertool gathertool是golang脚本化开发库&#xff0c;目的是提高对应场景程序开发的效率&#xff1b;轻量级爬虫库&#xff0c;接口测试&压力测试库&#xff0c;DB操作库等。 地址&#xff1a; https://github.com/mangenotwork/gathertool 下载: go get …

醛肽:Gly-Phe-Gly-aldehyde、102579-48-6

可逆组织蛋白酶 B 抑制剂 GFG-醛缩氨基脲已用于通过亲和层析从日本血吸虫中纯化组织蛋白酶 B 样蛋白酶 Sj31&#xff0c;并用于从疟原虫物种中分离恶性疟原虫。编号: 200138 中文名称: 三肽Gly-Phe-Gly-aldehyde CAS号: 102579-48-6 单字母: H2N-GFG-CHO 三字母: H2N-Gly-Phe-G…

Docker网络管理

目录 一、Docker 网络实现原理 二、Docker 的网络模式 1.四种网络模式 2.各网络模式详解 &#xff08;1&#xff09;Host模式 &#xff08;2&#xff09;Container模式 &#xff08;3&#xff09;None模式 &#xff08;4&#xff09;Bridge模式 3.指定容器网络…

常用的实体类转换方式 - BeanUtil | MapStruct

0. 相关依赖&#xff1a;1. 实体类信息&#xff1a;2. BeanUtil方法转换&#xff1a;2.1. 实体类转实体类&#xff08;copyProperties&#xff09;&#xff1a;2.2. 实体类集合转实体类集合&#xff08;copyToList&#xff09;&#xff1a;2.3. 实体类集合转Map&#xff08;bea…

java泛型类型解释

文章目录1、Class<T>使用写法2、常见字母含义举例说明3、object.getClass()和Object.class的区别举例说明1、Class 使用写法 mongoTemplate.findAll(Customer.class); 2、常见字母含义 E - Element (在集合中使用&#xff0c;因为集合中存放的是元素) T - Type&#x…

css修改滚动条样式

有一说一 系统默认的滚动条确实不是很美观 那么我就来带着大家修改一下他的样式 ::-webkit-scrollbar 设置整个滚动条的样式 一般用于设置宽度 你要跟什么元素加 就 元素::-webkit-scrollbar 例如你想 给body 就 body::-webkit-scrollbar ::-webkit-scrollbar-track 设置滚…

一周活动速递|Paper Time第五期;技术征文大赛即将收官

今天周一&#xff0c;小编为大家准时带来 「OceanBase 一周活动速递」 &#xff0c;活动按时间排序&#xff0c;欢迎大家关注&#xff01; Paper Time&#xff1a;基于无服务计算的机器学习方法 01 基本安排 时间&#xff1a; 11 月 23 日&#xff08;周三&#xff09;19:00-2…

让我们进入面向对象的世界(二)

让我们进入面向对象的世界(二) 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录让我们进入面向对象的世界(二)前言二.对象的操作三.让我们离对象村更进一步&#xff0c;进入面向对象封装的特性四 实例变量和局部变量…

ヾ(⌐ ■_■)— HTML-Emmet语法速查表

Emmet是一款文本编辑器/IDE的插件&#xff0c;用来快速生成复杂的HTML代码&#xff0c;只要掌握一些常用的语法&#xff08;类似于CSS选择器&#xff09;&#xff0c;就可以减少重复编码的工作。 1.调用方法 Emmet使用Tab作为自动生成HTML代码的触发器。输入完生成HTML的缩写…

Qt-FFmpeg开发-视频播放(4)

Qt-FFmpeg开发-视频播放【软解码 OpenGL显示YUV420P图像】 文章目录Qt-FFmpeg开发-视频播放【软解码 OpenGL显示YUV420P图像】1、概述2、实现效果3、FFmpeg软解码流程4、主要代码4.1 解码代码4.2 OpenGL显示RGB图像代码5、完整源代码更多精彩内容&#x1f449;个人内容分类汇…

图片如何转换为文字?这些软件可以实现

最近有小伙伴私信说&#xff0c;因为临近期末&#xff0c;老师上课的进度开始加快。他为了兼顾知识点能够当堂吸收&#xff0c;所以没有记笔记&#xff0c;而是将知识点都拍照下来&#xff0c;集中注意力上课。然而当他课后打算整理笔记却发现&#xff0c;自己原来拍了几十张图…

比较研究测井预测:遗传算法与神经网络(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

day071:网络编程(IP、端口、协议)、InetAddress类、UDP协议、TCP协议

目录 一、网络编程 1.网络编程三要素 2.IP地址 &#xff08;1&#xff09;IP地址&#xff08;每台计算机指定的标识号&#xff09; &#xff08;2&#xff09;类InetAddress:方便对IP地址获取和操作&#xff1b;此类表示Internet&#xff08;IP&#xff09;地址 3.端口&am…

LVS+Keepalived高可用群集

目录 一、keepalived简介 二、keepalived工作原理 三、LVS-DR模式keepalived 高可用集群部署 1、部署2台web服务器 2、部署2台负载调度器 四、总结 一、keepalived简介 Keepalived是通过vrrp 协议的实现高可用性&#xff0c;对网络比较了解的IT人&#xff0c;对这个技术应…

[操作系统笔记]调度与死锁杂项知识点

部分定义截取自书本 管态和目态 这说的是处理机的执行状态 管态又称为特权态&#xff0c;系统态&#xff0c;核心态。CPU在管态下可以执行指令系统的全集。如果程序处于管态&#xff0c;则该程序可以访问计算机的任何资源&#xff0c;它的资源访问权限不受限制&#xff0c;通常…

iOS16 中的 3 种新字体宽度样式

前言 在 iOS 16 中&#xff0c;Apple 引入了三种新的宽度样式字体到 SF 字体库。 Compressed Condensed Expend UIFont.Width Apple 引入了新的结构体 UIFont.Width&#xff0c;这代表了一种新的宽度样式。 目前已有的四种样式。 standard&#xff1a;我们总是使用的默认…