树状数组初步理解

学习树状数组已经两周了,之前偷懒一直没有写,赶紧补上防止自己忘记(虽然好像已经忘得差不多了)。
作为一种经常处理区间问题的数据结构,它和线段树、分块一样,核心就是将区间分成许多个小区间然后通过对大区间的调用来提升效率。因此,我们主要需要了解的就是这种分块方式。
不同于线段树直接将区间不断的进行二分,我们将区间二分的同时将父节点直接放在右区间上,从而形成了一个占用空间很小的树。
在这里插入图片描述
我们仔细观察这张图:根据我们刚才的思想,每个右节点都储存着左右两个子区间的和,即右节点本身就是自己的父节点,而右节点的父节点就是父节点的父节点。想象一下,原本是一个立体的二叉树,我们现在将它向右压,硬生生将一个二维的树压成了一个数组,就得到——树状数组!!!
虽然占用空间大大减小,但是对结点的访问现在变成了一个问题,我们应该怎么访问父亲结点和子节点呢?
仔细观察,我们发现结点n是x个结点的祖先,这个x就是n的二进制的不为零的最小位(不要问我为什么能看出来,我也看不出来啊,也不知道哪位神仙想出来的),我们用一个函数lowbit(n)来表示这个神奇的数字。因为父节点是右偏的(杜撰的专业术语233),所以右边lowbit(n)个元素和这个区间是并列的,并且右边lowbit(n)长的区间最右边的元素是左右两个区间的祖先,它的位置我们很容易得到是n+lowbit(n)——这就是子节点到父节点的访问方式。
结点n是左边lowbit(n)个元素的祖先,所以n-lowbit(n)就是另外一个与n所在区间紧邻而且没有重叠的区间,所以我们想要遍历n以前所有的元素时只需要不断的进行n-lowbit(n)直到n==0表示已经跳出区间,通过这种方法我们能够方便的得到前缀和。
通过上面的总结,我们得到了对树状数组进行访问的初步方法。
lowbit()函数的实现方式一般开来说时lowbit(x)=x&(-x);至于为什么这就涉及到玄学的二进制知识,有兴趣的话自己去了解一下吧。
根据以上分析,我们可以得到初步的对树状数组建立以及维护的方法:
假如我们想要得到的是区间求和:

int lowbit(x)
{return x&(-x);
}
void update(int x,int y)
{for(;x<=n;x+=lowbit(x))	//x+lowbit(x)是包含x元素的父节点 {c[x]+=y;}
}

如何进行查询呢?

int sum(int x)	//x的前缀和 
{int ans=0;for(;x;x-=lowbit(x)){ans+=c[x];}return ans;
} 

如果想要得到中间一段区间的和,不难想到query(x,y)=sum(y)-sum(x-1);
这样,我们就初步实现了树状数组的维护和查询。
下附一道练手题:
POJ - 2352 Stars
大概意思就是说求一个二维数组中处于左下角的元素的个数。乍一看好像是一个二维的树状数组,但是分析一下数据范围就会发现不太现实。而且题目中说给出的数据是有顺序的,因此我们可以分析一下,不难发现(就当作不难吧)后面输入的数据对前面输入的数据是没有影响的,而且对于每一颗星星来讲,处于它下方右边的并没有什么意义,因此我们不妨将这个图形一维化,每个星星的亮度就是所有处于它左边(和它所在位置但不包括它)星星的个数。问题的思路应该很清晰,下附ac代码:

#include<cstdio>
#include<cstring>
using namespace std;const int maxn=32005;
int n;
int c[maxn];
int ans[maxn];int lowbit(int x)
{return x&(-x);
}
void update(int x)
{for(;x<=maxn;x+=lowbit(x)){c[x]++;}
}
int sum(int x)
{int ans=0;for(;x;x-=lowbit(x)){ans+=c[x];}return ans;
}
int main()
{int u,v;memset(c,0,sizeof(c));memset(ans,0,sizeof(ans));scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d%d",&u,&v);u++;//需要注意树状数组的下标必须从1开始!!!ans[sum(u)]++;update(u);}for(int i=0;i<n;i++){printf("%d\n",ans[i]);}return 0;
}

至于树状数组的区间修改区间查询,将会在树状数组的进一步理解中说明。

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

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

相关文章

命名函数

函数体是代码块 代码块do...end是一种表达式的组织方式。 # ./times.exs下defmodule Times dodef doule(n) don * 2end end 函数调用与模式匹配 代码如下&#xff1a; # ./factorial.exs    计算阶层 defmodule Factorial dodef of(0), do: 1          #终止条件…

STL运用的C++技术(6)——函数对象

http://blog.csdn.net/wuzhekai1985/article/details/6658940?_t_t_t0.20427969420870595 STL是C标准库的重要组成部分之一&#xff0c;它不仅是一个可复用的组件库&#xff0c;更是一个包含算法与数据结构的软件框架&#xff0c;同时也是C泛型编程的很好例子。STL中运用了许多…

列表与递归

头部和尾部 [head | tail ] [1] #head 1 tail [] [head | tail ] [1, 2, 3] #head 1 tail [2, 3] [head | tail ] [] #报错 创建映射函数 我们可以使用一个函数来处理列表中的各个元素&#xff0c;如此可以接受更加复杂的处理&#xff0c;也可以…

优先队列小结

不像栈和队列&#xff0c;虽然STL有较好实现但是我们自己也可以很方便的实现&#xff0c;优先队列自己实现起来就比较复杂&#xff0c;比较浪费时间&#xff08;而且自己目前也不会233&#xff09;而优先队列因为其较好的特性经常被使用&#xff0c;因此对它的熟练掌握是做题的…

字典:散列表、散列字典、关键字列表、集合与结构体

字典 散列表和散列字典都实现了Dict的行为。Keyword模块也基本实现了&#xff0c;不同之处在于它支持重复键。 Eunm.into可以将一种类型的收集映射转化成另一种。 defmodule Sum dodef values(dict) dodict |> Dict.values |> Enum.sumend endhd [ one: 1, two: 2, thre…

C++11 学习笔记 lambda表达式

http://blog.csdn.net/fjzpdkf/article/details/50249287 lambda表达式是C11最重要也最常用的一个特性之一。lambda来源于函数式编程的概念&#xff0c;也是现代编程语言的一个特点。 一.函数式编程简介 定义&#xff1a;简单说&#xff0c;“函数式编程”是一种“编程范式”。…

Cutting Codeforces Round #493 (Div. 2)

Cutting There are a lot of things which could be cut — trees, paper, “the rope”. In this problem you are going to cut a sequence of integers. There is a sequence of integers, which contains the equal number of even and odd numbers. Given a limited bud…

Enum、Stream

Enum 其常见用法见&#xff1a;https://cloud.tencent.com/developer/section/1116852 在sort时&#xff0c;如果要获得稳定的排序结果&#xff0c;要使用< 而不是 <。 Stream Stream是延迟处理的&#xff0c;而Enum是贪婪的&#xff0c;则意味着传给它一个收集&#xff…

linux网络编程之posix 线程(三):posix 匿名信号量与互斥锁 示例生产者--消费者问题

http://blog.csdn.net/jnu_simba/article/details/9123603 一、posix 信号量 信号量的概念参见这里。前面也讲过system v 信号量&#xff0c;现在来说说posix 信号量。 system v 信号量只能用于进程间同步&#xff0c;而posix 信号量除了可以进程间同步&#xff0c;还可以线程间…

洛谷P1080-国王游戏-贪心+高精度

P1080-国王游戏 啊啊啊&#xff0c;刚才已经写了一次了&#xff0c;但是Edge浏览器不知道为什么卡住了&#xff0c;难受。 好吧&#xff0c;其实是一道可做题&#xff0c;分析得到的贪心策略就是就是将a * b小的放在前面&#xff08;其他的懒得说了&#xff09;&#xff0c;主要…

字符串与二进制

单引号字符串会被表示成整数值列表。 &#xff1f;c返回字符 c 的整数编码。下面这个例子用于解析字符列表表示法&#xff0c;该表示法用于表示一个任意的有符号的十进制数据。 defmodule Parse dodef number([ ?- | tail ]) do_number_digits(tail, 0) * -1enddef number([ ?…

P1092虫食算-深度优先搜索+玄学剪枝

P1092虫食算 这道题的思想并不复杂&#xff0c;可是难点在于各种玄学剪枝。在仔细研究了题解大佬的剪枝原理后终于氵了过去。 先上代码&#xff1a; #include<cstdio> #include<cstring> #include<algorithm> using namespace std;const int MAXN100; int n…

多进程

使用spawn创建一个新进程&#xff0c;其第一个参数是模块名、第二个参数是函数名、第三个参数是参数列表。spawn会返回一个进程标识符&#xff0c;通常叫做PID。 defmodule Spawn1 dodef greet doreceive do{sender, msg} ->send sender, { :ok, "Hello #{msg}" }…

Linux socket编程(二) 服务器与客户端的通信

http://www.cnblogs.com/-Lei/archive/2012/09/04/2670964.html上一篇写了对套接字操作的封装&#xff0c;这一节使用已封装好的Socket类实现服务器与客户端的通信&#xff08;Socket的定义见上篇Socket.h) 服务器端&#xff1a; ServerSocket.h #ifndef SERVERSOCKET_H #defin…

OTP服务器

defmodule Sequence.Server douse GenServerdef handle_call( :next_number, _from, current_number) do{ :reply, current_number, current_number 1}  #reply告诉OTP将第二个元素返回给客户端end end use的效果将OTP GenServer的行为添加到当前模块。这样它就可以处理所有…

洛谷P1040-加分二叉树-dp+二叉树

P1040-加分二叉树 这道题放在深度优先搜索的训练题中&#xff0c;可是我实在没有看出来应该怎么搜索。看了题解以后才看出来是一个很简单的dp(我果然还是太菜了) 看出dp并且算出来最大的分数不是很复杂&#xff0c;关键是输出给定中序遍历序列的二叉树的先序遍历&#xff0c;要…

UNIX网络编程:I/O复用技术(select、poll、epoll)

http://blog.csdn.net/dandelion_gong/article/details/51673085 Unix下可用的I/O模型一共有五种&#xff1a;阻塞I/O 、非阻塞I/O 、I/O复用 、信号驱动I/O 、异步I/O。此处我们主要介绍第三种I/O符复用。 I/O复用的功能&#xff1a;如果一个或多个I/O条件满足&#xff08;输…

解决iex -S mix报错

执行iex -S mix命令的时候会遇到如下错误&#xff1a; 执行 mix deps.get 然后就可以运行 iex -S mix了 其中&#xff0c;有可能会出现 按照其网站下载相应文件&#xff0c;复制到项目根目录下&#xff0c;然后执行命令&#xff08;mix local.rebar rebar ./rebar&#xff09;即…

贪心算法——选择不相交区间问题

题目描述&#xff1a;设有n个活动的集合&#xff0c;其中每个活动都要求使用同一个资源&#xff0c;而在同一时间内只有一个活动能够使用这一资源&#xff0c;每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi(si<fi)&#xff0c;如果选择了活动i&#xff0c;则…

Anker—工作学习笔记

http://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html 1、基本知识 epoll是在2.6内核中提出的&#xff0c;是之前的select和poll的增强版本。相对于select和poll来说&#xff0c;epoll更加灵活&#xff0c;没有描述符限制。epoll使用一个文件描述符管理多个描述符&am…