`
wangxiaohigh
  • 浏览: 1482753 次
文章分类
社区版块
存档分类
最新评论

士兵杀敌(二) n 116

 
阅读更多

我理解的还不太到位,这个似乎是对数组的 分块 求和,利用c数组实现a数组的分块分层求和,复杂度降为log2N

南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的。

小工是南将军手下的军师,南将军经常想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧。

南将军的某次询问之后士兵i可能又杀敌q人,之后南将军再询问的时候,需要考虑到新增的杀敌数。

输入
只有一组测试数据
第一行是两个整数N,M,其中N表示士兵的个数(1<N<1000000),M表示指令的条数。(1<M<100000)
随后的一行是N个整数,ai表示第i号士兵杀敌数目。(0<=ai<=100)
随后的M行每行是一条指令,这条指令包含了一个字符串和两个整数,首先是一个字符串,如果是字符串QUERY则表示南将军进行了查询操作,后面的两个整数m,n,表示查询的起始与终止士兵编号;如果是字符串ADD则后面跟的两个整数I,A(1<=I<=N,1<=A<=100),表示第I个士兵新增杀敌数为A.
输出
对于每次查询,输出一个整数R表示第m号士兵到第n号士兵的总杀敌数,每组输出占一行

样例输入

5 6
1 2 3 4 5
QUERY 1 3
ADD 1 2
QUERY 1 3
ADD 2 3
QUERY 1 2
QUERY 1 5

样例输出

6
8
8
20

问题提出:已知数组a[],元素个数为n,现在更改a中的元素,要求得新的a数组中i到j区间内的和(1<=i<=j<=n).

思考:对于这个问题,我们可以暴力地来解决,从a[i]一直累加到a[j],最坏的情况下复杂度为O(n),对于m次change&querry,合起来的复杂度为O(m*n),在n或m很大的情况下,这样的复杂度是让人无法忍受的.另外,如果没有元素的变更,我们完全可以存储sum[1,k](k=1,2,……),然后对任意给定的查找区间[i,j],都可以方便的用ans=sum[1,j]-sum[1,i-1],当然这只是没有元素改变的情况下的比较优化的解法.那么对于有元素变更的问题是否有更高效的方法呢?(废话!没有我还写啥?!)可以想一下,每次更改的元素是比较少的,有时候甚至每次只改变一个元素,但是在用暴力方法求区间和的时候,却对区间内所有的元素都累加了一遍,这样其实造成了许多无谓的运算.这时候也许会想到如果能把一些结果存起来会不会减少很多运算?答案是肯定的,但问题是怎么存,存什么?如果存任意区间的话,n比较大的时候不但内存吃不消,而且存储的量太大,不易更改,反而得不偿失;那么也许可以考虑存储特定的一些区间(比如说线段树,其实现在讨论的问题用线段树完全可以解,以后再详细写线段树).那么现在重新回过头来,看下这个问题,我们已经确定了要存储一些特定区间sum的想法,接下来我们要解决的无非是两个问题:1、减少更改元素后对这些区间里的sum值的更改时间.2、减少查找的时间.

好了废话了这么半天,无非是想让自己以及看到的人明白为什么要用树状数组.

接下来正式入题.

首先我们可以借鉴元素不变更问题的优化方法,先得到前i-1项之和and前j项之和,以s[i]表示前i项之和,那么sum[i,j]=s[j]-s[i-1].那么现在的问题已经转化为求前i项之和了.另外,我们已经确定要存储一些特定区间的和,现在就要来揭示这些特定的区间究竟指什么.

在文字说明之前先引入一个非常经典的,在网上找到的树状数组文章里几乎都要出现的一个图片


从图中不难发现,c[k]存储的实际上是从k开始向前数k的二进制表示中右边第一个1所代表的数字个元素的和(这么说可能有点拗口,令lowbit为k的二进制表示中右边第一个1所代表的数字,然后c[k]里存的就是从a[k]开始向前数lowbit个元素之和)这么存有什么好处呢?无论是树状数组还是线段树,都用到了分块的思想,而树状数组采用这样的存储结构我想最主要的还是这样方便计算,我们可以用位运算轻松地算出lowbit.分析一下这样做的复杂度:对于更改元素来说,如果第i个元素被修改了,因为我们最终还是要求和,所以可以直接在c数组里面进行相应的更改,如图中的例子,假设更改的元素是a[2],那么它影响到得c数组中的元素只有c[2],c[4],c[8],我们只需一层一层往上修改就可以了,这个过程的最坏的复杂度也不过O(logN);对于查找来说,如查找s[k],只需查找k的二进制表示中1的个数次就能得到最终结果,比如查找s[7],7的二进制表示中有3个1,也就是要查找3次,到底是不是呢,我们来看上图,s[7]=c[7]+c[6]+c[4],可能你还不知道怎么实现这个过程.

还以7为例,二进制为0111,右边第一个1出现在第0位上,也就是说要从a[7]开始向前数1个元素(只有a[7]),即c[7];

然后将这个1舍掉,得到6,二进制表示为0110,右边第一个1出现在第1位上,也就是说要从a[6]开始向前数2个元素(a[6],a[5]),即c[6];

然后舍掉用过的1,得到4,二进制表示为0100,右边第一个1出现在第2位上,也就是说要从a[4]开始向前数4个元素(a[4],a[3],a[2],a[1]),即c[4].

代码实现:

int lowbit(int x)//计算lowbit
{
return x&(-x);
}
void add(int i,int val)//将第i个元素更改为val
{
while(i<=n)
{
c[i]+=val;
i+=lowbit(i);
}
}
int sum(int i)//求前i项和
{
int s=0;
while(i>0)
{
s+=c[i];
i-=lowbit(i);
}
return s;
}


分享到:
评论

相关推荐

    士兵站队如何选择x 和y的值才能使士兵们以最少的总移动步数排成一列。

    在一个划分成网格的操场上,n个士兵散乱地站在网格点上。网格点由整数坐标(x,y)表示。士兵们可以沿网格边上、下、左、右移动一步,但在同一时刻任一网格点上只能有一名士兵。按照军官的命令,士兵们要整齐地列成一个...

    士兵战队问题.cpp

    在一个划分成网格的操场上,n个士兵散乱地站在网格点上。网格点由整数坐标(x,y)表示。士兵们可以沿网格边上、下、左、右移动一步,但在同一时刻任一网格点上只能有一名士兵。按照军官的命令,士兵们要整齐地列成一个...

    acm 士兵站队 c源码

    在一个网格状的操场中,有n个士兵随机分布于各网格点上,每个网格点用一对整数坐标(x, y)表示。士兵可以在网格中向上、下、左右四个方向移动一步。目标是通过移动这些士兵,使得它们最终能够排成一个水平队列,即排...

    经典士兵分子弹问题Java源代码

    这个题目源自军事训练中的一个场景:一排士兵按照命令依次向后射击,每名士兵射杀站在他后面的第n个士兵,直到只剩下一个士兵为止。其中n是题目给定的一个数字。该问题涉及的主要知识点包括数组操作、循环、条件判断...

    马士兵课程源码11111111111111111111

    从提供的文件信息来看,标题和描述均为“马士兵课程源码11111111111111111111”,这意味着我们关注的焦点是与“马士兵”课程相关的源码文件。马士兵是一位在Java编程领域具有广泛影响力的人物,他的课程往往覆盖了...

    计算机算法士兵站队问题

    要解决士兵站队问题,需要观察最终的士兵位置坐标,可以发现最终y轴坐标是同一固定值,而x轴坐标依次减0,1,2,…,(n-1)后所得到的x轴坐标也是同一固定值。因此,可以依据在一组数中,各数距中位数的绝对差之和来...

    最新可用 H5士兵扫雷6.0修复版新增签到稳定流畅源码带教程

    《H5士兵扫雷6.0修复版:稳定流畅与新增签到功能解析》 H5士兵扫雷,作为一款深受玩家喜爱的经典游戏,凭借其简单易懂的...同时,源码的开放性为技术学习和二次开发提供了宝贵的资源,进一步推动了H5游戏生态的发展。

    树状数组详解

    在主函数`main()`中,先读取士兵的数量`m`和指令数量`n`,然后初始化树状数组`c[]`为0,并输入每个士兵的初始杀敌数,用`gb(i, f)`进行更新。接着,对每一条指令,根据指令类型执行查询(计算区间和)或更新(增加...

    数据结构实验 士兵站队问题

    在数据结构领域,"士兵站队问题"是一个典型的算法应用实例,它可以帮助我们理解排序算法的原理和实现。这个问题可以从不同的角度来分析,比如通过排序、优先队列或图论等方法来解决。下面我们将详细探讨这个实验所...

    jvm java虚拟机 调优 马士兵 笔记

    jvm java虚拟机 调优 马士兵 笔记 让你对java虚拟机调优有初步的认识

    开源PHP士兵扫雷6.0带教程带支付接口

    了解这些资源可以帮助快速上手并进行二次开发。 总之,士兵扫雷6.0开源项目涵盖了PHP开发的基本要素,包括Web应用设计、数据库操作、前端技术以及支付接口集成等。对于想要学习PHP开发或者希望了解游戏开发的开发者...

    马士兵oracle笔记

    马士兵oracle笔记,浅显易懂。

    马士兵老师spring框架学习笔记

    马士兵老师是知名的Java教育专家,他的Spring框架学习笔记深入浅出,对于初学者和进阶者来说都是一份宝贵的资源。这份笔记涵盖了Spring的核心概念、配置、AOP(面向切面编程)、DI(依赖注入)等关键知识点。 1. **...

    《将军和士兵》阅读训练题及答案.pdf

    1. **字音字形**:文章中提到了几个词语的读音和汉字,如“打量”的“量”应读“liáng”,“稚嫩”的“嫩”应读“nèn”,“戎马生涯”的“戎”是“róng”,“口吻”的“吻”应读“wěn”。 2. **对话补充**:...

    欧洲士兵游戏模型下载

    本资源"欧洲士兵游戏模型下载"提供了一款士兵的3D模型,对于游戏开发者、设计师或是对游戏制作感兴趣的个人来说,都是一个有价值的参考资料。 首先,我们要理解什么是3D模型。3D模型是通过专业软件(如Blender、...

    马士兵多线程笔记.zip

    马士兵是一名知名的IT讲师,他的多线程训练营致力于帮助学员深入理解和掌握多线程技术。以下是对马士兵多线程笔记的详细解析。 1. **多线程基础**:多线程是指一个应用程序中同时执行多个线程(即任务)的能力。...

    马士兵jvm调优笔记.docx

    #### 二、垃圾收集算法 垃圾收集算法主要用于释放那些不再使用的对象所占用的内存,从而避免内存泄漏问题。主要包括以下几种: - **标记-清除算法**(Mark-Sweep):首先标记所有需要回收的对象,然后统一回收这些...

    unity普通士兵模型资源

    在"unity普通士兵模型资源"这个主题中,我们可以深入探讨Unity中的3D模型资源、游戏对象的创建与管理、动画系统以及资源打包和导入流程。 首先,3D模型资源是Unity游戏中的核心元素之一。士兵模型通常包含多个部分...

    中职语文基础下册士兵突击PPT学习教案.pptx

    第二部分则进一步深化了人物间的友情和相互支持;第三部分则是对个人选择和牺牲的思考,伍六一的无奈弃权和成才与许三多的成功,构成了一种对个人命运的反思;最后一个部分则是对三个人物成长轨迹的回顾,从而引发对...

    马士兵多线程训练营笔记

    马士兵是一位知名的IT教育专家,他的多线程训练营笔记深入浅出地讲解了这一主题,帮助开发者理解并掌握多线程的精髓。 多线程允许一个程序中有多个执行流同时运行,这样可以提高应用程序的效率和响应性。在Java中,...

Global site tag (gtag.js) - Google Analytics