树状数组原理和代码

树状数组

求下标的对应

求i管着的下标的范围

方法:拆掉最右侧的1然后+1  到你自己

query sum

1-i的和

拆掉最右侧的1 再把下一个数值吸收到sum 重复这个过程直到全变0为止

add

方法:加上最右侧的1 到上限为止

lowbit方法

单点增加范围查询模板

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include<vector>
#include<climits>
#include<cmath>
using namespace std;
typedef long long LL;
const int N=5e5+10;
int tree[N];
int n,m;int lowbit(int i){return i&-i;
}void add(int i,int v){while(i<=n){tree[i]+=v;i+=lowbit(i);}
}int sum(int i){int ans=0;while(i>0){ans+=tree[i];i-=lowbit(i);}return ans;
}int range(int l,int r){return sum(r)-sum(l-1);
}int main() {ios::sync_with_stdio(false); // 可选的,用于加快I/Ocin.tie(0);while (cin >> n >> m) {for (int i = 1, v; i <= n; i++) {cin >> v;add(i, v);}for (int i = 1, a, b, c; i <= m; i++) {cin >> a >> b >> c;if (a == 1) {add(b, c);} else {cout << range(b, c) << '\n';}}}return 0;
}

范围增加单点查询的模板

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include<vector>
#include<climits>
#include<cmath>
using namespace std;
typedef long long LL;
const int N=5e5+10;
int tree[N];
int n,m;int lowbit(int i){return i&-i;
}void add(int i,int v){while(i<=n){tree[i]+=v;i+=lowbit(i);}
}int sum(int i){int ans=0;while(i>0){ans+=tree[i];i-=lowbit(i);}return ans;
}int range(int l,int r){return sum(r)-sum(l-1);
}int main() {while (cin >> n >> m) {for (int i = 1, v; i <= n; i++) {cin >> v;add(i, v);add(i + 1, -v);}for (int i = 1; i <= m; i++) {int op;cin >> op;if (op == 1) {int l, r, v;cin >> l >> r >> v;add(l, v);add(r + 1, -v);} else {int index;cin >> index;cout << sum(index) << '\n';}}}return 0;
}

树状数组实现范围增加范围查询

#include <iostream>
using namespace std;const int MAXN = 100001;
long long info1[MAXN]; // 维护原始数组的差分信息:Di
long long info2[MAXN]; // 维护原始数组的差分加工信息:(i-1) * Di
int n, m;int lowbit(int i) {return i & -i;
}void add(long long tree[], int i, long long v) {while (i <= n) {tree[i] += v;i += lowbit(i);}
}long long sum(long long tree[], int i) {long long ans = 0;while (i > 0) {ans += tree[i];i -= lowbit(i);}return ans;
}void rangeAdd(int l, int r, long long v) {add(info1, l, v);add(info1, r + 1, -v);add(info2, l, (l - 1) * v);add(info2, r + 1, -(r * v));
}long long rangeQuery(int l, int r) {return sum(info1, r) * r - sum(info2, r) - sum(info1, l - 1) * (l - 1) + sum(info2, l - 1);
}int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin >> n >> m;long long cur;for (int i = 1; i <= n; ++i) {cin >> cur;rangeAdd(i, i, cur);}int op, l, r;long long v;for (int i = 1; i <= m; ++i) {cin >> op;if (op == 1) {cin >> l >> r >> v;rangeAdd(l, r, v);} else {cin >> l >> r;cout << rangeQuery(l, r) << '\n';}}return 0;
}

相关题目

逆序对

归并分治法

#include <iostream>
#include <vector>
using namespace std;const int MAXN = 500001;
int arr[MAXN];
int help[MAXN];
int n;
long long merge(int l, int m, int r);long long f(int l, int r) {if (l == r) {return 0;}int m = (l + r) / 2;return f(l, m) + f(m + 1, r) + merge(l, m, r);
}long long merge(int l, int m, int r) {long long ans = 0;// 统计逆序对数量for (int i = m, j = r; i >= l; i--) {while (j >= m + 1 && arr[i] <= arr[j]) {j--;}ans += j - m;}// 归并排序,让arr[l...r]变成有序int i = l, a = l, b = m + 1;while (a <= m && b <= r) {help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];}while (a <= m) {help[i++] = arr[a++];}while (b <= r) {help[i++] = arr[b++];}for (i = l; i <= r; i++) {arr[i] = help[i];}return ans;
}int main() {cin >> n;for (int i = 1; i <= n; i++) {cin >> arr[i];}cout << f(1, n) << '\n';return 0;
}

树状数组解法

去重+离散化

#include <iostream>
#include <algorithm>
using namespace std;const int MAXN = 500001;
int arr[MAXN];
int sortArr[MAXN]; // 用于排序和去重的数组
int tree[MAXN]; // 树状数组
int n, m; // n为数组长度,m为离散化后的值域大小int lowbit(int x) {return x & (-x);
}void add(int idx, int val) {while (idx <= m) {tree[idx] += val;idx += lowbit(idx);}
}long long sum(int idx) {long long res = 0;while (idx > 0) {res += tree[idx];idx -= lowbit(idx);}return res;
}// 离散化函数,将数组arr中的值映射到1~m
void discretization() {sort(sortArr + 1, sortArr + n + 1);m = unique(sortArr + 1, sortArr + n + 1) - (sortArr + 1); // unique返回去重后的尾后迭代器for (int i = 1; i <= n; ++i) {arr[i] = lower_bound(sortArr + 1, sortArr + m + 1, arr[i]) - sortArr;}
}long long compute() {long long ans = 0;for (int i = n; i >= 1; --i) {ans += sum(arr[i] - 1);add(arr[i], 1);}return ans;
}int main() {ios::sync_with_stdio(false); // 关闭同步cin.tie(0); // 解除cin和cout的绑定cout.tie(0);cin >> n;for (int i = 1; i <= n; ++i) {cin >> arr[i];sortArr[i] = arr[i];}discretization(); // 离散化处理cout << compute() << endl; // 计算逆序对数量并输出return 0;
}

上升三元组

#include <iostream>
#include <algorithm>
#include <vector>using namespace std;const int MAXN = 30001;
int arr[MAXN], sortArr[MAXN];
long long tree1[MAXN], tree2[MAXN];
int n, m;int lowbit(int i) {return i & -i;
}void add(long long tree[], int i, long long c) {while (i <= m) {tree[i] += c;i += lowbit(i);}
}long long sum(long long tree[], int i) {long long ans = 0;while (i > 0) {ans += tree[i];i -= lowbit(i);}return ans;
}long long compute() {copy(arr + 1, arr + n + 1, sortArr + 1);sort(sortArr + 1, sortArr + n + 1);m = unique(sortArr + 1, sortArr + n + 1) - (sortArr + 1);for (int i = 1; i <= n; i++) {// Using lower_bound to replace the manual rank functionarr[i] = lower_bound(sortArr + 1, sortArr + m + 1, arr[i]) - sortArr;}long long ans = 0;for (int i = 1; i <= n; i++) {ans += sum(tree2, arr[i] - 1);add(tree1, arr[i], 1);add(tree2, arr[i], sum(tree1, arr[i] - 1));}return ans;
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cin >> n;for (int i = 1; i <= n; i++) {cin >> arr[i];}cout << compute() << endl;return 0;
}

最长递增子序列个数

673. 最长递增子序列的个数

#include <vector>
#include <algorithm>
#include <numeric> // 用于iota函数
using namespace std;class Solution {
public:static const int MAXN = 2001; // 设置最大数值范围vector<int> treeMaxLen = vector<int>(MAXN, 0); // 以数值i结尾的最长递增子序列的长度vector<int> treeMaxLenCnt = vector<int>(MAXN, 0); // 以数值i结尾的最长递增子序列的个数int m; // 数组去重排序后的长度int lowbit(int i) {return i & (-i);}void query(int i, int& maxLen, int& maxLenCnt) {maxLen = maxLenCnt = 0;while (i > 0) {if (treeMaxLen[i] == maxLen) {maxLenCnt += treeMaxLenCnt[i];} else if (treeMaxLen[i] > maxLen) {maxLen = treeMaxLen[i];maxLenCnt = treeMaxLenCnt[i];}i -= lowbit(i);}}void add(int i, int len, int cnt) {while (i <= m) {if (treeMaxLen[i] == len) {treeMaxLenCnt[i] += cnt;} else if (treeMaxLen[i] < len) {treeMaxLen[i] = len;treeMaxLenCnt[i] = cnt;}i += lowbit(i);}}int findNumberOfLIS(vector<int>& nums) {if (nums.empty()) return 0;vector<int> sortedNums(nums.begin(), nums.end());sort(sortedNums.begin(), sortedNums.end());auto it = unique(sortedNums.begin(), sortedNums.end()); // 去重,it指向去重后新的末尾m = distance(sortedNums.begin(), it); // 使用迭代器之间的距离作为去重后数组的长度// 根据去重后的长度调整树状数组的大小treeMaxLen.assign(m + 1, 0);treeMaxLenCnt.assign(m + 1, 0);for (int num : nums) {// 注意这里的lower_bound的范围,应当是begin()到itint i = lower_bound(sortedNums.begin(), it, num) - sortedNums.begin() + 1; // 获取排名(1-based)int maxLen, maxLenCnt;query(i - 1, maxLen, maxLenCnt);add(i, maxLen + 1, maxLenCnt == 0 ? 1 : maxLenCnt);}int totalMaxLen = 0, totalCount = 0;query(m, totalMaxLen, totalCount);return totalCount;
}};

P1972 [SDOI2009] HH的项链

每种颜色只留最右边的

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>using namespace std;const int MAXN = 1000010;
int arr[MAXN], ans[MAXN], map[MAXN], tree[MAXN], n, m;struct Query {int l, r, idx;Query(int l = 0, int r = 0, int idx = 0) : l(l), r(r), idx(idx) {}
};vector<Query> queries(MAXN);int lowbit(int i) {return i & -i;
}void add(int i, int v) {while (i <= n) {tree[i] += v;i += lowbit(i);}
}int sum(int i) {int ans = 0;while (i > 0) {ans += tree[i];i -= lowbit(i);}return ans;
}int range(int l, int r) {return sum(r) - sum(l - 1);
}void compute() {sort(queries.begin() + 1, queries.begin() + m + 1, [](const Query& a, const Query& b) {return a.r < b.r;});for (int s = 1, q = 1; q <= m; q++) {int r = queries[q].r;for (; s <= r; s++) {if (map[arr[s]] != 0) {add(map[arr[s]], -1);}add(s, 1);map[arr[s]] = s;}ans[queries[q].idx] = range(queries[q].l, r);}
}int main() {scanf("%d", &n);for (int i = 1; i <= n; i++) {scanf("%d", &arr[i]);}scanf("%d", &m);for (int i = 1; i <= m; i++) {int l, r;scanf("%d %d", &l, &r);queries[i] = Query(l, r, i);}compute();for (int i = 1; i <= m; i++) {printf("%d\n", ans[i]);}return 0;
}

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

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

相关文章

Java八股文(SpringCloud Alibaba)

Java八股文のSpringCloud Alibaba SpringCloud Alibaba SpringCloud Alibaba Spring Cloud Alibaba与Spring Cloud有什么区别&#xff1f; Spring Cloud Alibaba是Spring Cloud的衍生版本&#xff0c;它是由Alibaba开发和维护的&#xff0c;相比于Spring Cloud&#xff0c;它在…

【PLC】PROFIBUS(二):总线协议DP、PA、FMS

1、总线访问协议 (FDL) 1.1、多主通信 多个主设备间&#xff0c;使用逻辑令牌环依次向从设备发送命令。 特征&#xff1a; 主站间使用逻辑令牌环、主从站间使用主从协议主站在一个限定时间内 (Token Hold Time) 对总线有控制权从站只是响应一个主站的请求它们对总线没有控制…

【Java程序设计】【C00383】基于(JavaWeb)Springboot的水产养殖系统(有论文)

【C00383】基于&#xff08;JavaWeb&#xff09;Springboot的水产养殖系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c…

【包邮送书】一本书掌握数字化运维方法,构建数字化运维体系

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

11.数据库技术(下)

1.select语句 中括号表示可有可无&#xff1b; 尖括号表示变量名&#xff1b; 分组后再筛选&#xff0c;用having&#xff1b;分组前筛选&#xff0c;用where&#xff1b; select后跟随的所有列&#xff0c;除聚集函数外&#xff0c;都需要列在group by后&#xff1b; 注&…

IDEA : 已经有一个永久破解版的IDEA2019版本,现在又想安装最新版本的,俩版本共存,发现新版本打不开的解决方案

在新文件的目录下&#xff0c;注释掉一行19版本的地址 地址&#xff1a;C:\Users\23999\AppData\Roaming\JetBrains\IntelliJIdea2023.2 (不同电脑Users后边的一个地址的注释会不一样) 然后找到该目录下的indea64.exe.vmoptions 用 记事本 打开 在-javaagent 那一栏里会自动给…

【业界动态】Digital Twin-数字孪生

绝大多数的人对数字孪生是一个模糊的概念&#xff0c;数字孪生也被称为数字映射、数字镜像&#xff0c;他既是一种技术&#xff0c;也是一种生态。随着互联网的建设与发展&#xff0c;数字孪生在未来又会如何发展&#xff0c;虚拟与现实之间会产生怎样的星火&#xff1f; 上帝按…

算法(6)KMP+trie

KMP&#xff1a; 最浅显易懂的 KMP 算法讲解_哔哩哔哩_bilibili 该视频使用python书写代码&#xff0c;不会python的小伙伴也可以看看了解kmp的大致思路。 问题描述&#xff1a; kmp&#xff1a;字符串匹配算法&#xff0c;用来找一个长字符串中出现了几次小字符串&#xf…

AIGC——ComfyUI SDXL多种风格预设提示词插件安装与使用

概述 SDXL Prompt Styler可以预先给SDXL模型提供了各种预设风格的提示词插件&#xff0c;相当于预先设定好了多种不同风格的词语。使用这个插件&#xff0c;只需从中选取所需的风格&#xff0c;它会自动将选定的风格词汇添加到我们的提示中。 安装 插件地址&#xff1a;http…

scrapy爬虫框架

scrapy爬虫框架 一、scrapy的概念作用和工作流程1、scrapy的概念2、scrapy框架的作用3、scrapy的工作流程&#xff08;重点&#xff09;3.1 回顾之前的爬虫流程3.2 改写上述流程3.3 scrapy的流程3.4 scrapy的三个内置对象3.5 scrapy中每个模块的具体作用 二、scrapy的入门使用1…

注册、配置中心-微服务小白入门(2)

Nacos 已经下载安装并且使用了&#xff0c;那么看如何使用&#xff1a; Nacos 注册及配置&#xff0c;以下是一个服务启动后注册到nacos&#xff0c;同时&#xff0c;把该服务的相关配置&#xff0c;写到nacos之中 1、nacos设置 命名空间中&#xff0c;添加对应的服务命名空间…

基于单片机病房温度监测与呼叫系统设计

**单片机设计介绍&#xff0c;基于单片机病房温度监测与呼叫系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机病房温度监测与呼叫系统设计概要主要涵盖了通过单片机技术实现病房温度的实时监测以及病人呼叫功能…

python入门题:输入输出练习

以下是Python基础语法的练习&#xff0c;项目要求和代码如下&#xff1a; """ 例3&#xff1a;小精灵&#xff1a;你好&#xff0c;欢迎古灵阁&#xff0c;请问您需要帮助吗&#xff1f;需要or不需要&#xff1f; 你&#xff1a;需要 小精灵&#xff1a;请问你需…

免杀对抗-C2远控篇CC++SC转换格式UUID标识MAC物理IPV4地址减少熵值

参考文章&#xff1a; https://github.com/INotGreen/Bypass-AMSI https://mp.weixin.qq.com/s/oJ8eHdX8HGuk6dZv0kmFxg https://kyxiaxiang.github.io/2022/12/14/AMSIandEtw https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell 文章参考&#xff1a; https://www.…

刷到一个问题还请道友们解疑

问题如上&#xff0c;题目挺简单的&#xff0c;就是插入后排序的思路&#xff0c;我的代码如下&#xff1a; #include <bits/stdc.h>using namespace std; int f(int x,int y){return x < y;//其实要这个没有用&#xff0c;默认是就是从小到大排序 }int main(){int n…

代码随想录——搜索插入位置(Leetcode35)

题目链接 class Solution {public int searchInsert(int[] nums, int target) {int len nums.length;int left 0;int right len - 1;int index -1;while(left < len / 2){if(nums[left] target || target < nums[left]){index left;break;}else{left;}if(nums[ri…

LabVIEW高效光伏数据监控与管理系统

LabVIEW高效光伏数据监控与管理系统 随着新能源技术的发展&#xff0c;光伏发电系统作为一种清洁、高效的能源获取方式受到了广泛的关注。但是&#xff0c;由于光伏发电的特性受到多种环境因素的影响&#xff0c;其运行效率和安全性成为了关键问题。因此&#xff0c;开发一个高…

Automatic Prompt Engineering

让大模型自己生成prompt&#xff0c;生成提示&#xff08;prompt&#xff09;存在两种不同的操作方式。第一种方式是在文本空间中进行&#xff0c;这种提示以离散的文本形式存在。第二种方式是将提示抽象成一个向量&#xff0c;在特征空间中进行操作&#xff0c;这种提示是抽象…

【智能算法】飞蛾扑火算法(MFO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2015年&#xff0c;Mirjalili等人受到飞蛾受到火焰吸引行为启发&#xff0c;提出了飞蛾算法(Moth-Flame Optimization&#xff0c;MFO)。 2.算法原理 2.1算法思想 MFO基于自然界中飞蛾寻找光源的…

STL的基本概念

一、STL的诞生 长久以来&#xff0c;软件界一直希望建立一种可重复利用的东西 C的面向对象和泛型编程思想&#xff0c;目的就是复用性的提升 面向对象的三大特性(简单理解) 封装&#xff1a;把属性和行为抽象出来作为一个整体来实现事和物 继承&#xff1a;子类继承父类&a…