数据结构:树状数组

老规矩,推荐一篇原理讲解清晰的博客!(树状数组(详细分析+应用),看不懂打死我!_树形数组_鲜果维他命的博客-CSDN博客

相对于线段树,树状数组的优点就是代码简洁,容易修改。单缺点就是优点问题只有线段树才能解决,树状数组有一定的局限性。

1,模板

(1)单点修改,区间查询

int lowbit(int x) {return x & (-x);
}
int add_dandian(int pos, int k)
{for (int i = pos; i <= n; i += lowbit(i)) c[i] += k;
}
int search(int L, int R)
{//利用前缀和相减的性质,[L, R] = [1, R] −[1, L − 1]int ans = 0;for (int i = L - 1; i; i -= lowbit(i)) ans -= c[i];for (int i = R; i; i -= lowbit(i)) ans += c[i];return 0;
}

(2)区间修改,单点查询

我们需要构造出原数组的差分数组b,然后用树状数组维护b数组即可

对于区间修改的话,我们只需要对差分数组进行操作即可,例如对区间[L,R]+k,那么我们只需要更

新差分数组add(L,k),add(R+1,-k),这是差分数组的性质.

int lowbit(int x) {return x & (-x);
}
void update(int pos, int k)//pos表示修改点的位置,K表示修改的值也即+K操作
{for (int i = pos; i <= n; i += lowbit(i)) c[i] += k;
}void range_add(int L, int R, int k){update(L, k);update(R + 1, -k);
}int ask(int pos)//返回区间pos到1的总和
{int ans = 0;for (int i = pos; i; i -= lowbit(i)) ans += c[i];return ans;
}

(3)区间修改,区间查询

void add(ll p, ll x){for(int i = p; i <= n; i += i & -i)sum1[i] += x, sum2[i] += x * p;
}
void range_add(ll l, ll r, ll x){add(l, x), add(r + 1, -x);
}
ll ask(ll p){ll res = 0;for(int i = p; i; i -= i & -i)res += (p + 1) * sum1[i] - sum2[i];return res;
}
ll range_ask(ll l, ll r){return ask(r) - ask(l - 1);
}

2,题目练习

(1)【模板】树状数组 1 - 洛谷

 AC代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+5;
int n,m,a[N];int lowbit(int x)
{return x&(-x);
}
void add(int pos,int k);
int search(int l,int r);signed main()
{cin>>n>>m;for(int i=1;i<=n;i++){//cin>>a[i];int x;cin>>x;add(i,x);}for(int i=0;i<m;i++){int flag,l,r;cin>>flag>>l>>r;if(flag==1) add(l,r);else cout<<search(l,r)<<endl;}return 0;
}void add(int pos,int k)
{for(int i=pos;i<=n;i+=lowbit(i)){a[i]+=k;}
}int search(int l,int r)
{int sum=0;for(int i=r;i;i-=lowbit(i)){sum+=a[i];}for(int i=l-1;i;i-=lowbit(i)){sum-=a[i];}return sum;
} 

(2)【模板】树状数组 2 - 洛谷

   AC代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+5;
int n,m,a[N],b[N];int lowbit(int x)
{return x&(-x);
}
void add(int pos,int k);
int find(int pos);signed main()
{cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];add(i,a[i]-a[i-1]);//差分 }for(int i=0;i<m;i++){int flag,l,r,k;cin>>flag;if(flag==1){cin>>l>>r>>k;add(l,k);add(r+1,-k);}else{cin>>l;cout<<find(l)<<endl;}}return 0;
}void add(int pos,int k)
{for(int i=pos;i<=n;i+=lowbit(i)) b[i]+=k;return;
}int find(int pos)
{int sum=0;for(int i=pos;i;i-=lowbit(i)) sum+=b[i];return sum;
}

(3)逆序队  逆序对 - 洛谷

AC代码

#include <bits/stdc++.h>
using namespace std;
int n, a[5000001], b[5000001];
long long ans;
inline void msort(int l, int r)//归并排序
{int mid = (l + r) / 2;//取中间 if(l == r)//若l == r了,就代表这个子序列就只剩1个元素了,需要返回 {return;}else{msort(l, mid);//分成l和中间一段,中间 + 1和r一段(二分) msort(mid + 1, r);}int i = l;//i从l开始,到mid,因为现在排序的是l ~ r的区间且要二分合并 int j = mid + 1;//j从mid + 1开始,到r原因同上int t = l;//数组b的下标,数组b存的是l ~ r区间排完序的值 while(i <= mid && j <= r)//同上i,j的解释 {if(a[i] > a[j])//如果前面的元素比后面大(l ~ mid中的元素 > mid + 1 ~ r中的元素)(逆序对出现!!!) { ans += mid - i + 1;//由于l ~ mid和mid + 1 ~ r都是有序序列所以一旦l ~ mid中的元素 > mid + 1 ~ r中的元素而又因为第i个元素 < i + 1 ~ mid那么i + 1 ~ mid的元素都 > 第j个元素。所以+的元素个数就是i ~ mid的元素个数,及mid - i + 1(归并排序里没有这句话,求逆序对里有) b[t++] = a[j++];//第j个元素比i ~ mid的元素都小,那么第j个元素是目前最小的了,就放进b数组里 //++j;//下一个元素(mid + 1 ~ r的元素小,所以加第j个元素) }else{b[t++] = a[i++];//i小,存a[i] //++i;//同理 }}while(i <= mid)//把剩的元素(因为较大所以在上面没选) {b[t++] = a[i++];//存进去 //++i; }while(j <= r)//同理 {b[t++] = a[j++];//++j;}for(int i = l; i <= r; ++i)//把有序序列b赋值到a里 {a[i] = b[i];}return;
}
int main()
{scanf("%d", &n);for(int i = 1; i <= n; ++i){scanf("%d", &a[i]);}msort(1, n);//一开始序列是1 ~ n printf("%lld", ans);return 0;
}

(4)康托展开  【模板】康托展开 - 洛谷

AC代码

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
const int mod = 998244353;
int a[N], w[N]={1,1},tr[N], n,ans;int lowbit(int x) {return x & (-x);
}
void update(int pos, int k) {for (int i = pos; i <= n; i += lowbit(i)) tr[i] += k;return;
}
int query(int pos)
{int sum = 0;for (int i = pos; i; i -= lowbit(i)) sum+=tr[i];return sum;
}signed main()
{cin >> n;for (int i = 1; i <= n; i++) {//求阶乘w[i] = (i * w[i - 1]) % mod;update(i, 1);}for (int i = 1; i <= n; i++) {cin >> a[i];ans = (ans + ((query(a[i]) - 1) * w[n-i]) % mod) % mod;update(a[i], -1);//减1后就变成0了}cout << ans+1 << endl;return 0;
}

(5)二维树状数组  上帝造题的七分钟 - 洛谷

思想:和二维前缀和的思路很相似

AC代码

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
const int N = 3000;
int board[N][N];
int n, m;// 定义树状数组结构(树状数组三件套)
struct BIT
{int tr[N][N];  // 树状数组int lowbit(int x) {return x & (-x);  // 返回 x 的最低位的 1 所在位置}// 在坐标 (x, y) 处添加值 kvoid add(int x, int y, int k){for (int i = x; i <= n; i += lowbit(i)) {for (int j = y; j <= m; j += lowbit(j)) {tr[i][j] += k;  // 在 (i, j) 处加上值 k}}}// 查询坐标 (x, y) 处的前缀和int query(int x, int y){int sum = 0;for (int i = x; i; i -= lowbit(i)) {for (int j = y; j; j -= lowbit(j)) {sum += tr[i][j];  // 查询 (1, 1) 到 (x, y) 的前缀和}}return sum;}
} A, Ai, Aj, Aij;  // 定义四个不同的树状数组void Add(int x, int y, int k);
int Ans(int x, int y);int main()
{char ch;cin >> ch >> n >> m;  // 读取矩阵大小while (cin >> ch) {int x1, x2, y1, y2;cin >> x1 >> y1 >> x2 >> y2;if (ch == 'L') {int num;cin >> num;Add(x1, y1, num);  // 在指定区域添加值 numAdd(x1, y2 + 1, -num);Add(x2 + 1, y1, -num);Add(x2 + 1, y2 + 1, num);}else {cout << Ans(x2, y2) - Ans(x1 - 1, y2) - Ans(x2, y1 - 1) + Ans(x1 - 1, y1 - 1) << endl;// 查询并输出给定矩形区域的和}}return 0;
}// 计算 (x, y) 处的结果
int Ans(int x, int y)
{return A.query(x, y) * (x * y + x + y + 1) - Ai.query(x, y) * (y + 1) - Aj.query(x, y) * (x + 1) + Aij.query(x, y);
}// 在坐标 (x, y) 处添加值 num
void Add(int x, int y, int num)
{A.add(x, y, num);Ai.add(x, y, num * x);Aj.add(x, y, num * y);Aij.add(x, y, num * x * y);
}

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

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

相关文章

计算机视觉中的特征检测和描述

一、说明 这篇文章是关于计算机视觉中特征检测和描述概念的简要理解。在其中&#xff0c;我们探讨了它们的定义、常用技术、简单的 python 实现和一些限制。 二、什么是特征检测和描述&#xff1f; 特征检测和描述是计算机视觉中的基本概念&#xff0c;在图像识别、对象跟踪和图…

Beats:使用 Filebeat 将 golang 应用程序记录到 Elasticsearch - 8.x

毫无疑问&#xff0c;日志记录是任何应用程序最重要的方面之一。 当事情出错时&#xff08;而且确实会出错&#xff09;&#xff0c;我们需要知道发生了什么。 为了实现这一目标&#xff0c;我们可以设置 Filebeat 从我们的 golang 应用程序收集日志&#xff0c;然后将它们发送…

Maven教程_编程入门自学教程_菜鸟教程-免费教程分享

教程简介 Maven 是一款基于 Java 平台的项目管理和整合工具&#xff0c;它将项目的开发和管理过程抽象成一个项目对象模型&#xff08;POM&#xff09;。开发人员只需要做一些简单的配置&#xff0c;Maven 就可以自动完成项目的编译、测试、打包、发布以及部署等工作。Maven 是…

微信小程序备案流程

微信小程序备案流程 &#x1f4d4; 千寻简笔记介绍 千寻简笔记已开源&#xff0c;Gitee与GitHub搜索chihiro-notes&#xff0c;包含笔记源文件.md&#xff0c;以及PDF版本方便阅读&#xff0c;且是用了精美主题&#xff0c;阅读体验更佳&#xff0c;如果文章对你有帮助请帮我…

二、异常日志

二、异常日志 &#xff08;一&#xff09;、错误码 错误码的制定原则&#xff1a;快速溯源、沟通标准化错误码不体现版本号和错误等级信息全部正常&#xff0c;但不得不填充错误码时返回五个零&#xff1a;00000错误码为字符串类型&#xff0c;共 5 位&#xff0c;分成两个部分…

win10 anaconda pytorch avalanche-lib 实验步骤记录

conda create --name test_python3.10 conda activate test_python3.10 配置conda国内源(北外) conda install pytorch torchvision torchaudio cpuonly -c pytorch pip3 install avalanche-lib -i https://pypi.tuna.tsinghua.edu.cn/simple conda install jupyter jupyte…

[tidb] tiup升级tidb的版本到 v7.1.1

备份 为了避免数据丢失&#xff0c;升级前需要备份当前tidb集群的数据&#xff0c;参考 TiDB 备份与恢复概述 | PingCAP 文档中心 说明 由于新版本的tidb的tiflash需要cpui支持avx2&#xff0c;所有升级前先验证当前升级的服务器是否支持avx2。升级的文档可以参考 使用 TiUP…

Android布局【TableLayout】

文章目录 说明常见属性子控件设置属性 项目结构主要代码 说明 TableLayout也称为表格布局 常见属性 android:collapseColumns&#xff1a;设置需要被隐藏的列的序列号&#xff0c;从0开始android:stretchColumns&#xff1a;设置允许被拉伸的列的列序号&#xff0c;从0开始&…

docker私有镜像仓库搭建

1、下载registry镜像 docker pull registry:2.52、生成登录私有仓库的用户名以及密码 mkdir -p /opt/registry/auth/ docker run --entrypoint htpasswd registry:2.5 -Bbn username userpwd >> /opt/registry/auth/htpasswd3、创建配置文件 mkdir -p /opt/registry/…

Git - 配置代理 和 取消代理配置

一. 配置代理 (使git走网路代理) git config --global http.proxy socks5://127.0.0.1:1080 git config --global https.proxy socks5://127.0.0.1:1080 其中 1080 是 SOCKS 代理的端口&#xff0c;一般默认 1080&#xff0c;可以在代理工具的设置中查看 地址记录&#xff1a…

Python中使用隧道爬虫ip提升数据爬取效率

作为专业爬虫程序员&#xff0c;我们经常面临需要爬取大量数据的任务。然而&#xff0c;有些网站可能会对频繁的请求进行限制&#xff0c;这就需要我们使用隧道爬虫ip来绕过这些限制&#xff0c;提高数据爬取效率。本文将分享如何在Python中使用隧道爬虫ip实现API请求与响应的技…

(十八)大数据实战——Hive的metastore元数据服务安装

前言 Hive的metastore服务作用是为Hive CLI或者Hiveserver2提供元数据访问接口。Hive的metastore 是Hive元数据的存储和管理组件&#xff0c;它负责管理 Hive 表、分区、列等元数据信息。元数据是描述数据的数据&#xff0c;它包含了关于表结构、存储位置、数据类型等信息。本…

Android Jetpack Compose 中的分页与缓存展示

Android Jetpack Compose 中的分页与缓存展示 在几乎任何类型的移动项目中&#xff0c;移动开发人员在某个时候都会处理分页数据。如果数据列表太大&#xff0c;无法一次从服务器检索完毕&#xff0c;这就是必需的。因此&#xff0c;我们的后端同事为我们提供了一个端点&#…

ArcGIS Pro应用—暨基础入门、制图、空间分析、影像分析、三维建模、空间统计分析与建模、python融合、案例应用全流程科研能力提升教程

详情点击链接&#xff1a;ArcGIS Pro应用—暨基础入门、制图、空间分析、影像分析、三维建模、空间统计分析与建模、python融合、案例应用全流程科研能力提升教程 第一&#xff1a;GIS及ArcGIS Pro 1.GIS基本原理及常用软件 2.ArcGIS Pro 安装与配置 3.ArcGIS Pro 3.0 的新…

C语言自动抓取淘宝商品详情网页数据,实现轻松高效爬虫

你是否曾经遇到过需要大量获取网页上的数据&#xff0c;但手动复制粘贴又太过费时费力&#xff1f;那么这篇文章就是为你而写。今天我们将会详细讨论如何使用C语言实现自动抓取网页上的数据。本文将会从以下8个方面进行逐步分析讨论。 1. HTTP协议的基本原理 在开始之前&…

小白到运维工程师自学之路 第七十三集 (kubernetes应用部署)

一、安装部署 1、以Deployment YAML方式创建Nginx服务 这个yaml文件在网上可以下载 cat nginx-deployment.yaml apiVersion: apps/v1 #apiVersion是当前配置格式的版本 kind: Deployment #kind是要创建的资源类型&#xff0c;这里是Deploymnet metadata: #metadata是该资源…

Photoshop多图片与多窗口下排列操作方法

首先&#xff0c;在Photoshop中打开6张图片&#xff0c;在“窗口”菜单下切换窗口排列状态&#xff1a; 在 “窗口”菜单下对窗口进行排列&#xff0c;分别呈现如下&#xff1a; &#xff08;一&#xff09;. 点击“窗口” -> “排列”->"全部垂直拼贴": &am…

本地oracle登录账号锁定处理,the account is locked

1.打开cmd命令窗口 2.打开sqlplus: sqlplus /nolog(加/nolog是不登录服务器的意思&#xff0c;不加就需要输账号密码) 3.切换到管理员&#xff1a;conn / as sysdba; 第2步第3步可以合并&#xff0c;直接使用sysdba登录&#xff1a;sqlplus / as sysdba; 4.解锁账号&#x…

大端和小端

大端和小端 大端&#xff08;Big Endian&#xff09;和小端&#xff08;Little Endian&#xff09;是两种不同的字节序排列方式&#xff0c;用于解释多字节数据在内存中的存储顺序。 在大端字节序中&#xff0c;高位字节&#xff08;最高有效位&#xff09;存储在低位地址&am…

1. 两数之和

题目&#xff1a; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你…