树状数组原理和代码

树状数组

求下标的对应

求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.mzph.cn/news/768317.shtml

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

相关文章

no main manifest attribute, in xxx.jar

找不到主类&#xff0c;如果是maven 项目&#xff0c;在pom.xml 指定主类 <mainClass>com.example.demo.Demo2Application</mainClass>还是不行的话&#xff0c;把 <skip>true</skip>去掉

nodejs+vue高校师资管理系统python-flask-django-php

快速发展的社会中&#xff0c;人们的生活水平都在提高&#xff0c;生活节奏也在逐渐加快。为了节省时间和提高工作效率&#xff0c;越来越多的人选择利用互联网进行线上打理各种事务&#xff0c;然后线上管理系统也就相继涌现。与此同时&#xff0c;人们开始接受方便的生活方式…

从FasterTransformer源码解读开始了解大模型(1.0)了解FasterTransformer

从FasterTransformer源码解读开始了解大模型&#xff08;1.0&#xff09;了解FasterTransformer 写在前面的话 最近的一年时间真是令人感慨&#xff0c;换了个工作方向&#xff0c;学了些深度算子开发相关知识&#xff0c;工作也转到对LLM的学习和开发了。入行不算深&#xf…

谷粒商城——缓存的概念

1. 使用缓存的好处&#xff1a;减少数据库的访问频率&#xff0c;提高用户获取数据的速度。 2. 什么样的数据适合存储到缓存中&#xff1f; ①及时性、数据一致性要求不高的数据&#xff0c;例如物流信息、商品类目信息 ②访问量大更新频率不高的数据(读多、写少) 3. 读模式…

加密技术概述

传输数据时的四个问题 窃听 数字加密 假冒 消息认证或数字签名 篡改 消息认证码或数字签名 事后否认 数字签名 加密技术 将数据变成第三者的计算机无法理解的形式&#xff0c;然后再将其恢复成原本数据的一系列操作就是加密技术。 哈希函数 哈希函数可以把给定的数据转…

设计模式之状态模式(一)

设计模式专栏&#xff1a; http://t.csdnimg.cn/4Mt4u 目录 1.概述 2.结构 3.实现 4.总结 1.概述 状态模式( State Pattern)也称为状态机模式( State Machine pattern), 是允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类, 属于行为型模式。 在状…

Vue3+echarts绘制世界地图

先放效果图 之前所查找的资料都没有讲清楚如何引入地图文件并绘制地图&#xff0c;下面做一个记录。 首先下载对应的地图json文件&#xff0c;这里可以参考我的这篇文章&#xff0c;提供了下载地址&#xff1a;记录echarts各种地图json文件下载地址-CSDN博客 第二步&#xff…

笔记本和台式机主板内部结构分析

笔记本和态势机主板内存接口以及配件安装位置 笔记本主板 1 以thinkpad L-490为例,使用拆机小工具拆机&#xff0c;打开后面板&#xff0c;内部结构示意图如下 台式机主板 以技嘉-B660M-AORUS-PRO-AX型号主板为例 笔记本电脑和台式机电脑的相同之处 CPU&#xff1a;笔记本…

【boost_search搜索引擎】1.获取数据源

boost搜索引擎 1、项目介绍2、获取数据源 1、项目介绍 boost_search项目和百度那种不一样&#xff0c;百度是全站搜索&#xff0c;而boost_search是一个站内搜索。而项目的宏观上实现思路就如同图上的思路。 2、获取数据源 我们要实现一个站内搜索&#xff0c;我们就要有这…

Rust 程序设计语言学习——结构体

结构体和元组类似&#xff0c;它们都包含多个相关的值。和元组一样&#xff0c;结构体的每一部分可以是不同类型。但不同于元组&#xff0c;结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字&#xff0c;结构体比元组更灵活&#xff1a;不需要依赖顺序来…

医院预约挂号系统设计与实现|jsp+ Mysql+Java+ Tomcat(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java&#xff0c;…

初识kafka-数据存储篇1

目录 背景 1 kafka总体体系结构 2 疑问解答 2.1 高吞吐低延迟 2.2 实现分布式存储和数据读取 2.3 如何保证数据不丢失 背景 最近在和产品过项目审批的时候&#xff0c;深刻感受到业务方对系统的时时响应提出了更高的要求。目前手上大部分的业务都是基础定时任务去实现的&…

nodejs+vue高校会议室预订管理系统python-flask-django-php

伴随着我国社会的发展&#xff0c;人民生活质量日益提高。于是对系统进行规范而严格是十分有必要的&#xff0c;所以许许多多的信息管理系统应运而生。此时单靠人力应对这些事务就显得有些力不从心了。所以本论文将设计一套高校会议室预订管理系统&#xff0c;帮助学校进行会议…

JDK,JRE,JVM之间的关系

他们明面上的关系是JDK包含JRE&#xff0c;JRE包含JVM。 简单理解JDK就是Java开发工具包。JRE是Java运行环境。JVM是Java虚拟机。 JDK是面向开发者的&#xff0c;JRE是面向JAVA程序的用户的。也就是说开发者开发JAVA程序是需要用到JDK&#xff0c;如果用户不去开发JAVA程序&am…

OpenHarmony IDL工具规格及使用说明书(仅对系统应用开放)

IDL接口描述语言简介 当客户端和服务器进行IPC通信时&#xff0c;需要定义双方都认可的接口&#xff0c;以保障双方可以成功通信&#xff0c;OpenHarmony IDL&#xff08;OpenHarmony Interface Definition Language&#xff09;则是一种定义此类接口的工具。OpenHarmony IDL先…

初识 Redis 浅谈分布式

目 录 一.认识 Redis二.浅谈分布式单机架构分布式是什么数据库分离和负载均衡理解负载均衡数据库读写分离引入缓存数据库分库分表引入微服务 三.概念补充四.分布式小结 一.认识 Redis 在 Redis 官网我们可以看到介绍 翻译过来就是&#xff1a;数以百万计的开发人员用作缓存、…

nodejs+vue高校社团管理小程序的设计与实现python-flask-django-php

相比于以前的传统手工管理方式&#xff0c;智能化的管理方式可以大幅降低学校的运营人员成本&#xff0c;实现了高校社团管理的标准化、制度化、程序化的管理&#xff0c;有效地防止了高校社团管理的随意管理&#xff0c;提高了信息的处理速度和精确度&#xff0c;能够及时、准…

t-rex2开放集目标检测

论文链接&#xff1a;http://arxiv.org/abs/2403.14610v1 项目链接&#xff1a;https://github.com/IDEA-Research/T-Rex 这篇文章的工作是基于t-rex1的工作继续做的&#xff0c;核心亮点&#xff1a; 是支持图片/文本两种模态的prompt进行输入&#xff0c;甚至进一步利用两…

CCF-CSP认证考试 202303-5 施肥 35/60/75/100分题解

更多 CSP 认证考试题目题解可以前往&#xff1a;CSP-CCF 认证考试真题题解 原题链接&#xff1a; 202303-5 施肥 时间限制&#xff1a; 2.0s 内存限制&#xff1a; 1.0GB 问题描述 春天到了&#xff0c;西西艾弗岛上的 n n n 块田地需要施肥了。 n n n 块田地编号为 1 , 2…

基于Google云原生工程师的kubernetes最佳实践(二)

目录 二、应用部署篇 为deployment打上丰富的label,以便selecting 使用sidecar容器部署agent、proxy等组件 使用init container处理依赖关系,而不要用sidecar 镜像tag使用版本号,不要用latest或空tag 为pod设置readiness和liveness探针 不要给所有服务都使用LoadBalance…