当前位置: 首页 > news >正文

树状数组基础知识以及相关习题

文章目录

  • 什么是树状数组?
  • 如何理解树状数组
  • 如何理解精髓lowbit
  • 二叉树和树状数组的结构
  • 树状数组的优点
  • 树状数组模板
    • 单点修改,区间查询
    • 区间修改,单点查询
    • 区间修改,区间查询
      • 树状数组法
      • 线段树法
  • 树状数组基础练习题
    • 逆序对
    • 动态求连续区间和
    • 数星星
    • 校门外的树
    • 简单题
    • 打鼹鼠

什么是树状数组?

 和并查集一样,树状数组和线段树都是算法竞赛中常见的数据结构,他们通常结构清晰,操作方便,应用灵活,效率很高。

如何理解树状数组

  • 一句话概括:树状数组可以高效率的查询和维护前缀和(或区间和)

 所谓前缀和,即给出长度为n的数列A={ a 1 , a 2 , a 3 , . . . . , a x a_1,a_2,a_3,....,a_x a1,a2,a3,....,ax}和一个查询 x < = n x<=n x<=n,求 s u m ( x ) = a 1 + a 2 + … + a x sum(x)=a_1+a_2+…+a_x sum(x)=a1+a2++ax。数列 [ i , j ] [i,j] [ij]区间和通过前缀和求得,即ai+…+aj=sum(j)-sum(i-1)。
 如果数列A是静态不变的,代码很好写,预处理前缀和就好了,一次预处理的复杂度为0(n),然后每次查询复杂度都为O(1)。但是,如果序列是动态变化的,如改变其中一个元素a的值,那么它后面的前缀和都会改变,需要重新计算,如果每次查询前元素都有变化,那么一次查询的复杂度就变为O(n)。

如何理解精髓lowbit

lowbit(x)=x&-x,功能是找x的二进制最后一个1,原理是用到了负数的补码。下面这两张张表可能能更好的让你理解为什么树状数组这样构造,以及他的基础函数的由来

在这里插入图片描述
在这里插入图片描述

二叉树和树状数组的结构

在这里插入图片描述
上述图片给我们展示了二叉树到树状数组的结构变换,有助于我们更好的理解树状数组。

树状数组的优点

优点:修改和查询操作复杂度于线段树一样都是logN,但是常数比线段树小,并且实现比线段树简单

缺点:扩展性弱,线段树能解决的问题,树状数组不一定能解决.

树状数组模板

万变不离其宗,这两个函数是树状数组的精髓,要好好掌握。

void update (int x,int k) {while (x<=N) {tree[x]+=k;x+=lowbit(x);}
}
int query (int x) {int ans=0;while (x>0) {ans+=tree[x];x-=lowbit(x);}return ans;
}

关于如何理解树状数组可以结合有关资料学习,这里只给出模板,并给出一些练习题帮助更好的理解树状数组

单点修改,区间查询

const int N = 1e6+5;
int a[N],b[N];
int tree[N];
int n,m;void solve ()
{cin>>n>>m;for (int i=1;i<=n;i++) {int x;cin>>x;update(i,x);}for (int i=1;i<=m;i++) {int pos,x,y;cin>>pos>>x>>y;if(pos==1) {update(x,y);}else {cout<<query (y)-query (x-1)<<'\n';}}return ;
}

区间修改,单点查询

区间修改,单点查询的模板用到了差分数组,不懂差分的可以去查询有关资料

const int N = 1e6+5;
int a[N],b[N];
int chafen[N];
int tree[N];
int n,m;void solve ()
{cin>>n>>m;for (int i=1;i<=n;i++) {cin>>chafen[i];int x=chafen[i]-chafen[i-1];update(i,x);}for (int i=1;i<=m;i++) {int pos,x,y,k;cin>>pos;if(pos==1) {cin>>x>>y>>k;update(x,k);update(y+1,-k);}		else {cin>>x;cout<<sum(x)<<'\n';}}return ;
}

区间修改,区间查询

这部分代码有些难以实现,运用到了数学的相互转换。区间修改,区间查询是线段树的强项。我把两种方法都贴出来以供参考

树状数组法

#include <bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;
const int N = 1e6+5;
int a[N],b[N];
int tree1[N],tree2[N];
int m,n;void update1 (int x,int k) {while (x<=n) {tree1[x]+=k;x+=lowbit(x);}
}void update2 (int x,int k) {while (x<=n) {tree2[x]+=k;x+=lowbit(x);}
}int sum1 (int x) {int res=0;while (x>0) {res+=tree1[x];x-=lowbit(x);}return res;
}int sum2 (int x) {int res=0;while (x>0) {res+=tree2[x];x-=lowbit(x);}return res;
}void solve () {cin>>m>>n;for (int i=1;i<=m;i++) {cin>>a[i];int x=a[i]-a[i-1];update1 (i,x);update2 (i,(i-1)*x);}for (int i=1;i<=n;i++) {int pos;cin>>pos;if (pos==1) {int x,y,k;cin>>x>>y>>k;update1(x,k);update1(y+1,-k);update2(x,k*(x-1));update2(y+1,-k*y);}else {int x,y;cin>>x>>y;int ans1=y*sum1(y)-sum2(y);int ans2=(x-1)*sum1(x-1)-sum2(x-1);cout<<ans1-ans2<<'\n';}}
}

线段树法

#include <bits/stdc++.h>
#define int long long 
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int N = 1e5+5;
int a[N];
int tree [N<<2],tag[N<<2];int ls (int p) {return p<<1;}
int rs (int p) {return p<<1|1; }void push_up (int p) {tree[p]=tree[ls(p)]+tree[rs(p)];
//	tree[p]=min (tree[ls(p)],tree[rs(p)]);//Çó×îСֵµÄʱºòpush_upº¯ÊýÀïÃæÊÇÕâ¸ö 
}void build (int p,int pl,int pr) {tag[p]=0;if (pl==pr) {tree[p]=a[pl];return ;}int mid = (pl+pr)>>1;build (ls(p),pl,mid);build (rs(p),mid+1,pr);push_up(p);
}void addage (int p,int pl,int pr,int d) {tag[p] += d;tree[p] += d*(pr-pl+1);
}void push_down (int p,int pl,int pr) {if (tag [p]) {int mid = (pl+pr)>>1;addage  (ls(p),pl,mid,tag[p]);addage (rs(p),mid+1,pr,tag[p]);tag[p]=0;}
}void update (int l,int r,int p,int pl,int pr,int d) {if (l <= pl && pr <= r) {addage (p,pl,pr,d);return ;}push_down(p,pl,pr);int mid=(pl+pr)>>1;if (l <= mid) update (l,r,ls(p),pl,mid,d);if (r > mid) update (l,r,rs(p),mid+1,pr,d);push_up (p);
}int query (int l,int r,int p,int pl,int pr) {if (pl>=l&&pr<=r) return tree[p];push_down (p,pl,pr);int res=0;int mid = (pl+pr)>>1;if (l<=mid) res += query (l,r,ls(p),pl,mid);if (r>mid) res +=query (l,r,rs(p),mid+1,pr);return res; 
}void solve () {int n,m;cin>>n>>m;for(int i=1;i<=n;i++)  cin>>a[i];build (1,1,n);while (m--) {int q,l,r,d;cin>>q;if (q==1) {cin>>l>>r>>d; update (l,r,1,1,n,d);}else {cin>>l>>r;cout<<query (l,r,1,1,n)<<'\n';}}}

虽然说线段树才是这类题的正解,但是线段树代码量很大,难以实现。树状数组相较于它的优点就是代码量少。但是有些问题(当然我还没遇到)只能用线段树来解决,树状数组就显得力不从心了。

树状数组基础练习题

逆序对

来源:洛谷
这是一道利用离散化结合树状数组的例题

 一道逆序对的例题,这个例题可以用归并排序的方法写,也可以用树状数组的方法写,如果要用到树状数组来写的话,就要用到离散化,因为数据比较大。这里我们用到的方法是树状数组。
其中的核心思想就是把数字看成树状数组的下标

#include <bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;
const int N = 1e6+5;
int a[N];
int chafen[N];
int tree[N];
int n,m;struct jiegou {int x,y;
}b[N];bool cmp (jiegou qwe,jiegou asd) {if (qwe.x!=asd.x)	return qwe.x<asd.x;return qwe.y<asd.y;
}//两个基础函数void solve () {cin>>n;for (int i=1;i<=n;i++) {cin>>b[i].x;b[i].y=i;}sort (b+1,b+1+n,cmp);for (int i=1;i<=n;i++) a[i]=b[i].y;int res=0;for (int i=n;i>=1;i--) {update(a[i],1);res+=sum(a[i]-1);}cout<<res;hreturn ;
}

动态求连续区间和

来源:ACwing
模板题,直接套用模板就可以

const int N = 2e5+5;
int a[N],tree[N];int n,k;
//两个基础函数,这里省略没写
void solve () {cin>>n>>k;for (int i=1;i<=n;i++) {cin>>a[i];update (i,a[i]);}for (int i=1;i<=k;i++) {int q,x,y;cin>>q>>x>>y;if (q==1) {update (x,y);}else {cout<<query (y)-query (x-1)<<'\n';}}return;
}

数星星

来源:ACwing
画出图像就能发现,我们只用求前面有多少小于x的数即可。前面有多少个数字,那么这个输入就是几级星星。多次求前缀和,优先想到我们的树状数组。我们用一个ans数组来存放i级星星有多少个。后续直接输出就可以

//两个基础函数没有写出
void solve () {int n;cin>>n;for (int i=1;i<=n;i++) {int x,y;cin>>x>>y;x++;//这里注意下标加1,因为树状数组下标不为0ans[query (x)]++;//求x前面有多少个数字,再用ans数组存起来update (x,1);}for (int i=0;i<n;i++) cout<<ans[i]<<'\n';return;
}

校门外的树

来源:ACwing
每一个 [ l , r ] [l,r] [l,r]里面的树都是一种,给出很多组l,r。问当查询[l,r]时,有多少种树。
其实这一题用到了一个括号序列的思想,我们把 [ l , r ] [l,r] [l,r]中l上放置一个左括号,r上放置一个右括号。在这一个括号里面树都是一种。这样我们只用维护括号的数量,最后查询括号的数量即可。
怎么查询 [ l , r ] [l,r] [l,r]里面有多少种树?我们画图就能发现。我们把r之前的左括号减去i之前的右括号即可。
故用两个树状数组分别维护左右括号的前缀和,更新时记录左右括号数,查询时相减即能得到结果

void solve () {int n,k;cin>>n>>k;for (int i=1;i<=k;i++) {int q,x,y;cin>>q>>x>>y;if (q==1) {update1 (x,1);update2 (y,1);}else {cout<<query1 (y) - query2 (x-1) << '\n';}}
}

巧妙的将求树的种类转化成求括号的数量

简单题

来源:ACwing
和上一题差不多,但这一题是反转0,1序列。我们依然用括号的思想, [ l , r ] [l,r] [l,r]里反转,我们就在两边加括号,单点查询的时候,我们就查询这个点被多少个括号扩了起来,就反转了几下,然后只能是0,1的缘故,我们直接判断奇偶就行了。
多点修改,单点查询,十分符合树状数组,直接开写。
实际上就是找这一点(包括这一点)之前左括号与右括号的差值

void solve () {int n,k;cin>>n>>k;for (int i=1;i<=k;i++) {int q,x,y;cin>>q;if (q==1) {cin>>x>>y;update1 (x,1);update2 (y,1);}else {cin>>x;int q = query1 (x) - query1 (x-1);
//			int w = query2 (x) - query2 (x-1); int pos = query1 (x-1) - query2 (x-1);pos += q;if (pos%2==0) cout<<"0"<<'\n';else cout<<"1"<<'\n';}}
}

打鼹鼠

来源:ACwing
这是一道二维树状数组的练习题,也是属于的一道板子题,可以看一看,就是将一维改成二维。

const int N=1040;
int c[N][N], n;void update (int x, int y, int k) {for(int i=x; i<=N; i+=lowbit(i)){for(int j=y; j<=N; j+=lowbit(j)){c[i][j] += k;}}
}int query (int x, int y){int ans = 0;for(int i=x; i>=1; i-=lowbit(i))for(int j=y; j>=1; j-=lowbit(j))ans += c[i][j];return ans;
}void solve () {cin>>n;int xx, yy, x, y, k, op;while(cin>>op, op!=3) {if(op==1){cin>>x>>y>>k;update(x+1, y+1, k);}else{cin>>x>>y>>xx>>yy;xx++, yy++;cout<<query (xx,yy)-query (xx,y)-query (x,yy)+query (x,y)<<'\n';}}
}

相关文章:

树状数组基础知识以及相关习题

文章目录 什么是树状数组&#xff1f;如何理解树状数组如何理解精髓lowbit二叉树和树状数组的结构树状数组的优点树状数组模板单点修改&#xff0c;区间查询区间修改&#xff0c;单点查询区间修改&#xff0c;区间查询树状数组法线段树法 树状数组基础练习题逆序对动态求连续区…...

2023大数据-架构师案例(八)

Lambda架构 nginx &#xff08;b&#xff09; Hbase &#xff08;c&#xff09;Spark Streaming &#xff08;d&#xff09;Spark &#xff08;e&#xff09;MapReduce &#xff08;f&#xff09;ETL &#xff08;g&#xff09;MemSQL &#xff08;h&#xff09;HDFS &#x…...

【Python】Python:探索未来科技的风向标

Python&#xff1a;探索未来科技的风向标 一、背景 近年来&#xff0c;随着人工智能、大数据、云计算等技术的飞速发展&#xff0c;Python 作为一门功能强大、简单易学的编程语言&#xff0c;逐渐成为了开发者的首选。在我国&#xff0c;Python 的热度持续攀升&#xff0c;不…...

Java语言程序设计——篇十一(6)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…...

2024年有哪些好用的文件加密软件?十款常用加密软件推荐

在2024年&#xff0c;随着数据泄露和网络威胁的日益复杂&#xff0c;文件加密软件成为了保护敏感信息不可或缺的工具。无论是个人用户还是企业&#xff0c;选择合适的加密软件都是确保数据安全的重要一环。 1. 安秉加密软件 安秉加密软件专为企业设计&#xff0c;提供全面的信…...

书生大模型学习笔记3 - 书生开源大模型链路体系

学习视频链接&#xff1a;书生浦语大模型全链路开源体系_哔哩哔哩_bilibili...

【竞技宝】奥运会:法国国奥淘汰埃及国奥晋级决赛

法国国奥在巴黎奥运会男足半决赛跟埃及国奥相遇&#xff0c;赛前大部分球迷和媒体&#xff0c;都一边倒看好法国国奥能轻松获胜。首先&#xff0c;法国国奥整体实力高出一个档次。最后&#xff0c;法国国奥坐拥主场作战的优势。所以&#xff0c;法国国奥正常发挥的话&#xff0…...

C++的STL简介(四)

目录 1.List 2.list 模拟实现 2.1基本框架 2.2 list_node 2.3 list 2.3.1 默认构造 2.3.2 析构函数 2.3.3 begin&#xff08;&#xff09; 2.3.4 end&#xff08;&#xff09; 2.3.5 size&#xff08;&#xff09; 2.3.6 empty&#xff08;&#xff09; 2.3.7 inser…...

NIO专题学习(一)

一、BIO/NIO/AIO介绍 1. 背景说明 在Java的软件设计开发中&#xff0c;通信架构是不可避免的。我们在进行不同系统或者不同进程之间的数据交互&#xff0c;或者在高并发的通信场景下都需要用到网络通信相关的技术。 对于一些经验丰富的程序员来说&#xff0c;Java早期的网络…...

Linux学习笔记:Linux基础知识汇总(个人复习版)

常用命令&#xff1a; 1、ls -a&#xff1a;显示所有文件&#xff08;包括隐藏文件&#xff09;&#xff0c;简洁版 -l&#xff1a;显示所有文件&#xff0c;详细版 -R&#xff1a;显示所有文件以及子目录下文件&#xff0c;简洁版 可以搭配使用。 2、netstat -i&#x…...

MSR020/MSR040低温漂、低功耗电压基准

MSR020/MSR040 是低温漂、低功耗、高精度 CMOS 电压基准&#xff0c; 具有 0.05% 初始精度和低功耗的特点。 该器件的低输出电压迟滞和低长期输出电压漂移的 特性&#xff0c;可以进一步提高稳定性和系统可靠性。 此外&#xff0c;器 件的小尺寸和低工作电流的特性使其非…...

一个是生产打包的时候, 一个是本地测试启动的时候,maven如何配置?

在Maven项目中&#xff0c;使用两套不同的pom.xml配置分别用于生产打包和本地测试启动是常见需求&#xff0c;尤其当你需要调整依赖范围、插件配置或使用不同资源文件时。Maven通过profiles和activeProfiles提供了灵活的配置管理方案&#xff0c;允许你为不同的环境或构建场景定…...

公文字体包下载

https://zuzhibu.xaufe.edu.cn/info/1063/3421.htm 下载解压后&#xff0c;将相应字体文件粘贴至C:\Windows\Fonts 等待安装完成就可以了...

主从备份及安装准备

主从复制 学习内容 1. 备份的三种类型 1. 热备份 2. 逻辑备份 3. 物理备份 2. 情景 ⼊职企业&#xff0c;发现企业架构为⼀主多从&#xff0c;但是两台从服务器和主库不同 步&#xff0c;但是每天会全库北⽅主服务器上的数据到从服务器&#xff0c;由于数据量 不是很⼤&a…...

翻译英文的软件,分享3款翻译神器!

在这个全球化的时代&#xff0c;跨越语言障碍成为了我们连接世界的桥梁。无论你是旅行爱好者、国际商务人士&#xff0c;还是学习新语言的求知者&#xff0c;一款高效、准确的翻译软件都是不可或缺的伙伴。今天&#xff0c;就让我们一起探索那些让沟通无界限的翻译神器&#xf…...

软件测试解读——性能效率测试

一、性能效率测试概述 性能效率(efficiency)为GB/T 25000.51-2016标准中提及的软件产品的八大产品质量特征之一。性能效率测试用于评估待测系统与软件在给定的时间和其他资源限制下完成其指定功能的程度&#xff0c;也称作性能测试。 为完成系统与软件性能测试&#xff0c;…...

【PLC】子程序功能心得

博主用GX Works编程的时候用到子程序&#xff0c;这里给大家和自己强调一下&#xff0c;每个子程序一定要以SRET结束&#xff0c;尤其是有多个子程序的时候 博主吃了个大亏&#xff0c;由于有两个子程序&#xff0c;结果第一个子程序没有写SRET&#xff0c;结果两个子程序默认以…...

Iris for mac 好用的录屏软件

Iris 是一款高性能屏幕录像机&#xff0c;可录制到 h.264。Iris 在可用时利用板载 GPU 加速。它可以选择包括来自摄像头和最多两个麦克风的视频。 兼容性 所有功能在macOS 11.0-14上完全支持&#xff0c;包括macOS Sonoma。 简单编码 直接录制为h.264、h.265、ProRes或Motion…...

Transformers实战05-模型量化

文章目录 简介主要类型量化的优点量化的缺点量化过程量化过程反量化过程 精度和参数 量化实例bitsandbytes安装bitsandbytes4bit量化(加载)8bit量化(加载)验证效果 简介 模型量化&#xff08;Model Quantization&#xff09;是一种优化技术&#xff0c;旨在减少机器学习模型的…...

【Python】bytes 和 bytearray 到底是什么类型呢?

bytes和bytearray同属于二进制序列类型&#xff0c;是常见的数值类型的一种。 bytes多用在在文件的读写、网络通信、数据编码/解码等场景用的比较多。 而bytearray在二进制数据处理、图像处理、内存映射文件和网络通信等场景用的比较多。 其中这两部分的主要差别&#xff1a; …...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...