当前位置: 首页 > wzjs >正文

巴中网站建设营销推广计划怎么写

巴中网站建设,营销推广计划怎么写,网站举报平台,一条 wordpress树状数组是算法中一种十分重要的数据结构!通过这篇文章你能够快速的get到树状数组的精髓,即使是第一次接触树状数组也能让你完全弄懂 目录 管辖区间 怎么让计算机计算 lowbit? 区间初始化: 更新区间 计算前缀和: 计算任意区…

树状数组是算法中一种十分重要的数据结构!通过这篇文章你能够快速的get到树状数组的精髓,即使是第一次接触树状数组也能让你完全弄懂

目录

管辖区间

怎么让计算机计算 lowbit?

区间初始化:

更新区间

计算前缀和:

计算任意区间和:


先来举个例子:我们想知道  a[1...7]的前缀和,怎么做?

一种做法是:a[1]  +a[2] + a[3] + a[4] .... a[7],需要求 7个数的和。

但是如果已知三个数 A,B,C,,A = a[1...4] 的总和,B = [5...6] 的总和和C = a[7..7](其实就是a[7] 自己)。你会怎么算?你一定会回答:A + B + C,只需要求  3个数的和。

这就是树状数组能快速求解信息的原因:我们总能将一段前缀 [1..n] 拆成 不多于 \log n 段区间,使得这 \log n 段区间的信息是 已知的

于是,我们只需合并这  \log n  段区间的信息,就可以得到答案。相比于原来直接合并  个信息,效率有了很大的提高。不难发现信息必须满足结合律,否则就不能像上面这样合并了。

那么如何划分a[1.. n]呢? 咱们直接先说结论吧  (图片出自灵神)

管辖区间

那么问题来了,c[x](x \ge 1) 管辖的区间到底往左延伸多少?也就是说,区间长度是多少?

树状数组中,规定 c[x] 管辖的区间长度为 2^{k},其中:

  1. 设二进制最低位为第 0 位,则 k 恰好为 x 二进制表示中,最低位的 1 所在的二进制位数;
  2. 2^k(c[x] 的管辖区间长度)恰好为 x 二进制表示中,最低位的 1 以及后面所有 0 组成的数。举个例子,c_{88} 管辖的是哪个区间?

因为 88_{(10)}=01011000_{(2)},其二进制最低位的 1 以及后面的 0 组成的二进制是 1000,即 8,所以c_{88}管辖 8 个 a 数组中的元素。

因此,c_{88}代表 a[81 \ldots 88]的区间信息。

我们记 x 二进制最低位 1 以及后面的 0 组成的数为 \operatorname{lowbit}(x),那么 c[x] 管辖的区间就是 [x-\operatorname{lowbit}(x)+1, x]。 为什么要加1呢这个理解的十分简单你看c_{88}

这里注意:\boldsymbol{\operatorname{lowbit}}指的不是最低位 1 所在的位数 \boldsymbol{k},而是这个 1 和后面所有 0 组成的 \boldsymbol{2^k}

怎么让计算机计算 lowbit?

(如果是人那么一看就知道了,那么如何让计算机理解呢?)

根据位运算知识,可以得到 lowbit(x) = x & -x。这是一种简单的实现方法

如果对位运算不是十分敏感的可能不知道为什么是这样算的,我们可以假设x是 7那么相应的lowbit(7) 为1 对于负数的二进制就是求法:

  1.         先求绝对值的二进制。对于-7来说7的二进制是111
  2.         再求第一步的补码那么就是000
  3.         在将第二步得到的值 加一得到 001,那么001就是-7的二进制,当然前面缺位补0

那么言归正传 7 & -7 就是111 & 001 那么lowbit就是001 十进制就是1表示当前lowbit(7)值为1,并且区间只有一个值

def lowbit(self, x):return x & -x

补充:对于计算机是这样理解的,那么对于我们还有一种更容易的理解方式,参考灵神题解

区间初始化:

    def __init__(self, nums: List[int]):n = len(nums)tree = [0] * (n + 1)for i, x in enumerate(nums, 1):tree[i] += x nxt = i + (i & -i) #下一个关键区间的右端点,这也就说明当前区间在下一个区间内,那么就要操#这里的 i & -i 就是lowbitif nxt <= n:tree[nxt] += tree[i] self.nums = nums self.tree = tree 

更新区间

假设下标 x 发生了更新,那么所有包含 x 的关键区间都会被更新。

例如下标 5 更新了,那么关键区间 [5,5],[5,6],[1,8],[1,16] 都需要更新,这三个关键区间的右端点依次为 5,6,8,16。

如果在 5-6,6-8,8-16 之间连边(其它位置也同理),我们可以得到一个什么样的结构?

如下图,这些关键区间可以形成如下树形结构(区间元素和保存在区间右端点处)。


 

注意到:

5+lowbit(5)=5+1=6

6+lowbit(6)=6+2=8

8+lowbit(8)=8+8=16

猜想:如果 x 是一个被更新的关键区间的右端点,那么下一个被更新的关键区间的右端点为 x+lowbit(x)。

我们需要证明两点:

  1. 右端点为 x 的关键区间,被右端点为 x+lowbit(x) 的关键区间包含。
  2. 右端点在 [x+1,x+lowbit(x)−1] 内的关键区间,与右端点为 x 的关键区间没有任何交集。

1) 的证明

2 )的证明

以上两点成立,就可以保证 x+lowbit(x) 是「下一个」被更新的关键区间的右端点了。

由于任意相邻被更新的关键区间之间,没有其余关键区间包含 x,所以我们可以找到所有包含 x 的关键区间,具体做法如下。

def update(self, index: int, val: int) -> None:#将nums[index]更新为valdelta = val - self.nums[index] #val是目标值,相当于把当前值增加了deltaself.nums[index] = val #把当前值更新了i = index + 1 #为什么index要加1呢,因为index是下标0 --n-1 为了和1--n的c的下标对应肯定加1while i < len(self.tree):self.tree[i] += delta i += i & -i #手搓lowbit 

计算前缀和:

在树状数组中计算1-n的前缀和有更快的方法那就是访问树状数组的结构

def prefixsum(self, i: int) -> int: #计算前缀和是为了计算区间,每一个区间都可以用前缀和表示s = 0while i:s += self.tree[i]i  = i - (i & -i) #相当于i - lowbit(),其实就是前缀和跳到上一个关键区间的右端点了#相较于传统计算前缀和更快,这里的prefixsum是计算1-i的前缀和

计算任意区间和:

因为本质上所有子区间都可以写成两个区间和的差

def sumRange(self, left: int, right: int) -> int:return self.prefixsum(right + 1) - self.prefixsum(left)

关于相关题目,博主会尽快整理发表。

下面是全部实现代码和解释:

class NumArray:__slots__ = 'nums', 'tree'#__slots__是一个特殊的内置类属性,它可以用于定义类的属性名称的集合。一旦在类中定义了__slots__属#性,Python将限制该类的实例只能拥有__slots__中定义的属性。这有助于减少每个实例的内存消耗,#提高属性访问速度,同时也可以防止意外添加新属性。#最右端为i的长为lowbit(i)的关键区间是 [i - lowbit(i) + 1 , i]def __init__(self, nums: List[int]):n = len(nums)tree = [0] * (n + 1)for i, x in enumerate(nums, 1):tree[i] += x nxt = i + (i & -i) #下一个关键区间的右端点,这也就说明当前区间在下一个区间内,那么就要操#这里的 i & -i 就是lowbitif nxt <= n:tree[nxt] += tree[i] self.nums = nums self.tree = tree def update(self, index: int, val: int) -> None:#将nums[index]更新为valdelta = val - self.nums[index] #val是目标值,相当于把当前值增加了deltaself.nums[index] = val #把当前值更新了i = index + 1 #为什么index要加1呢,因为index是下标0 --n-1 为了和1--n的c的下标对应肯定加1while i < len(self.tree):self.tree[i] += delta i += i & -i #手搓lowbit # #需要证明两点:# 1.右端点为x的关键区间,被右端点为x + lowbit(x)的关键区间包含# 2.右端点为[x + 1, x + lowbit(x) - 1]内的关键区间,与右端点为x的关键区间没有任何交集def prefixsum(self, i: int) -> int: #计算前缀和是为了计算区间,每一个区间都可以用前缀和表示s = 0while i:s += self.tree[i]i  = i - (i & -i) #相当于i - lowbit(),其实就是前缀和跳到上一个关键区间的右端点了#相较于传统计算前缀和更快,这里的prefixsum是计算1-i的前缀和return s def sumRange(self, left: int, right: int) -> int:return self.prefixsum(right + 1) - self.prefixsum(left)

本博客参考灵神题解和树状数组

希望这篇文章能帮到你,感谢点赞收藏!

http://www.dtcms.com/wzjs/116397.html

相关文章:

  • 网站系统维护地推平台
  • 西安免费做网站公司企业网站开发
  • 内网网站建设工作会议网络营销服务的特点
  • 打开网站 显示建设中seo技术代理
  • 迅雷网站做爰视频品牌推广计划
  • b2b网站解决方案游戏优化大师
  • 公司怎么建网站做推广百度网站排名关键词整站优化
  • 黑龙江高端网站建设方象科技的企业愿景
  • 网站备案安全承诺书百度上做优化
  • 南宁做网站比较好的公司成都关键词排名推广
  • 如何建论坛网站seo关键词排名优化评价
  • 网站建设行业发展史今日国内新闻大事件
  • iis配置网站无法访问百度官方网页
  • 上海网站制作工作室百度seo公司兴田德润
  • 网站建设培训教程有利于seo优化的是
  • iis wordpress衡水seo排名
  • 武汉做网站企业百度竞价排名服务
  • 网站更新的意义广告推销网站
  • 网站的图文链接怎么做成都百度推广联系方式
  • 网站如何做反链网上培训
  • 网站首页可以做竖版吗网络营销的原理
  • 手机搭建网站软件下载久久seo综合查询
  • 响应式网站导航怎么做办公软件速成培训班
  • iis 无法访问此网站直通车推广怎么做
  • 网站域名 被别人备案沈阳网站关键词排名
  • 东阿企业做网站推广武汉seo网站优化排名
  • 东莞网站建设设互联网品牌的快速推广
  • 网站地图提交长春做网站推广的公司
  • 山东网站方案百度竞价排名规则及费用
  • 怀化建设公司网站百度搜索电话