树状数组 (三种模型)

[树状数组] 区间求和的三种模型 树状数组在区间求和问题上有很高的效率,尤其在非常困难的比赛中(数据量大,对时间限制很严格的比赛)能发挥非常大的作用,其各种复杂度都要比线段树低很多,而且其代码简洁优美……有关区间求和,主要有以下三个模型: (以下设a[1…n]为一个长为n的序列,初始值全为0)1、改点求段型:即对于序列A有以下操作: 求整段区间的和:给定i,计算a1+a2+…+ai 修改单点:给定x和c,执行ax += c 这是最 阅读详情

感谢大佬的讲解:https://blog.youkuaiyun.com/sinat_37668729/article/details/77387668                        

 

1.改变某一元素的值,查询某一区间内所有元素的和(单点更新,区间查询)。

2.把一个区间内的所有元素都加上一个值,查询某一个元素的值(区间更新,单点查询)。

3.把某一个区间内的所有元素都加上一个值,查询某一区间内所有元素的和(区间更新,区间查询)。

第三种操作是转载RoBa大牛的,具体还得深入理解,现在暂当模板。虽然前面说是“区间更新”,或者“区间查询”,但实际上并不能做到像线段树那样完美,有着很大的局限性。

模式1:

#define Lowbit(p) (p&(-(p)))
//1.改变某一元素的值,查询某一区间内所有元素的和(单点更新,区间查询)。
//向上更新,向下求和
void Update(int *BIT,int p,int val)
{
    while ( p<=N )
    {
        BIT[p] += val;
        p += Lowbit(p);
    }
}

int GetSum(int *BIT,int p)
{
    int ret=0;
    while ( p>0 )
    {
        ret += BIT[p];
        p -= Lowbit(p);
    }
    return ret;
}

//向下更新,向上求和
void Update(int *BIT,int p,int val)
{
    while ( p>0 )
    {
        BIT[p] += val;
        p -= Lowbit(p);
    }
}

int GetSum(int *BIT,int p)
{
    int ret=0;
    while ( p<=N )
    {
        ret += BIT[p];
        p += Lowbit(p);
    }
    return ret;
}


模式2:  

把一个区间内的所有元素都加上一个值,查询某一个元素的值(区间更新,单点查询)。描述给定一个初始值都为0的序列,动态地修改一段连续位置上的数字,加上一个数,减去一个数,然后动态地提出问题,问题的形式是求出一个位置的数字。
输入
输入数据第一行包含2个整数N,M(1≤N,M≤100000),表示序列的长度和操作的次数。
接下来M行,每行会出现如下的一种格式:
* Add i j x ——将序列中第i个数到第j个数加上x
* Query i ——求出序列中第i个数
输出
对于每一个Query操作输出一个数,表示序列中第i个数。
分析:
我们把支持这种操作的树状数组称为树状数组的模式二,在这种模式下,a[i]已经不再表示真实的值了,只不过是一个没有意义的、用来辅助的数组。这时我们真正需要的是另一个假想的数组b[],b[i] 才表示真实的元素值。此时Sum(i)虽然也是求a[i]之前的元素和,但它现在表示的是实际我要的值,也就是 b[i]

注意,这里只是对a[i]进行了加一,i+1到j的值是没变的,所以求得和即为某点的值)

比如现在我要对图1 中a[]数组中红色区域的值全部1。当然你可以用模式一的 Update(i)对该区间内的每一个元素都修改一次,但如果这个区间很大,那么每次修改的复杂度就都是O(NlogN),m次修改就是O(MNlbN),这在M和N很大的时候仍是不满足要求的。这时模式二便派上了用场。我只要将该区域的第一个元素+1,最后一个元素的下一位置-1,对每个位置GetSum(i)以后的值见下图:

 


相信大家已经看得很清楚了,数组b[]正是我们想要的结果。模式二难理解主要在于 a[]数组的意义。这时请不要再管a[i]表示什么,a[i]已经没有意义了,我们需要的是b[i]!但模式二同样存在一个缺陷,如果要对某个区间内的元素求和,复杂度就变成O(NlogN)了。所以要分清两种模式的优缺点,根据题目的条件选择合适的模式,灵活应变!

 

//[l,r]中每个元素加上val
void _Update(int *BIT,int l,int r,int val)
{
    //调用的是模式一中的向上更新
    Update(BIT,l,val);
    Update(BIT,r+1,-val);
}

//询问p位置的数
int Querry(int BIT,int p)
{
    //调用的是模式一中的向下求和
    return GetSum(BIT,p);
}

 

模式3:

把某一个区间内的所有元素都加上一个值,查询某一区间内所有元素的和(区间更新,区间查询)。
简单的树状数组模型是不支持这样一组操作的:(1)把某一个区间内所有元素都加上一个值 (2)查询某一个区间内所有元素的和。当然,这个东西可以用线段树完成,但是线段树占内存比较大,写起来也比较繁(对我这种不会数据结构的人而言)。下面我们用一个改进版的树状数组完成这个任务。
首先一个观察是区间操作总可以变成从最左端开始,比如把区间[3..6]都加10,可以变成[1..6]加10, [1..2]减10。查询也类似。于是下面只关心从最左端开始的情况。定义Insert(p, d)表示把区间[1..p]都加d,Query(p)表示查询区间[1..p]之和。
我们考虑调用一次Insert(p, d)对以后的某次查询Query(q)的影响:
(1) 如果p<=q,总的结果会加上p*d (2) 如果p>q,总的结果会加上q*d
也就是说,Query(q)的结果来源可分为两部分,一部分是Insert(p1,d) (p1<=q),一部分是Insert(p2,d) (p2 > q)。我们用两个数组B[], C[]分别维护这两部分信息,B[i]表示区间右端点恰好是i的所有区间的影响之和,C[i]表示区间右端点大于i的所有区间的影响之和。每当遇到 Insert时,考虑当前的Insert会对以后的Query产生什么影响,更新B和C数组;当遇到Query时,把两部分的结果累加起来。
具体来说,当我们遇到Insert(p, d)时,把B[p]增加p*d,把C[1], C[2], …, C[p-1]都增加d。当遇到Query(p)时,查询B[1]+B[2]+…+B[p]+C[p]*p即可。可以发现对B数组是修改单个元素,查询区间和;对C数组是修改区间,查询单个元素,这恰好对应于一开始说的树状数组支持的基本操作。于是我们用两个树状数组漂亮地完成了任务。
 

#include <cstdio>
const int MAXN = 1024;
int B[MAXN], C[MAXN];
#define LOWBIT(x) ((x)&(-(x)))
void bit_update(int *a, int p, int d)
{
    for ( ; p && p < MAXN ; p += LOWBIT(p))
        a[p] += d;
}

int bit_query(int *a, int p)
{
    int s = 0;
    for ( ; p ; p -= LOWBIT(p))
        s += a[p];
    return s;
}

void bit_update2(int *a, int p, int d)
{
    for ( ; p ; p -= LOWBIT(p))
        a[p] += d;
}

int bit_query2(int *a, int p)
{
    int s = 0;
    for ( ; p && p < MAXN ; p += LOWBIT(p))
        s += a[p];
    return s;
}

inline void _insert(int p, int d)
{
    bit_update(B, p, p*d);
    bit_update2(C, p-1, d);
}

inline int _query(int p)
{
    return bit_query(B, p) + bit_query2(C, p) * p;
}

inline void insert_seg(int a, int b, int d)
{
    _insert(a-1, -d);
    _insert(b, d);
}

inline int query_seg(int a, int b)
{
    return _query(b) - _query(a-1);
}

int main()
{
    int com, a, b, c;
    while (scanf("%d%d%d",&com,&a,&b) != EOF)
    {
        a += 2;
        b += 2; //防止出现负数
        if (com == 0)   //更新
        {
            scanf("%d",&c);
            insert_seg(a, b, c);
        }
        else     //查询
        {
            printf("%d\n",query_seg(a,b));
        }
    }
    return 0;
}

 

【ComfyUI】Flux 图像扩展 本文介绍了一个基于Flux扩图技术的ComfyUI工作流,能够智能扩展图像尺寸并保持内容连贯性。该流程通过扩散模型与条件编码的结合,对图像边缘进行语义填充生成,适用于艺术创作、海报设计等场景。工作流包含图像加载、外扩填充、文本编码、扩散采样等核心节点,采用Flux1-fill-dev等专业模型确保生成质量。演示效果显示,系统能自然延伸原图内容,保持风格统一。该技术可广泛应用于插画扩展、摄影增强、游戏场景构建等领域,显著提升创意工作效率。 阅读详情

相关推荐

【OpenCV】背景替换(opencv、python),照片、证件照的背景替换(抠图)

目录步骤:导入库1、读入将要抠图的图片2、create一个带颜色域的mask3、通过mask使得原图只显示汽车,即抠出所需要的部分4、将要替换掉的图像resize或裁剪到和上述图片一样的大小5、将该图片预留出将要重叠上的部分,即将mask部分改为(0,0,0)6、通过和运算使得两部分图片mask部分替换7、最后保存图片 步骤: 导入库 import matplotlib.pyplot as plt import matplotlib.image as mpimg import numpy as np imp

weixin_41729258的博客 4362

树状数组入门(快速求和问题)

树状数组 解决求和问题 树状数组是一种数据结构主要解决快速求和的问题,其次他还可以快速的查找最大值,但是查找最大值还是推荐使用线段树来做,相比之下树状数组更节省空间。 有时候觉得树状数组难以理解,我觉得根本原因是:你还在用十进制的视角来看待树状数组,下面的讲解我会时刻提醒你转换到二进制的视角。 lowbit()函数:顾名思义,lowbit这个函数的功能就是求某一个数的二进制表示中最低的一...

weixin_40488730的博客 971

YOLOv8中间特征层可视化

在通过观察这些特征,可以清楚地看到模型如何逐步将输入图像转化为有意义的表示。

weixin_45314480的博客 6890

树状数组求和三种模型

1.改变某一元素的值,查询某一区间内所有元素的和(单点更新,区间查询)。 2.把一个区间内的所有元素都加上一个值,查询某一个元素的值(区间更新,单点查询)。 3.把某一个区间内的所有元素都加上一个值,查询某一区间内所有元素的和(区间更新,区间查询)。 第三种操作是转载RoBa大牛的,具体还得深入理解,现在暂当模板。虽然前面说是“区间更新”,或者“区间查询”,但实际上并不能做到像线段树那样完美

sdau20163940的博客 803

不写代码,Cursor 10分钟开发1个APP!保姆级教程喂饭来了

做出第一个能运行的app,那种成就感真的很棒。虽然过程可能有点折腾,但只要耐心一点,问题都能解决。记住,遇到问题不要慌,现在有AI帮忙,大部分问题都能快速解决。重要的是迈出第一步,开始动手实践。你的第一个app可能很简单,但这是一个很好的开始。随着经验积累,你能做出的东西会越来越酷。现在就开始行动吧,说不定下个月你就能向朋友炫耀你自己做的app了!

chenhong007的博客 1551

Ubuntu 24.04 + RTX 5090 部署 OpenVLA-OFT:从环境配置到机器人任务评估实战

本文详细记录了在Ubuntu 24.04 LTS系统上,为全新RTX 5090显卡配置CUDA 12.8+与PyTorch 2.7.1+开发环境,并成功部署OpenVLA-OFT视觉语言模型进行机器人任务评估的完整实战流程。文章重点解决了驱动安装、依赖版本冲突、路径设置等核心难题,为在最新硬件上运行先进AI机器人模型提供了可靠的避坑指南和性能观察。

n8m7b6v5c4的博客 595

Java 树结构的构造及树中数据自下向上的汇总(递归和非递归实现)

Java 树结构的构造以及对树结构中的数据进行自下向上的汇总, 提供了递归和非递归两种实现方式供大家参考.

Waruler的博客 5606

AutoLisp文件(.lsp)从编写到加载运行:一份给CAD新手的避坑指南

本文为CAD新手提供了一份AutoLisp文件(.lsp)从编写到加载运行的完整指南,涵盖编写环境配置、文件加载流程、调试技巧及工程化实践建议。通过详细的步骤和常见错误解决方案,帮助用户避免常见陷阱,提升AutoLisp脚本的开发效率和应用效果。

weixin_29228203的博客 896

树状数组及求和

1.概念 给定一个n个数字的数列,要求一下操作: ①改变第k个数字,增加或减少一个值; ②查询第i个到第j个数的和 一般数组解法: O(1) O(n); 树状数组 O(logn) O(logn); 2.构建 假设给定数列A[1]->A[8] 序列C[]为树状数组 特点: (1)满二叉树,且二叉树中的每个叶子节点为A[]的一个元素 (2) C[i]为A[i]对应的那一列的最高的节点 找出规律: i的二进制中从右到左连续0为x,则C[i...

qq_51758329的博客 439

【DaVinci Developer专题】-36-创建一个“既读又写”的Sender Receiver Port(SR PR-Port)

有时会遇到SWC需要对一个Port进行“既可以读,也可以写”的操作。以下图为例,Test_A_SWC中Test_A_Port是P-Port;Test_B_SWC中Test_A_Port是R-Port。Test_C_SWC需要对Test_A_Port同时进行“读”和“写”。 该篇将详细介绍PR-Port的创建方法。 目录 1 创建一个S/R Port Interface 2 将一个PR-Port端口添加至Application Component 3 PR-Port端口初始化 4 Run.

「汽车电子助手」的博客 3013

从0到1:用Claude 3.7十日拿下教育部课题申报书(附可修改LaTeX模板)

🟣"作为教育部人文社科项目评审专家,请根据近三年立项数据分析,为[您的学科方向]领域推荐5个具有创新性且符合'十四五'规划的重点选题,要求选题体现交叉学科特征,并标注潜在理论突破点"🟣"根据前期研究基础,创建包含4个研究模块、12个关键节点的三维技术路线图,要求体现实验仿真-实证研究-理论建模的螺旋递进关系,并标注每个节点的预期成果形态"🟣"现在切换至教育部学科评审组组长模式,从选题价值、创新程度、研究可行性三个维度对本申报书进行盲审,生成包含9个扣分风险点的诊断报告及修改优先级排序"

智能AI让学术科研更容易 545

树状数组-------求数组和

 据图可知:c1=a1,c2=a1+a2,c3=a3,c4=a1+a2+a3+a4,c5=a5,c6=a5+a6,c7=a7,c8=a1+a2+a3+a4+a5+a6+a7+a8,c9=a9,c10=a9+a10,c11=a11........c16=a1+a2+a3+a4+a5+.......+a16。  分析上面的几组式子可知,当 i 为奇数时,ci=ai ;当 i 为偶数时,就要看 i 的因...

bxg1065283526的博客 270

实战干货|.NET9 C#上位机:多PLC并发通信+数据防丢+指令精准下发(10台设备实测+踩坑实录)

摘要:本文介绍了一个基于.NET9重构汽车零部件产线10台西门子S7-1200 PLC并发通信的工业级解决方案。针对原有系统存在的同步轮询阻塞、数据丢失、指令重复等问题,采用连接池复用、异步并发控制、超时隔离等技术,实现800ms内完成10台PLC并发采集、零丢包率、100%指令精准下发。方案通过.NET9的ThreadPool调度优化和ValueTask内存管理,将CPU占用控制在15%以内,解决了多PLC通信中的并发冲突、超时扩散等核心痛点,并提供了可直接复用的工业级代码实现。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 453

树状数组区间求和三种模型

树状数组在区间求和问题上有大用,其三种复杂度都比线段树要低很多……有关区间求和的问题主要有以下三个模型(以下设A[1..N]为一个长为N的序列,初始值为全0): (1)“改点求段”型,即对于序列A有以下操作: 【1】修改操作:将A[x]的值加上c; 【2】求

mr_lee 8386

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

树状数组三种模型

树状数组在区间求和问题上有大用,其三种复杂度都比线段树要低很多……有关区间求和的问题主要有以下三个模型(以下设A[1..N]为一个长为N的序列,初始值为全0): (1)“改点求段”型,即对于序列A有以下操作: 【1】修改操作:将A[x]的值加上c; 【2】求和操作:求此时A[l..r]的和。 这是最容易的模型,不需要任何辅助数组。树状数组中从x开始不断减lowbit(x)(即x&amp...

weixin_34032621的博客 69

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

树状数组区间求和的三种模型

树状数组在区间求和问题上有大用,其三种复杂度都比线段树要低很多……有关区间求和的问题主要有以下三个模型(以下设A[1..N]为一个长为N的序列,初始值为全0): (1)“改点求段”型,即对于序列A有以下操作: 【1】修改操作:将A[x]的值加上c; 【2】求和操作:求此时A[l..r]的和。 这是最容易的模型,不需要任何辅助数组。树状数组中从x开始不断减lowbit(x

u010621873的专栏 545

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

详解树状数组三种模型

首先说明下:最后的最大值模型的代码没有测试,不过应该是没问题的。其它三个更新求和的模型的代码借鉴于网上的各个博文,应该是没问题的。其中前两个模型的代码已测试无误。 树状数组与线段树在思想上很类似的一种数据结构,它比线段树更简洁,但它的适用范围也小了些。 提供一篇博文,详解树状数组的:http://www.hawstein.com/posts/binary-indexed-trees.html

一蓑烟雨任平生 1878

树状数组区间求和三种模型 [转]

原帖地址:http://blog.youkuaiyun.com/q573290534/article/details/6664454 树状数组在区间求和问题上有大用,其三种复杂度都比线段树要低很多……有关区间求和的问题主要有以下三个模型(以下设A[1..N]为一个长为N的序列,初始值为全0):(1)“改点求段”型,即对于序列A有以下操作:【1】修改操作:将A[x]的值加上c;【2】求和操作:求此时A[l..

DGY01的博客 423

(转载) 树状数组区间求和三种模型

树状数组在区间求和问题上有大用,其三种复杂度都比线段树要低很多……有关区间求和的问题主要有以下三个模型(以下设A[1..N]为一个长为N的序列,初始值为全0): (1)“改点求段”型,即对于序列A有以下操作: 【1】修改操作:将A[x]的值加上c; 【2】求和操作:求此时A[l..r]的和。 这是最容易的模型,不需要任何辅助数组。树状数组中从x开始不断减lowbit(x)(即...

weixin_30268071的博客 82

【转】树状数组求区间和的一些常见模型

这一篇树状数组总结的非常全面。。。 树状数组求区间和的一些常见模型 Posted on 2011-03-19 19:53 Mato_No1 阅读(925) 评论(1)  编辑 收藏 引用 所属分类: 树状数组  树状数组在区间求和问题上有大用,其三种复杂度都比线段树要低很多……有关区间求和的问题主要有以下三个模型(以下设A[1..N]为一个长为N的序列,初始值为全0): (

码代码的猿猿 1089

二分查找突破上下限,树状数组的三种应用。

result=lower_bound(nums.begin(),nums.end(),new_val); result=upper_bound(nums.begin(),nums.

码码要洗手 770

树状数组

定义 树状数组(Binary Indexed Tree(BIT), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和(维护前缀和), 但是每次只能修改一个元素的值。 逻辑结构上是一棵树,但实际上只是个数组。 树状数组和线段树:树状

slime_kirito的专栏 421
上一篇: Minimum Sum of Array
下一篇: hdu1698 Just a Hook
codertcm
博客等级 码龄8年 80粉丝 98原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值