高级数据结构—树状数组

引入问题:

给出一个长度为n的数组,完成以下两种操作:
1. 将第i个数加上k

2. 输出区间[i,j]内每个数的和

朴素算法:

单点修改:O( 1 )

区间查询:O( n )

使用树状数组:

单点修改:O( logn )

区间查询:O( logn )

前置知识:

lowbit()
运算:非负整数x在二进制表示下最低位1及其后面的0构成的数值。

如lowbit(12)= 1100 = 4

函数实现: 

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

树状数组思想:

树状数组的主要思想就是利用树结构维护“前缀和”。

对于一个序列,对其建立如下树形结构:

1.每个结点t[x]保存以x为根的子树中叶结点值的和
2.每个结点覆盖的长度为lowbit(x)
3.t[x]结点的父结点为t[x + lowbit(x)]
4.树的深度为log2n+1

树状数组操作:

add(x, k)表示将序列中第x个数加上k。

在整棵树上维护这个值,需要一层一层向上找到父结点,并将这些结点上的t[x]值都加上k,这样保证计算区间和时的结果正确。

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

ask(x)表示将查询序列前x个数的和

以ask(7)为例:
查询这个点的前缀和,需要从这个点向左上找到上一个结点,将加上其结点的值。向左上找到上一个结点,只需要将下标 x -= lowbit(x),例如 7 - lowbit(7) = 6

int ask(int x)
{int sum = 0;for(int i = x; i; i -= lowbit(i))sum += t[i];return sum;
}

例题: 

楼兰图腾

题目链接:楼兰图腾

从左向右依次遍历每个数a[i],使用树状数组统计在i位置之前所有比a[i]大的数的个数、以及比a[i]小的数的个数。
统计完成后,将a[i]加入到树状数组。

从右向左依次遍历每个数a[i],使用树状数组统计在i位置之后所有比a[i]大的数的个数、以及比a[i]小的数的个数。
统计完成后,将a[i]加入到树状数组。

代码附上:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5+5;
int tr[N];
int low[N],great[N];
int a[N];
int n;int lowbit(int x){return x&(-x);
}void add(int x,int c){for(int i=x;i<=n;i+=lowbit(i)){tr[i]+=c;}return;
}int ask(int x){int res=0;for(int i=x;i>=1;i-=lowbit(i)){res+=tr[i];}return res;
}signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++){//记录i点左边的信息int y=a[i];low[i]=ask(y-1);//low[i]记录左边[1,y-1]区间的数字个数great[i]=ask(n)-ask(y);//great[i]记录左边[y+1,n]区间的数字个数add(y,1);//加入树状数组中,出现一次+1}memset(tr,0,sizeof(tr));//初始化int ans1=0,ans2=0;for(int i=n;i>=1;i--){//记录i点右边的信息int y=a[i];ans2+=low[i]*ask(y-1);//乘法原理ans1+=great[i]*(ask(n)-ask(y-1));add(y,1);}cout<<ans1<<" "<<ans2<<"\n";return 0;
}

一个简单的整数问题

题目链接:一个简单的整数问题

区间修改 + 求单点

那么这道题目可以采用差分的方法去做,在上一道题目中我们求的是区间和,采用前缀和的思想去做,那么这里我们可以把单点a[i]看成前缀和,因为a[i]=\sum差分和。

首先我们要先建差分数组:

for(int i=1;i<=n;i++){add(i,a[i]-a[i-1]);}

 那么接下来的情况就跟第一题一样了

代码附上:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N =1e5+5;
int a[N],tr[N],low[N],great[N];
int n,q;int lowbit(int x){return x&-x;
}void add(int x,int c){for(int i=x;i<=n;i+=lowbit(i)){tr[i]+=c;}return;
}int ask(int x){int res=0;for(int i=x;i>=1;i-=lowbit(i)){res+=tr[i];}return res;
}signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n>>q;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++){add(i,a[i]-a[i-1]);}while(q--){char op;cin>>op;if(op=='C'){int l,r,d;cin>>l>>r>>d;add(l,d);add(r+1,-d);}else if(op=='Q'){int l;cin>>l;cout<<ask(l)<<"\n";}}return 0;
}

一个简单的整数问题2

题目链接:一个简单的整数问题2

区间查询+区间修改

直接上图:

 所以这道题目我们需要维护两个树状数组,一个是d[i],另一个是i*d[i]。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+5;
int n,m;
int a[N];
int tr[N],tr2[N];
//tr[]数组是原始数组的差分数组d[i]的树状数组
//tr2[]数组是原始数组的差分数组乘以i即i*d[i]的树状数组int lowbit(int x){return x&-x;
}void add1(int x,int c){for(int i=x;i<=n;i+=lowbit(i)){tr[i]+=c;}return;
}void add2(int x,int c){for(int i=x;i<=n;i+=lowbit(i)){tr2[i]+=c;}return;
}int ask1(int x){int res=0;for(int i=x;i>=1;i-=lowbit(i)){res+=tr[i];}return res;
}int ask2(int x){int res=0;for(int i=x;i>=1;i-=lowbit(i)){res+=tr2[i];}return res;
}int get_sum(int x){//最后一步的推导return ask1(x)*(x+1)-ask2(x);
}signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n>>m;memset(tr2,0,sizeof(tr2));memset(tr,0,sizeof(tr));for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++){int b=a[i]-a[i-1];add1(i,b);add2(i,b*i);}while(m--){char op;cin>>op;if(op=='Q'){int l,r;cin>>l>>r;cout<<get_sum(r)-get_sum(l-1)<<"\n";}else if(op=='C'){int l,r,d;cin>>l>>r>>d;add1(l,d),add1(r+1,-d);add2(l,l*d),add2(r+1,(r+1)*(-d));}}return 0;
}

谜一样的牛

题目链接:谜一样的牛

仅仅根据题目的信息,很难找出他们之间的高度关系。面对这种题目,我们可以从边界去思考,(正着不行就反着来),从最后一头牛看,最后一头牛的a[i]表示前i头牛有x个比它矮的,那么也就意味着它排第x+1位,那么从倒数第二头牛来看,前面有y头比它矮的,那最后一头牛可能比它高也可能比它矮,因此,对于倒数第二头牛而言,它应该在除去上述x+1的区间[1,n]中,选取A(n−1)+1小的数。其他的牛以此类推。

假如建立一个全部元素为1的数列,某个位置的数为1代表这个高度还不知道是哪头牛的,那么就用树状数组维护该数列的前缀和,若某个位置的前缀和等于A(i)+1此时的下标就是要找的数。选择这个数后,将相应位置的1置0.可以二分这个位置。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+5;
int a[N],ans[N],tr[N];
int n;int lowbit(int x){return x&-x;
}void add(int x,int c){for(int i=x;i<=n;i+=lowbit(i)){tr[i]+=c;}	return;
}int ask(int x){int res=0;for(int i=x;i>=1;i-=lowbit(i)){res+=tr[i];}return res;
}signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n;a[1]=0;for(int i=2;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)tr[i]=lowbit(i);//初始化for(int i=n;i>=1;i--){//从后往前枚举int k=a[i]+1;//找剩余的牛中高度排第kint l=1,r=n;while(l<r){int mid=(l+r)/2;if(ask(mid)>=k)r=mid;else l=mid+1;}ans[i]=r;add(r,-1);//高度排第r的牛去掉}for(int i=1;i<=n;i++){cout<<ans[i]<<"\n";}return 0;
}

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

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

相关文章

17-软件脉冲宽度调制(SW_PWM)

ESP32-S3的软件脉冲宽度调制&#xff08;SW_PWM&#xff09; 引言 ESP32-S3 LED 控制器LEDC 主要用于控制 LED&#xff0c;也可产生PWM信号用于其他设备的控制。该控制器有 8 路通道&#xff0c;可以产生独立的波形&#xff0c;驱动 RGB LED 等设备。LED PWM 控制器可在无需C…

CLion远程调试

一 CLion远程调试 ## 1.1 建立远程连接过程 设置——部署——“”——SFTP——新建服务器名称——输入主机、用户名、密码信息——确定 工具链建立远程主机 设置——工具链——“”——远程主机——凭据新增服务器信息 上传本地代码到服务器 ps:要保证本地文件完整&#…

测试人员一定要避免的这些不专业行为!

软件测试并非一个简单的任务&#xff0c;需要高度的专业性和责任感&#xff0c;本文将探讨一些常见的不专业行为&#xff0c;及其对软件开发过程和产品质量可能产生的负面影响。 1. 忽略细节 在测试过程中忽视细节&#xff0c;导致测试不彻底&#xff0c;漏洞未被发现。 2. …

从 Android 恢复已删除文件的 3 种简单方法

如何从 Android 恢复已删除的文件&#xff1f;毫不犹豫&#xff0c;有些人可能会认为从 Google 备份恢复 Android 文件太容易了。但是&#xff0c;如果删除的文件未同步到您的帐户或未备份怎么办&#xff1f;您错误的恢复可能会永久删除您想要的数据。因此&#xff0c;我们发布…

常见的软件架构模式

在软件开发过程中&#xff0c;软件架构模式是实现高质量、可扩展系统的关键。本文将介绍一些常见的软件架构模式&#xff0c;分析其优缺点和适用场景&#xff0c;从而帮助大家在实际项目中做出更明智的架构选择&#xff08;注意以下的架构模式相互之间并不一定互斥&#xff0c;…

23种设计模式之抽象工厂

简单工厂和工厂方法 关注 产品等级 抽象工厂 关注 产品族 对于比较稳定的产品&#xff0c;抽象工厂更有效率&#xff08;一个工厂生产很多产品族&#xff09; 抽象工厂代码例子加深理解

我与C++的爱恋:类和对象(三)

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;我与C的爱恋 先来回顾一下&#xff0c;上一节的内容并且通过上次的内容来做一道oj题。 https://leetcode.cn/problems/implement-queue-using-stacks/ class MyQueue { private:stack&l…

【LeetCode:216. 组合总和 III + 递归】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

JavaSE-15笔记【注解(+2024新)】

文章目录 1.注解概述2.几个常用的JDK内置的注解2.1 Deprecated2.2 Override2.3 SuppressWarnings2.4 FunctionalInterface 3.自定义注解3.1 注解也可以定义属性3.2 注解的使用规则补充 4.元注解4.1 Retention4.2 Target4.3 Documented4.4 Inherited4.5 Repeatable 5.通过反射获…

微信小程序开发

微信小程序隶属于前端&#xff0c;因此我们只需要了解掌握一些基本的功能与业务逻辑即可。 HttpClient HttpClient 是Apache Jakarta Common 下的子项目&#xff0c;可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包&#xff0c;并且它支持 HTTP 协议…

Robbins-Monro(RM)算法【随机近似】

强化学习笔记 主要基于b站西湖大学赵世钰老师的【强化学习的数学原理】课程&#xff0c;个人觉得赵老师的课件深入浅出&#xff0c;很适合入门. 第一章 强化学习基本概念 第二章 贝尔曼方程 第三章 贝尔曼最优方程 第四章 值迭代和策略迭代 第五章 强化学习实践—GridWorld 第…

WP-AutoPostPro 汉化版: WordPress自动采集发布插件

WP-AutoPostPro 是目前最好用的WordPress自动采集发布插件&#xff0c;最大的特点是可以采集来自于任何网站的内容并自动发布到你的WordPress站点。真正做到可以采集任何网站的内容并自动发布&#xff0c;采集过程完全自动进行无需人工干预&#xff0c;并提供内容过滤、HTML标签…

libssh C++封装(一)

1 概述 libssh是一个在客户端和服务器端实现SSHv2协议的多平台C库。使用libssh&#xff0c;您可以远程执行程序、传输文件、使用安全透明的隧道、管理公钥等等。本文描述的对libssh客户端功能的C封装。 libssh下载地址 2 设计 2.1 类图 类型说明&#xff1a; Session SSH连接…

Centos7 的 Open Stack T 版搭建流程 --- (三)配置消息队列

配置消息队列 文章目录 配置消息队列&#xff08;1&#xff09;安装 RabbitMQ 服务并配置新用户权限controller &#xff08;2&#xff09;如何开启图形化&#xff08;拓展&#xff09; &#xff08;1&#xff09;安装 RabbitMQ 服务并配置新用户权限 controller yum install…

开源AI智能名片源码:虚实融合引领品牌营销新篇章

随着数字时代的飞速发展&#xff0c;品牌营销已经步入了一个全新的纪元。在这个变革的时代&#xff0c;开源AI智能名片源码以其独特的虚实融合功能&#xff0c;正引领着品牌营销走向更加智能化、个性化的道路。 传统的品牌营销往往局限于单向的信息传播&#xff0c;难以与用户产…

成都污水处理站运维厂家服务商

选择污水处理运维服务厂家时&#xff0c;需要考虑以下几个关键的事项来确保您选择了合适的服务提供商&#xff1a; 1. **资质和认证&#xff1a;** 确认厂家是否具备国家或地方政府颁发的相关环保和水处理行业资质、证书&#xff0c;比如ISO认证、水污染治理资质等&#xff0c;…

Nacos服务注册中心的下载与使用

1. Nacos是什么&#xff1f; https://nacos.io/ 官方&#xff1a;一个更易于构建云原生应用的动态服务发现(Nacos Discovery )、服务配置(Nacos Config)和服务管理平台。 集 注册中心配置中心服务管理 平台 Nacos 的关键特性包括: 服务发现和服务健康监测 动态配置服务 动…

手写一个Spring IOC框架

目录 一&#xff0c;Spring IOC 二&#xff0c;流程图设计 三&#xff0c;设计思路解析 三&#xff0c;开始写代码 1.准备工作: 2.扫描并加载类信息 3.初始化bean 4.测试一下 一&#xff0c;Spring IOC Spring IoC容器是Spring框架的核心&#xff0c;它通过读取配置信息…

【每日刷题】Day20

【每日刷题】Day20 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 面试题 17.04. 消失的数字 - 力扣&#xff08;LeetCode&#xff09; 2. 189. 轮转数组 - 力扣&#…