数据结构<1>——树状数组

树状数组,也叫Fenwick Tree和BIT(Binary Indexed Tree),是一种支持单点修改区间查询的,代码量小的数据结构。

那神马是单点修改和区间查询?我们来看一道题。

洛谷P3374(模板): 在本题中,单点修改就是将某一个数加上x的操作,区间查询就是求出某区间每一个数的和的操作,这下明白了吧。

下面来解释一下树状数组的工作原理。先看一张图(来源于OI-Wiki)

Tips:别找了,点一下"图"那个字就有了。

我们发现,树状数组总能将一段前缀拆成不多于log n段区间,使得这几段区间的信息是已知的。因此,我们只用合并这些区间的信息,就可以得到答案。因此,时间复杂度从\Theta (n)变成\Theta (log n),效率大大提高。

管辖区间

我们观察刚刚的图发现,每个c_{i}相当于一个小leader,掌管自己的范围。那这个范围是多少呢?我们规定c_{i}管辖的区间长度为2^{k},其中k为x的二进制表示中,最低位的1所在的二进制位数。而2^{k}为x的二进制表示中,最低位的1以及后面所有0组成的数。即c_{x}管辖的区间是[x-lowbit(x)+1,x]注意:lowbit(x)表示这个1和后面所有0组成的2^{k}

下面附上OI-Wiki中对lowbit(x)的原理的解释(其实是我不会解释)

x 的二进制所有位全部取反,再加 1,就可以得到 -x 的二进制编码。例如, 的二进制编码是 110,全部取反后得到 001,加 1 得到 010

设原先 x 的二进制编码是 (...)10...00,全部取反后得到 [...]01...11,加 1 后得到 [...]10...00,也就是 -x 的二进制编码了。这里 x 二进制表示中第一个 1x 最低位的 1

(...)[...] 中省略号的每一位分别相反,所以 x & -x = (...)10...00 & [...]10...00 = 10...00,得到的结果就是 lowbit

//lowbit的实现
int lowbit(int x){return x&(-x);
}

lowbit可以说是一个很经典的二进制运算了。

区间查询

经过上面的分析,我们可以知道回答区间查询的步骤了:

·c_{x}往前跳,一直让x-lowbit(x)就行了。

· 如果x=0就结束循环

· 将跑到的c_{x}累加

实现如下↓:

int get_sum(int x){int sum=0;while(x>0){sum+=c[x];x-=lowbit(x);}return sum;
}

单点修改

也很简单。

· 先修改c_{x}

· 然后一直让让x+lowbit(x)

· 如果x=n就结束循环

实现如下↓:

void modify(int x,int y){while(x<=n){c[x]+=y;x+=lowbit(x);}
}

洛谷P3374(模板):

那这题就很easy啦~

#include <bits/stdc++.h>
using namespace std;
int c[maxn];
int n,m;
int lowbit(int x){return x&(-x);
}
void modify(int x,int y){while(x<=n){c[x]+=y;x+=lowbit(x);}
}
int get_sum(int x){int res=0;while(x>0){res+=c[x];x-=lowbit(x);}return res;
}
int main(){cin>>n>>m;for(int i=1;i<=n;i++){int x;cin>>x;modify(i,x);}for(int i=1;i<=m;i++){int op,x,y;cin>>op>>x>>y;if(op==1)modify(x,y);if(op==2)cout<<get_sum(y)-get_sum(x-1)<<endl;}return 0;
}

别走啊,这不得在找几题练练?

逆序对:

基础题。现在按照序列从左到右将数据的值对应的位置的数加一,代表又有一个数出现。因此,在循环到第i项时,前i-1项已经加入到树状数组内了,树状数组内比a_{i}大的都会与a_{i}构成逆序对,因为它们一定出现的更早,所以产生的逆序对数量为i-query(a_{i})。要注意的是,我们需要进行离散化,因为根据a_{i}建树确实不够。然后就是代码部分啦。

#include <bits/stdc++.h>
using namespace std;
pair<long long,long long> a[maxn];
long long b[maxn],c[maxn];
int n;
int lowbit(int x){return x&(-x);
}
void modify(int x){while(x<=n){c[x]++;x+=lowbit(x);}
}
int get_sum(int x){int sum=0;while(x>0){sum+=c[x];x-=lowbit(x);}return sum;
}
int main(){cin>>n;for(int i=1;i<=n;i++){cin>>a[i].first;a[i].second=i;}sort(a+1,a+n+1);for(int i=1;i<=n;i++)b[a[i].second]=i;long long ans=0;for(int i=n;i;i--){ans+=get_sum(b[i]);modify(b[i]);}cout<<ans<<endl;return 0;
}

当然,用归并也是Ok的。

火柴排队:

一道非常非常经典的题目。我们乍一看,就是让我们最小化\sum_{i=1}^{n} (a_{i}-b_{i})^{2},也就是最小化a_{i}-b_{i},也就是a序列第k大的元素必须和序列b中第k大的元素的位置必须一样。OK,那我们把a,b离散化,问题变成了b序列要交换几次可以令其等于a。我们令id_{a_{i}}=b_{i},相当于以a_{i}为关键字对序列b_{i}排序,如果a和b一样,那么q_{i}=i。那么我们需要让q升序排列。问题又变成,将原本乱的 q序列升序排列的最少交换次数。

诶,这不就是逆序对吗?

用树状数组或归并即可。这里给归并的代码,树状数组的参考上面P1908的代码。

#include <bits/stdc++.h>
using namespace std;
int a[maxn],b[maxn];
int c[maxn],d[maxn];
int num1[maxn],num2[maxn];
int calc[maxn];
long long ans=0;
int tmp[maxn];
void msort(int l,int r){if(l==r)return;int mid=(l+r)>>1;msort(l,mid);msort(mid+1,r);int i=l,j=mid+1;int k=l;while(i<=mid && j<=r){if(a[i]<=a[j])tmp[k++]=a[i++];else{tmp[k++]=a[j++];ans+=mid-i+1;ans%=MOD;}}while(i<=mid)tmp[k++]=a[i++];while(j<=r)tmp[k++]=a[j++];for(int i=l;i<=r;i++)a[i]=tmp[i];
}
int main(){int n;cin>>n;for(int i=1;i<=n;i++){cin>>a[i];c[i]=a[i];}for(int i=1;i<=n;i++){cin>>b[i];d[i]=b[i];}sort(d+1,d+n+1);for(int i=1;i<=n;i++)num1[d[i]]=i;sort(c+1,c+n+1);for(int i=1;i<=n;i++)num2[c[i]]=i;for(int i=1;i<=n;i++)calc[num1[b[i]]]=i;for(int i=1;i<=n;i++)a[i]=calc[num2[a[i]]];msort(1,n);cout<<ans%MOD<<endl;return 0;
}

别忘了取模哦。

The Last Problem:ABC157E

此题一看就是树状数组。但是由于有26个字母,我们要建26个树状数组,每一个存放该字母出现的位置。这样,在询问的时候,直接查询每一个树状数组的[l,r]的和,如果这个和>0,那么就把 ans加1,最后输出即可。

#include <bits/stdc++.h>
using namespace std;
int c[26][500005];
int lowbit(int x){return x&(-x);
}
void update(int c[],int x,int val){while(x<=500000){c[x]+=val;x+=lowbit(x);}
}
int getsum(int c[],int x){int sum=0;while(x>0){sum+=c[x];x-=lowbit(x);}return sum;
}
int main(){int n;cin>>n;string str;cin>>str;str=' '+str;for(int i=1;i<=n;i++)update(c[str[i]-'a'],i,1);int q;cin>>q;while(q--){int op;cin>>op;if(op==1){int x;char ch;cin>>x>>ch;update(c[str[x]-'a'],x,-1);update(c[ch-'a'],x,1);str[x]=ch;}if(op==2){int l,r;cin>>l>>r;int ans=0;for(int i=0;i<26;i++){if(getsum(c[i],r)-getsum(c[i],l-1))ans++;}cout<<ans<<endl;}}return 0;
}

Ok,以上就是本期的全部内容了。我们下期再见!

温馨提示:本期的所有代码都有问题,请不要无脑Ctrl C+Ctrl V(你会挂的很惨),看懂了自己写一遍

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

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

相关文章

有哪些简单好用、适合中小型企业的CRM系统?

阅读本文&#xff0c;你将了解&#xff1a;一、中小型企业对CRM系统的主要需求&#xff1b;二、盘点四款好用的CRM系统&#xff1b;三、CRM系统实施策略和优秀实践。 在快速变化的商业环境中&#xff0c;中小型企业面临着独特的挑战&#xff1a;如何在有限的资源下高效地管理客…

web安全思维导图(白帽子)

web安全思维导图(白帽子) 客户端脚本安全 服务端应用安全 白帽子讲web安全 安全运营体系建设

2、Line Charts折线图

可视化时间趋势 现在你已经熟悉了编码环境,是时候学习如何制作自己的图表了! 在本教程中,您将学习足够的Python来创建专业外观的折线图。然后,在接下来的练习中,您将使用您的最新技能处理真实世界的数据集。 本课程数据集夸克网盘下载链接:https://pan.quark.cn/s/a235ac…

数据管理平台Splunk Enterprise本地部署并结合内网穿透实现远程访问

文章目录 前言1. 搭建Splunk Enterprise2. windows 安装 cpolar3. 创建Splunk Enterprise公网访问地址4. 远程访问Splunk Enterprise服务5. 固定远程地址 前言 本文主要介绍如何简单几步&#xff0c;结合cpolar内网穿透工具实现随时随地在任意浏览器&#xff0c;远程访问在本地…

智能控制箱解决方案

一、建设背景 在数字时代的浪潮中&#xff0c;智能化的管理和操作已经成为各行业的共同追求。唯众物联网智能控制箱&#xff0c;是一款功能性强、使用安装简单的智能网络传输、温湿度监测、门锁控制综合系统。系统由I/O网络模块、传感器、管理后端、移动端APP组成&#xff0c;辅…

TArry TMap TSet

一.TArry 1. TArray<int32> MyArray; 增加 删除 改 查 2.TMap<int32, int32>MyMap; //TMap是一种键值对容器&#xff0c;里面的数据都是成对出现的(Key&#xff0c;Value),Value通过Key值来获取&#xff0c;且Key值不能重复&#xff0c;key值唯一。 增&#x…

idea——git提交到本地记录如何退回/删除

目录 一、git提交到本地记录如何退回/删除 一、git提交到本地记录如何退回/删除 git提交到本地记录&#xff0c;如下图【更新】记录&#xff0c;表示本次提交到git本地需要退回/删除的操作&#xff1a; 选中项目&#xff0c;右键点击【git】——>【Show History】——>…

基于SSM的影视创作论坛(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的影视创作论坛&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

21.云原生之GitLab pipline语法(CI基础)

云原生专栏大纲 文章目录 gitlab-ci.yml 介绍GitLab中语法检测gitlab-ci.yml 语法job定义作业before_script和after_scriptstages定义阶段tages指定runnerallow_failure运行失败when控制作业运行retry重试timeout超时parallel并行作业only & exceptrulescache 缓存cache:p…

PolarDB 再升级:欢迎来到云数据库 x AI新时代

大模型时代&#xff0c;数据库的变化走到了哪&#xff1f; 作者|思杭 编辑|皮爷 出品|产业家 “搭积木”、“‘自动驾驶’”、“三层解耦”&#xff0c;这些形象的标签成了1月17日阿里云开发者生态大会当天最出圈的词汇。 会上&#xff0c;一名小学生受邀上台演示了数据…

3.jmeter接口关联及实战

1.当所传参数包含键值对和json文件时&#xff0c;键值对放在链接后&#xff0c;参数放在消息体数据中 2.当查看结果树返回乱码时&#xff0c;修改请求中内容编码为utf-8 一、jmeter接口关联 1.正则表达式提取器 接口2.3传递的参数中需要用到接口1的返回值 禁用接口2.3&#…

Elasticsearch:Simulate ingest API

Ingest pipeline 为我们摄入数据提供了极大的方便。在我之前的文章中&#xff0c;有非常多的有关 ingest pipeline 的文章。请详细阅读文章 “Elastic&#xff1a;开发者上手指南”。针对一组提供的文档执行摄取管道&#xff0c;可以选择使用替代管道定义。 Simulate ingest AP…

基于关系型数据库的知识图谱存储探析

目录 前言1 图结构数据的关系存储1.1 Wikidata与MySQL的结合1.2 关系型数据库的优势与挑战 2 选择数据库需要考虑的三个问题2.1 存储的物理结构2.2 存储的性能问题2.3 图的查询问题 3. 不同的存储方式3.1 Triple Store3.2 属性表存储3.3 二元表3.4 全索引结构 结语 前言 在当今…

前端动画特效分享(附效果图及在线演示)

分享7款有趣也实用的前端动画特效 其中有CSS动画、canvas动画、js小游戏等等 下方效果图可能不是特别的生动 那么你可以点击在线预览进行查看相应的动画特效 同时也是可以下载该资源的 SVG天气图标动画特效 SVG天气图标动画特效 不管是晴天雨天等都很完美的展示出了各自真实的…

新版idea创建spring boot项目

目录 前言 汉化教程 项目模板初始化 1.点击新建项目 2.配置初始化信息 3.初始依赖选择 配置Maven 1.打开maven设置 2.重写maven配置文件 3.选择你创建的配置文件 4.重启项目 spring boot配置并测试 1.修改配置文件后缀 2.启动项目 3.编写测试控制类 4.重启项目…

创建.gitignore,忽视不必要提交的文件

在项目主目录下创建.gitignore文件 touch .gitignore在.gitignore文件内输入要忽略的文件即可。 e.g. build/.gitignore文件不生效问题 上传后并没有不在build目录内产生文件 该文件只能作用于Untracked Files&#xff0c;也就是那些从来没有被git记录过的文件。 解决方法…

springboot druid数据库配置密码加密

1.使用的druid版本 <!-- 阿里数据库连接池 --> <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId><version>1.2.21</version> </dependency> 2.配置文件 # Spring配置 …

141:vue+leaflet 利用高德逆地理编码,点击地图标记marker,popup地址信息

第141个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中利用高德逆地理编码,点击地图标记marker,popup地址信息 。主要利用高德地图的api将坐标转化为地址,然后在点击的位置,弹出弹窗,在里面显示出地址信息。 直接复制下面的 vue+leaflet源代码,操作2分钟…

性能优化(CPU优化技术)-NEON 介绍

「发表于知乎专栏《移动端算法优化》」 本节主要介绍基本 SIMD 及其他的指令流与数据流的处理方式&#xff0c;NEON 的基本原理、指令以及与其他平台及硬件的对比。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;…

Unity之Timeline教程

前言 Unity Timeline是Unity的一种时间轴编辑器工具&#xff0c;用于制作和管理游戏中的动画、剧情以及事件触发。它提供了直观的界面&#xff0c;使得开发者可以通过拖放操作轻松创建和编辑时间轴。 Timeline的使用 创建新的Timeline 在Unity中&#xff0c;选择菜单栏的 Wi…