分块思想(Sqrt Decomposition)的实现(golang)

news2024/9/24 15:25:42

前言

Sqrt Decomposition 是一种数据结构,能够在O(1)时间复杂度内完成数组元素值的查询和更新,在 O ( n ) O(\sqrt{n}) O(n ) 时间复杂度内完成数组某个区间属性值的查询和批量更新某个区间的值。这里的属性 可以是区间的和、最小值、最大值等。

说到区间的和,你可能会想到前缀和,能够在O(1)时间复杂度内查询区间的和,明显比本文要说的Sqrt Decomposition 更快。但是它不支持数据的更新,因为更新后需要重新计算前缀和。

Sqrt Decomposition 来自于分块思想的启发,把数组分成若干的长度相等的区块(最后一块除外)。区块长度可以任取,但一般为数组长度取根号。 假设我们有一个数组 a [ 0... n − 1 ] a[0...n-1] a[0...n1], 那么区块长度 s = ⌈ n ⌉ s=\left \lceil \sqrt{n} \right \rceil s=n 。如图:
在这里插入图片描述
以计算区间和为例。引入数组 b [ 0... s − 1 ] b[0...s-1] b[0...s1] ,其中 b [ j ] b[j] b[j]表示第 j j j个区块的和。这时:

  • 当获取数组位置 i i i某个值时,直接读取 a [ i ] a[i] a[i]即可。
  • 当设置数组位置 i i i某个值 v v v时,更新 b [ j ] = b [ j ] + v − a [ i ] b[j] = b[j] + v - a[i] b[j]=b[j]+va[i],再直接设置 a [ i ] a[i] a[i]即可。
  • 查询区间 [ l , r ] [l, r] [l,r]的和时,区间被分为三个部分:
    • 对于开头不完整区块,逐个累加。
    • 对于中间完整区块,累加对应b中的值
    • 对于结尾不完整区块,逐个累加。

对于前两种操作,显然 O ( 1 ) O(1) O(1)时间即可完成。
对于最后一种操作,时间复杂度计算如下:
T ( n ) = 左区间累加次数 + 中间完整区间数 + 右区间累加次数 ≤ s + s + s = O ( n ) \begin{align*} T(n) &= 左区间累加次数 + 中间完整区间数 + 右区间累加次数 \\ & \le s + s + s \\ & = O(\sqrt {n}) \end{align*} T(n)=左区间累加次数+中间完整区间数+右区间累加次数s+s+s=O(n )

到目前为上,还不支持区间的批量更新。即把区间的值同时加上某一个值,例如[l, r]范围内的值,同时加上5。如果把批量更新拆解成对数组a中[l, r]范围内每个元素的更新,则复杂度为O(n), 太高了。因此需要额外引入数组 c [ 0... s − 1 ] c[0...s-1] c[0...s1]记录区间的更新。更新过程如下,依然是把区间分为三个部分:

  • 对于开头不完整区块,逐个更新值到数组a
  • 对于中间完整区块,把更新记录对应区块中的c中的值
  • 对于结尾不完整区块,逐个更新值到数组a。

与计算区间和方法一样,可以计算这样操作的时间复杂度为 O ( n ) O(\sqrt{n}) O(n )

因为有部分更新是记录到c中,所以逻辑上数组第 i i i个位置的值应由a和c共同组成。即 d a t a [ i ] = a [ i ] + c [ j ] / s {data}[i] = a[i] + c[j] / s data[i]=a[i]+c[j]/s 。其中 j j j表示数组第 i i i个位置对应的区块索引号。

参考:
https://cp-algorithms.com/data_structures/sqrt_decomposition.html#description

实现

以go语言,实现上述区间和的例子。

package main

import (
	"fmt"
	"math"
)

type SqrtDecomposition struct {
	a []int
	s int   // 区间长度
	b []int // 区间和
	c []int // 区间delta。data[i] = a[i] + c[j] / s
}

func NewSqrtDecomposition(data []int) *SqrtDecomposition {
	// 初始化分区大小
	s := 2
	if len(data) > 4 {
		s = int(math.Ceil(math.Sqrt(float64(len(data)))))
	}
	// 分区个数
	count := 1 + (len(data)-1)/s

	// 计算b[i] 和 c[i]值
	// b[i] 即表示小区间的和。遍历相加即可
	// c[i] 初始值为0
	b := make([]int, count)
	c := make([]int, count)
	for i := 0; i < len(data); i++ {
		b[i/s] += data[i]
	}

	// 计算c[i] 值
	return &SqrtDecomposition{
		a: data,
		s: s,
		b: b,
		c: c,
	}
}

/*
*
获取某个位置的区间号和区间长度
*/
func (receiver *SqrtDecomposition) getInfo(p int) (int, int) {
	le := receiver.s
	no := p / le
	if no == len(receiver.b)-1 {
		le = len(receiver.a) - no*le
	}
	return no, le
}

/*
*
获取数组长度
*/
func (receiver *SqrtDecomposition) Size() int {
	return len(receiver.a)
}

/*
*
获取范围内的和
*/
func (receiver *SqrtDecomposition) GetRange(l int, r int) int {
	sum := 0
	i := l
	for i <= r {
		if i%receiver.s == 0 && (i+receiver.s-1) <= r {
			no, _ := receiver.getInfo(i)
			sum += receiver.b[no]
			i += receiver.s
		} else {
			sum += receiver.Get(i)
			i += 1
		}
	}
	return sum
}

/*
*
获取第p个位置的值
*/
func (receiver *SqrtDecomposition) Get(p int) int {
	no, le := receiver.getInfo(p)
	return receiver.a[p] + receiver.c[no]/le
}

/*
*
设置第p个位置的值
*/
func (receiver *SqrtDecomposition) Set(p int, v int) {
	no, le := receiver.getInfo(p)
	newAi := v - receiver.c[no]/le
	receiver.b[no] += newAi - receiver.a[p]
	receiver.a[p] = newAi
}

/*
*
给一定范围内的值增加一个变化
*/
func (receiver *SqrtDecomposition) SetRange(l int, r int, d int) {
	i := l
	for i <= r {
		if i%receiver.s == 0 && (i+receiver.s-1) <= r {
			no, _ := receiver.getInfo(i)
			receiver.c[no] += d * receiver.s
			receiver.b[no] += d * receiver.s
			i += receiver.s
		} else {
			receiver.Set(i, receiver.Get(i)+d)
			i += 1
		}
	}
}

测试

对各个功能进行了测试,测试结果与代码如下:

在这里插入图片描述


func main() {
	structure := NewSqrtDecomposition([]int{
		1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
	})

	//get
	fmt.Println("【初始值】")
	fmt.Print("值:")
	for i := 0; i < structure.Size(); i++ {
		fmt.Print(structure.Get(i), " ")
	}
	fmt.Println()
	fmt.Print("和:")
	for i := 0; i < len(structure.b); i++ {
		fmt.Print(structure.b[i], " ")
	}
	fmt.Println()

	// set
	for i := 0; i < structure.Size(); i++ {
		structure.Set(i, structure.Size()-i)
	}
	fmt.Println("【设置后的值】")
	fmt.Print("值:")
	for i := 0; i < structure.Size(); i++ {
		fmt.Print(structure.Get(i), " ")
	}
	fmt.Println()
	fmt.Print("和:")
	for i := 0; i < len(structure.b); i++ {
		fmt.Print(structure.b[i], " ")
	}
	fmt.Println()

	// get range
	fmt.Println("【获取范围】")
	for i := 0; i < structure.Size(); i++ {
		for j := 0; j < structure.Size(); j++ {
			if j >= i {
				fmt.Print(structure.GetRange(i, j), "\t")
			} else {
				fmt.Print("-", "\t")
			}
		}
		fmt.Println()
	}

	// set range
	structure.SetRange(1, 8, 2)
	structure.SetRange(5, 9, -3)

	fmt.Println("【设置范围】")
	fmt.Print("值:")
	for i := 0; i < structure.Size(); i++ {
		fmt.Print(structure.Get(i), " ")
	}
	fmt.Println()
	fmt.Print("和:")
	for i := 0; i < len(structure.b); i++ {
		fmt.Print(structure.b[i], " ")
	}
	fmt.Println()
	for i := 0; i < structure.Size(); i++ {
		for j := 0; j < structure.Size(); j++ {
			if j >= i {
				fmt.Print(structure.GetRange(i, j), "\t")
			} else {
				fmt.Print("-", "\t")
			}
		}
		fmt.Println()
	}
	fmt.Println()
}

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

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

相关文章

DDR3(MIG核配置官方demoFPGA代码实现及仿真)

由于直接对 DDR3 进行控制很复杂&#xff0c;因此一般使用 MIG IP 来实现&#xff0c;同时为了更简单地使用 MIG IP&#xff0c;我们采用 AXI4 总线协议进行控制。下面首先介绍 MIG IP 的配置&#xff0c;然后看看官方 demo &#xff08;里面包含一个仿真要用到的 DDR3 模型&am…

Android Jetpack:利用Palette进行图片取色

与产品MM那些事 新来一个产品MM&#xff0c;因为比较平&#xff0c;我们就叫她A妹吧。A妹来第一天就指出&#xff1a;页面顶部的Banner广告位的背景是白色的&#xff0c;太单调啦&#xff0c;人家不喜欢啦&#xff0c;需要根据广告图片的内容自动切换背景颜色&#xff0c;颜色…

送了老弟一台 Linux 服务器,它又懵了!

大家好&#xff0c;我是鱼皮。 前两天我学编程的老弟小阿巴过生日&#xff0c;我问他想要什么礼物。 本来以为他会要什么游戏机、Q 币卡、鼠标键盘啥的&#xff0c;结果小阿巴说&#xff1a;我想要一台服务器。 鱼皮听了&#xff0c;不禁称赞道&#xff1a;真是个学编程的好苗…

演讲回顾 | 释放Atlassian工具的力量

2023年4月14日&#xff0c;Atlassian中国合作伙伴企业日上海站圆满落幕。作为Atlassian全球白金合作伙伴、云专业伙伴&#xff0c;龙智携客户小米参与了此次活动。 小米集团信息技术部SRE薛世英为大家带来主题为《小米集团Jira实战&#xff1a;如何在高负载状态下保持Jira性能与…

Html技术

软件架构&#xff1a; 架构访问端服务端C/SClientServerB/SBrowserServer Html&#xff1a; Hyper Text Markup Language &#xff08;超文本标记语言&#xff09; 简写&#xff1a;HTML HTML 通过标签来标记要显示的网页中的各个部分。 网页文件本身是一种文本文件&#xff0…

Redis类型操作

目录 一、List&#xff08;列表&#xff09; 1.List模板 2.List基本操作(不区分大小写) 2.1添加命令 2.2移除命令 2.3下标索引 2.4列表长度 2.5移除指定值 2.6List截断 2.7移除列表最后一个元素并将他移到新的列表中 2.8替换操作 2.9插入命令 二、Set(集合) 1.Set定义 2…

日撸 Java 三百行day41

文章目录 说明day41 顺序查找与折半查找1.顺序查找2.折半查找3.代码 说明 闵老师的文章链接&#xff1a; 日撸 Java 三百行&#xff08;总述&#xff09;_minfanphd的博客-CSDN博客 自己也把手敲的代码放在了github上维护&#xff1a;https://github.com/fulisha-ok/sampledat…

微信小程序蓝牙功能开发与问题记录

一、蓝牙支持情况 1. 微信小程序对蓝牙的支持情况 目前普遍使用的蓝牙规格&#xff1a;经典蓝牙和蓝牙低功耗。 经典蓝牙&#xff08;蓝牙基础率/增强数据率&#xff09;&#xff1a;常用在对数据传输带宽有一定要求的大数据量传输场景上&#xff0c;比如需要传输音频数据的…

AI工具和用法汇总—集合的集合

AI 工具和用法汇总 汇集整理 by Staok/瞰百&#xff0c;源于相关资料在我这慢慢越积累越多&#xff0c;到了不得不梳理的程度。 文中有许多内容作者还没有亲自尝试&#xff0c;所以很多内容只是罗列&#xff0c;但信息大源都已给出&#xff0c;授人以渔&#xff0c;欢迎 PR 补…

hadoop3.2.1+hive3.1.2-docker安装

Hadoop 1.拉取镜像 docker pull hadoop_hive:32.运行容器 建立hadoop用的内部网络(此步出错&#xff0c;若与其它网段冲突&#xff0c;可省略) #指定固定ip号段 docker network create --driverbridge --subnet172.17.0.1/16 hadoop建立Master容器&#xff0c;映射端口 10…

滚动加载数据

效果图: 综合使用后,觉得还是以下绑定 div监听滚动条的方式好用,有的可以监听滚轮滚动,但是监听不到鼠标拖动滚动条,下面这种方式两者都可以监测到↓ <template><div class"scrollTest-container" id"scrollTestContainer"><div class&quo…

简单分享微信小程序上的招聘链接怎么做

招聘小程序的主要用户就是企业招聘端和找工作人员的用户端,下面从这两个端来对招聘小程序开发的功能进行介绍。 企业端功能 1、岗位发布:企业根据自身岗位需求,在招聘app上发布招聘岗位及所需技能。 2.简历筛选:根据求职者提交的简历选择合适的简历,并对公开发布的简历进行筛…

105.(cesium篇)cesium指南针

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <html lang="en">

【软考高级】2019年系统分析师综合知识

第 1 题 面向对象分析中&#xff0c;一个事物发生变化会影响另一个事物&#xff0c;两个事物之间属于&#xff08;1&#xff09;。 (1) A .关联关系 B .依赖关系 C .实现关系 D .泛化关系 参考答案&#xff1a;(1)B 试题解析&#xff1a; 本题考查的是 UML 图中类的关系…

业务零中断,数据零丢失|庚顿新一代双活高可用架构实时数据库为流程工业核心业务保驾护航

新一代双活架构高可用架构实时数据库管理系统可实现流程工业数据平台“零中断”、“零丢数”的超高可用性要求&#xff0c;在满足实时性要求的同时&#xff0c;实现断网/掉电时业务不中断、不丢数&#xff0c;突破传统主备架构。 随着生产生活自动化、数字化、信息化水平不断升…

二叉树或者多叉树直径问题

原题链接&#xff1a;543. 二叉树的直径 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给定一棵二叉树&#xff0c;你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。 什么是任意两点路径…

ChatGPT来了不用慌,广告人还有这个神器在手

#ChatGPT能取代广告人吗&#xff0c;#ChatGPT会抢走你的工作吗&#xff1f;#ChatGPT火了&#xff0c;会让营销人失业吗&#xff1f;自ChatGPT爆火以来&#xff0c;各种专业or非专业文章不停给广告人强加焦虑&#xff0c;但工具出现的意义&#xff0c;更多在于提效而非替代&…

BetaFlight统一硬件配置文件研读之timer命令

BetaFlight统一硬件配置文件研读之timer命令 1. 源由2. 代码分析3. 实例分析4. 配置情况4.1 AFn配置查表4.2 timer4.3 timer show4.4 timer pin list 5. 参考资料 统一硬件配置文件的设计是一种非常好的设计模式&#xff0c;可以将硬件和软件的工作进行解耦。 1. 源由 cli命令…

某程序员哀叹:二本计算机,4年开发,年包才40多万。二本真的不如985/211吗?

前段时间&#xff0c;某职场论坛上有人发了一个帖子&#xff0c;发帖人问&#xff1a;为什么大家工资那么高&#xff0c;三五年都六七十万了&#xff1f;我二本计算机专业&#xff0c;四年前端开发&#xff0c;找个年包40万多点就顶头了。 原贴如下&#xff1a; 有网友表示楼主…

【Docker】Docker上篇

文章目录 一、认识Docker1、Docker出现的背景2、Docker的历史3、虚拟机技术与容器技术4、容器比虚拟机快的原因5、对Devops层面的影响 二、Docker的安装的原理1、核心名词2、安装Docker&#xff08;for Linux&#xff09;3、配置阿里云镜像加速4、Run的流程和Docker原理 三、Do…