树状数组(学习笔记)

news/2025/2/28 23:56:17/文章来源:https://www.cnblogs.com/XichenOC/p/18682399

例题一:P3374 【模板】树状数组 1

例题二:P3368 【模板】树状数组 2

作用:

  • 特征: 一个多用于区间修改,和单点查询。或区间查询单点修改的数据结构,其代码量较少,比较好写。
  • 区别: 它与线段树的功能差不多,但线段树的可拓展性更强。也就是说:树状数组能做的,线段树都能做;而线段树能做的,树状数组有些不能做。但树状数组都可以被线段树替代,那还学什么树状数组?理由很简单它的常数小,且码量小,考场上线段树要写半个小时,而树状数组只需要十几分钟。
  • 优缺点: 总结下来,线段树有一下缺点:

\(1.\)拓展性小
\(2.\)对区间维护的值有较高的要求

普通树状数组维护的信息及运算要满足 结合律 且 可差分,如加法(和)、乘法(积)、异或等。

  • 结合律:\((x \circ y) \circ z = x \circ (y \circ z)\),其中 \(\circ\) 是一个二元运算符。

  • 可差分:具有逆运算的运算,即已知 \(x \circ y\)\(x\) 可以求出 \(y\)

优点也很明显:

\(1.\)码量小
\(2.\)常数小
\(3.\)好调试

实现:

基本模型:


\(2.\)我们先给出一个基本概念 —— \(lowbit\)

\(lowbit\) 指该数二进制下从右往左第一个 \(1\) 的位置的值,如 \(6\) 二进制下 \((6)_{10}=(110)_2\),那它的的\(lowbit\) 值就是 \(10\) ,在比如\((664)_{10}=(1010011000)_2\),则 \(lowbit(664)=(1000)_2\)

那如何求 \(lowbit\),我们知道,在计算机中,一个负数的等于它正数的二进制全部取反在加 \(1\),及假设有一二进制正数 \((1010011000)_2\) 则全部取反后为 \((0101100111)_2\) 在加一就变为 \((0101101000)\) 这时就发现当前数的 \(lowbit\) 就是和它负数的与,及 \(lowbit(x)=x \& -x\)。原理也很简单,因为第一个 \(1\) 前的所有 \(0\) 都变为一,而加一就会全部进位,重新变回 \(0\)\(1\)会变成 \(0\) 所有进位到这就停止了,所以第一个 \(1\) 后的就会变成一样的,其他就不同

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

\(3.\)知道了 \(lowbit\) 的概念后在看树状数组的基本样子,我们发现,任意一个节点的父亲节点的编号都等于该节点的编号加 \(lowbit\) ,及 \(fa_x=x+lowbit(x)\) 而我们每个节点的值都对应储存了某一个区间的值(后面以区间和为例),那我们又该如何找到对应的区间了?

\(4.\)我们发现一个区间的下一个包含最多区间的节点编号为 该节点编号减去其 \(lowbit\)值,及 \(x-lowbit(x)\),原因很简单,因为树状数组上的每个节点的 \(lowbit\)值就是它所代表区间的长度。

操作:

知道了这最基本的几个性质后,就好进行操作了:

区间查询和单点修改:

\(1.\)单点修改: 我们只需要修改根节点的值并逐步向上递推,依次修改所有父亲节点,时间复杂度 \(O(logn)\)

void add(int x,int num){for(int i=x;i<=n;i+=lowbit(i)){t[i]+=num;}
}

\(2.\)建树: 对于每个点都进行加点即可,时间复杂度 \(O(nlogn)\)

\(3.\)区间查询: 我们要查询 \(l\)\(r\)的区间和,它实际上就相当于找到 \(1 \sim r\) 的区间和,在减去 \(1 \sim l-1\)的区间和,只需要循环加上每个区间的和即可:

int query(int l,int r){int res=0;for(int i=r;i>=1;i-=lowbit(i)){res+=t[i];}for(int i=l-1;i>=1;i-=lowbit(i)){res-=t[i];}return res;
}

区间修改和单点修改:

\(1.\)区间修改: 若暴力修改每一个点,那复杂度为 \(O(nlogn)\)比较劣,但我们考虑差分,差分可以将一个区间的修改改为对两个点的修改,这样只需要对 \(l\) 加上修改值,对 \(r+1\) 减去修改值即可:

add(l,k);
add(r+1,-k);void add(int x,int num){for(int i=x;i<=n;i+=lowbit(i)){t[i]+=num;}
}

\(1.\)单点查询: 由于维护的是差分,所以一个点的值等于差分数组的前缀和,只需要不断跳即可:

int query(int r){int res=0;for(int i=r;i>=1;i-=lowbit(i)){res+=t[i];}return res;
}

第一题完整代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int a[N];
int n,m;
int lowbit(int x){return x&(-x);
}
int t[2*N];
void add(int x,int num){for(int i=x;i<=n;i+=lowbit(i)){t[i]+=num;}
}
int query(int l,int r){int res=0;for(int i=r;i>=1;i-=lowbit(i)){res+=t[i];}for(int i=l-1;i>=1;i-=lowbit(i)){res-=t[i];}return res;
}
int main(){cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];add(i,a[i]);}for(int i=1;i<=m;i++){int op;cin>>op;if(op==1){int x,k;cin>>x>>k;add(x,k);}else if(op==2){int x,y;cin>>x>>y;cout<<query(x,y)<<endl;}}
}

第二题完整代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int lowbit(int x){return x&(-x);
}
int a[N],t[2*N];
int n,m;
void add(int x,int num){for(int i=x;i<=n;i+=lowbit(i)){t[i]+=num;}
}
int query(int r){int res=0;for(int i=r;i>=1;i-=lowbit(i)){res+=t[i];}return res;
}
int main(){cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];int num=a[i]-a[i-1];add(i,num);}for(int i=1;i<=m;i++){int op;cin>>op;if(op==1){int x,y,k;cin>>x>>y>>k;add(x,k);add(y+1,-k);}else if(op==2){int x;cin>>x;cout<<query(x)<<endl;}}
}

练习:

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Centos根目录扩容

CentOS磁盘在根目录下扩容(无卷组情况下)查看磁盘分区情况,sda3挂载在根目录下,新扩容增加的sda4挂在在/data下现在想把sda4同样挂载在根目录下解决方法:删除sda3,再重建sda3(注意:删除后不要退出,紧接着重建,注意重建后的起始位置) 删除sda3然后重建输入下面那个命…

U455764 The Rotation Game

U455764 The Rotation Game 题目理解 本题要求移动\(A-H\)中的一列或一行,使其整个一行和一列的数字移动,使最后的中间8个的数字相同。求最少需要移动的步数和它的操纵顺序思路 1.本题可以很显然的想到用 \(BFS\) 来枚举执行不同字母操作后结果,但每 \(BFS\) 一次就会增加八…

BUU SQL COURSE 2

BUU SQL COURSE 2 BUU SQL COURSE 2 和前面那题差不多,但是注一下找到的登录成功但是显示 fault。 注一下别的看一下,在另一个数据库里找到了 flag。本文来自博客园,作者:Maplisky,转载请注明原文链接:https://www.cnblogs.com/lbh2021/p/18682313

PotPlayer 配置安装

目录一、下载1、官网链接2、微软商店 Microsoft Store二、安装1、双击安装包2、选择字体3、安装向导下一步4、接收许可协议5、选择组件及关联6、选择安装位置7、硬解选项三、设置1、关闭自动更新2、左键单双击设置3、视频下自动隐藏3.1、效果对比4、播放信息显示设置4.1、效果5…

2024年春秋杯网络安全联赛冬季赛部分wp

部分附件下载地址: https://pan.baidu.com/s/1Q6FjD5K-XLI-EuRLhxLq1Q 提取码: jay1 Misc day1-简单算术 根据提示应该是异或下载文件是一个字符串,写个代码字符串异或解密,由于需要密钥,所以先对单字节密钥进行爆破解密 爆破出flag代码如下: cipher_text = "ys~xdg/…

大夏龙雀DX-WF25(ESP32C2)蓝牙WIFI模块试用体验

模块尺寸跟引脚兼容常见的ESP8266 12-F模块,使用非常简单,vcc接3.3v,gnd接地,rx连接ch340的tx,tx连接ch340的rx即可。 如果需要通过urat下载程序,只需要把io9的引脚接地就行(下载完程序记得断开io9跟gnd的连接,否则程序无法运行)。芯片用的是ESP32C2(ESP8684),很遗…

1.20 前端连接数据库

今天完成了项目的网页前端与后端数据库的连接,已经能够将前端填写的内容添加到mysql数据库 例如页面如下:数据库内容:明天开始编写下一个功能

【vjudge训练记录】大一寒假专项训练——枚举算法

训练情况A题 给定 \((x,y)\),倒着枚举地毯的范围是否覆盖 \((x,y)\),如果覆盖直接输出,如果全部枚举完都没有则输出 -1点击查看代码 #include <bits/stdc++.h> // #define int long long #define endl \nusing namespace std;void solve(){int n; cin>>n;int x[…

Khepri C2 framework beacons记录(之前的)

1、背景 在查看进程时发现可疑隐藏进程,名称为.test(.test.93627),隐藏文件,很可疑,于是查了下进程日志发现如下:/private/tmp/.test /private/var/db/oah/4b8f81eadefb42da07e9e88fa7905df57faec82d8621008e0ae4a04d81e2169f/bb9595accf35a51de80f42e656bdb2217238af58…

(重要***)查询自己需要的SQL语句

凡是指标相关的,先清空相关干扰条件,然后点击确认,比如加载性能里的列表页面,要查慢加载次数这个指标这个时候去这个数据库 写SQL语句select* fromquery_log ql whereql.user_name = sheng.yu-n@msxf.com order byexec_time desc limit 50然后找到自己对应操作的SQL 通过结…

最强截图录屏工具ShareX v17.0.0 中文绿色版

软件介绍 ShareX 是一款功能强大的屏幕截图和屏幕录制工具,可用于创建高质量的屏幕截图、动画 GIF 和屏幕录像,并提供多种上传选项,使用户能够轻松地将它们共享到互联网上。除此之外,它还支持多种自定义功能,例如图像编辑、颜色拾取、OCR 文字识别等。软件功能快速截图:简…

动态可视化:一步步拆解LSTM和GRU

转自:https://zhuanlan.zhihu.com/p/47907312 编者按:关于LSTM,之前我们已经出过不少文章,其中最经典的一篇是chrisolah的《一文详解LSTM网络》,文中使用的可视化图片被大量博文引用,现在已经随处可见。但正如短视频取代纯文字阅读是时代的趋势,在科普文章中,用可视化取…