数据结构——树状数组

news/2024/9/20 0:01:22

前言:

树状数组,利用二进制乱七八糟的东西的数据结构。

trick:

修改,查询:

​ 区间修改和单点修改分开来说,区间修改相当于树状数组维护的是一个差分数组,区间修改对应的单点查询,单点修改对应的区间查询,前者是维护差分数组,后者维护的是原本的数组,这次不过多赘述,因为如果树状数组是以下标进行维护的话,那本人更习惯使用线段树。大多数还是权值树状数组用的更多一些。

查询第k大(小)值:

​ (来自https://www.cnblogs.com/LiuRunky/p/BIT_Find_kth.html)

如图所示,由于树状数组的特性,最高位的1所在的位置会存储到所有数字的个数。所以我们可以像倍增那样,i从大往小,设当前位置是x,则如果F[x+i]<k,那么就进行下去。进行下去的话,x+=i。接着继续。

int find(int k){int x=0,sum=0;if(qry(0,n)<k || k<=0) return -114514;for(int i=1<<std::__lg(n);i;i/=2){//这里是小于而没有等于号是因为我们要找到最右边小于k的数然后再+1才是我们要的答案,但是又因为这里树状数组整体下标+1了已经(因为这样可以解决下标0)所以直接return x。if(x+i<=n and sum+F[x+i]<k){sum+=F[x+i];x+=i;}}return x;}

二维查询k大:

倘若我们有一个矩阵,要查询这个矩阵横坐标在l,r之间的k大数该怎么办呢?我们可以用到二维树状数组。

直接贴代码先:

int suan(int x,int i){int sum=0;for(int q=x;q>=1;q-=fan(q)) sum+=F[q][i];return sum;
}
int find(int l,int r,int k){l+=1,r+=1;int y=0,sum=0;for(int i=1<<std::__lg(m);i;i/=2){int tem=suan(r,y+i)-suan(l-1,y+i);if(y+i<=m and sum + tem < k){sum+=tem;y+=i;}}return y;
}

用举例去说明,我们知道最高位的1所在的位置会存储到所有数字的个数。但是二维的怎么做呢?我们总不能直接用\(F[r][i]-F[l-1][i]\),因为我们需要表示前r行里前i个的数,第二维是能够直接代表第r行的所有数字,但是第一维的r因为lowbit不是0,所以我们不能直接使用,需要qry,所以我们要用suan()函数处理出来,对r进行qry,l也是同理。

模板:

一维树状数组:

class tree {vector<int> F;int n;int fan(int x) { return x & -x; }int get(int x) {x += 1; int tem = 0; for (int i = x; i >= 1; i -= fan(i)) tem += F[i];return tem;}
public:void init(int n_) {vector<int>().swap(F);n=n_+1;F.resize(n + 5);}void add(int x, int val) {x += 1; for (int i = x; i <=n; i += fan(i)) F[i] += val;}int qry(int l, int r) {if (l > r) return 0; if (l - 1 < 0) return get(r);return get(r) - get(l - 1);}int find(int k){int x=0,sum=0;if(qry(0,n)<k || k<=0) return -114514;for(int i=1<<std::__lg(n);i;i/=2){if(x+i<=n and sum+F[x+i]<k){sum+=F[x+i];x+=i;}}return x;}
}shu;

二维树状数组:

class tree {vector<vector<int> > F;int n,m;int fan(int x) { return x & -x; }int get(int x,int y){x+=1,y+=1;int tem=0;for(int i=x;i>=1;i-=fan(i))for(int j=y;j>=1;j-=fan(j)){tem+=F[i][j];}return tem;}
public:void init(int n_,int m_) {n=n_+1,m=m_+1;F.reserve(n+10);rep(i,1,n) F[i].assign(m+10,0);}void add(int x,int y, int val) {x+=1,y+=1;for(int i=x;i<=n;i+=fan(i)){for(int j=y;j<=m;j+=fan(j)){F[i][j]+=val;}}}int qry(int x1, int y1,int x2,int y2) {return get(x2,y2)-get(x1-1,y2)-get(x2,y1-1)+get(x1-1,y1-1);}
}shu;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

白云龙期货投资-第四讲

趋势线波浪理论总结: 1.一般行情完成一次阶段性的上涨或者下跌都会通过三波来完成; 2.这三波上涨和下跌的时间空间,经常同等 3.可以利用波浪理论以上两个特性来判断和预测,还会有几次的上涨或者下跌行情,以及每次大概运行的时间及空间 三种常用实用突破法 1.早盘30mins突破…

中秋 -2024/9/16

今天是中秋假期的第二天,已经过了2/3了,怎么俺滴中秋这么快就没了 今天学习了SQL语句种的查询聚合函数进行查询和Java种的集合 TreeSet,HashSet,LinkedHashSet DQL-聚合函数介绍:将一列数据作为一个整体,进行纵向计算 常见聚合函数count - 统计数量 max - 最大值 min - 最小值 …

李尚杰的第一次作业

这次作业属于哪个课程 https://edu.cnblogs.com/campus/zjlg/rjjc这个作业的目标 熟悉博客的建立,向老师/助教介绍自己并阐述对课程的期待姓名-学号 李尚杰-2022329301146一、个人简介 (一)基本介绍我叫李尚杰,来自22自动化1班,浙江杭州人。我爱好摄影、旅游、看电影、健身…

数木莫系且的旭酱买水问题

dut开区用,在别的情况下该博客无效数木莫系且的旭酱买水问题 创中的招新又双叒叕开始了,“数木莫系且”要开始出招新题了,“数木莫系且”的36位老东西为了想招新题整天废寝忘食、绞尽脑汁、抓耳挠腮、呕心沥血,甚至连水都忘记喝了。“数木莫系且“的不时用日语小声发癫的旭…

字符编码发展史1 — ASCII和EASCII

1. 字符集与字符编码1.1. 字符集 1.2. 字符编码 1.3. 两者的关系2. 字符编码的发展历史2.1. 第一个阶段 ASCII编码2.1.1. ASCII 2.1.2. EASCII1. 字符集与字符编码 1.1. 字符集 字符集(Charcater Set或Charset): 是一个系统支持的所有抽象字符的集合,也就是一系列字符的集合…

[JVM]对象创建过程

Java 对象的创建过程 Java对象创建的过程主要分为五个步骤,下面我将详细介绍这五个步骤。 Step1:类加载检查 虚拟机遇到一条new指令时,首先会去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且会检查这个符号引用所指向的类是否已经完成加载、连接和初始化,…

教小模型进行推理

https://arxiv.org/abs/2212.08410 思维链提示在基础层面上是如此成功,以至于它产生了一些被称为 x 链现象的东西。谷歌研究院探索了如何使用 llm 为现有数据集生成 CoT 数据本体,然后如何在 CoT 上微调较小的语言模型。 介绍 众所周知,思维链提示提高了大型语言模型的推理能…