线性结构 —— 分块算法
【概述】
所谓分块,即对于一个长度为 n 的序列,设块的大小为 S,从序列的第一个元素起,每 S 个元素被分成一块,若剩余的元素不足 S 个,令他们组成一块。经过分块后的数组,称为块状数组,在块状数组的基础上加以扩展,即可得到块状链表。
在一个区间操作时,完整包含于区间的块称为整块,只有部分包含于区间的块,称为不完整的块,不完整的块实质上行即为区间左右端点所在的两个块。
在许多区间问题中,使用树型结构,如:树状数组、线段树等会更加优秀,但当所需的某些信息无法快速合并时,就只能使用分块,例如:询问一个区间的众数
需要注意的是,利用来解决的问题,大部分都是要求强制在线的,此外,在时间复杂度上:树状数组 > 线段树 > 块状数组(分块)
但三者各有优劣:
- 树状数组:代码简单、常数小
- 线段树:代码复杂、功能强大、常数大
- 块状数组:代码复杂、常数大、能维护一些难以快速合并的数据
【基本原理】
从时间复杂度来考虑,一般来说,分块长度为 sqrt(n),那么,初始化时有:
int block,sum;//block为块的长度,sum为块的个数
int a[N];//存放数列元素
int pos[N],tag[N];//pos记录第i个元素在第几个块中,tag为操作标记
int ans[N];//维护整块和
void init(){//初始化block=(int)sqrt(n) //块的长度sum=n/block;//块数if(n%block)sum++;for(int i=1;i<=n;i++)//第i个元素在第几块中pos[i]=(i-1)/block+1;
}
对于区间查询,有三种情况:
- 询问区间 [x,y] 中,x 不是块的左边界,y 也不是块的右边界
- 询问区间 [x,y] 中,x 不是块的左边界,y 是块的右边界
- 询问区间 [x,y] 中,x 是块的左边界,y 不是块的右边界
由于可以预处理每一块的值,因此对于一块来说,查询的时间复杂度是 O(1) 的,对于多出来的边角料的部分总和不会超过 2*sqrt(n),基于这个时间复杂度,进行暴力求解,可以发现对于第一种情况,q 次查询的复杂度为 O(q*sqrt(n)),对于第二、三中情况,完全可以当成情况 1 来处理
对于一个块的左边界,可以求出上一个块的右边界 (pos[x]-1)*block,那么 +1 后就是这个块的左边界,即:(pos[x]-1)*block+1
因此,在每次询问时,第 i 个元素 a[i] 处于第 (i-1)/sqrt(n)+1 块,其左端点为 (i-1)*sqrt(n)+1,右端点为 min(i*sqrt(n),n),返回元素的值再加上其所在块的标记即可。
int block,sum;//block为块的长度,sum为块的个数
int a[N];//存放数列元素
int pos[N],tag[N];//pos记录第i个元素在第几个块中,tag为操作标记
int ans[N];//维护整块和
int query(int L,int R){for(int i=L;i<=min(R,pos[L]*block);i++)//处理左边角料//do somethingfor(int i=(pos[R]-1)*block+1;i<=R;i++)//处理右边角料//do somethingfor(int i=pos[L]+1;i<=pos[R]-1;i++)//处理中间k块//do something
}
对于修改操作,与查询操作一样,同样分成三部分,对于边角料暴力修改 a[i],对于每一块,修改每一块的标记值 tag[pos[i]],那么,对于 m 次修改,总时间复杂度为 O(m*sqrt(n))
int block,sum;//block为块的长度,sum为块的个数
int a[N];//存放数列元素
int pos[N],tag[N];//pos记录第i个元素在第几个块中,tag为操作标记
void change(int x){//do something
}
void update(int L,int R,int x){for(int i=L;i<=min(R,pos[L]*block);i++)//处理左边角料,对a[i]进行操作change(x);if(pos[L]!=pos[R])//存在右区间才遍历,防止重复计算for(int i=(pos[R]-1)*block+1;i<=R;i++)//处理右边角料,对a[i]进行操作change(x);for(int i=pos[L]+1;i<=pos[R]-1;i++)//处理中间k块,对tag[i]进行操作change(x);
}
而对于整块的预处理,即使每个块暴力进行对 ans[i] 的预处理,时间复杂度也只有 O(n)
int ans[N];//维护整块
void work(int L,int R,int x){int start=0;for(int i=L;i<=R;i++)//do something with startans[x]=start;//整块的标记
}int mian(){...for(int i=1;i<=sum;i++)//传入块的左右边界与编号work((i-1)*block+1,i*block,i);...}
【模版&例题】
模版原理:分块九讲
- 数列分块入门 1(LibreOj-6277)(区间加法,单点询问):点击这里
- 数列分块入门 2(LibreOj-6278)(区间加法,询问区间内小于某个值 x 的元素个数):点击这里
- 数列分块入门 3(LibreOj-6279)(区间加法,询问区间内小于某个值 x 的前驱):点击这里
- 数列分块入门 4(LibreOj-6280)(区间加法,询问区间和):点击这里
- 数列分块入门 5(LibreOj-6281)(区间开方,询问区间和):点击这里
- 数列分块入门 6(LibreOj-6282)(单点插入,单点询问):点击这里
- 数列分块入门 7(LibreOj-6283)(区间乘法与加法,单点询问):点击这里
- 数列分块入门 8(LibreOj-6284)(询问区间某值个数,区间赋值):点击这里
- 数列分块入门 9(LibreOj-6285)(询问区间众数):点击这里
线性结构 —— 分块算法相关推荐
- 线性结构 —— 分块算法 —— 分块九讲
模型1:区间加法,单点询问 问题:给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,单点查值. 对每个块设置一个加法标记,记录这个块中元素一共加了多少,每次操作对整块直接 O(1) 标记, ...
- java算法概述,Java数据结构与算法基础(一)概述与线性结构
Java数据结构与算法基础(二)递归算法 Java数据结构与算法基础(一)概述与线性结构 学习目的:为了能更顺畅的读很多底层API代码和拓宽解决问题的思路 一.数据结构概述 1.数据结构是什么?数据与 ...
- 数据结构与算法(Python版) | (6) 线性结构---队列、双端队列和列表
本专栏主要基于北大的数据结构与算法教程(Python版)进行整理,包括课程笔记和OJ作业. 课程链接 1. 队列抽象数据类型及Python实现 什么是队列? 队列是一种有次序的数据集合,其特征是: 1 ...
- 线性表顺序存储结构操作算法
线性表顺序存储结构操作算法 ** 顺序表的初始化 线性表的插入算法 线性表的删除算法 线性表的查找算法** 根据书本的知识线性表顺序存储结构的操作算法其实是我们刚进入数据结构与算法的必修课 其实算法无 ...
- 数据结构与算法之线性结构链表
数据结构与算法之线性结构链表 这一篇文章主要介绍的是通过java实现单链表.循环链表和双向循环链表,仅供自己复习使用,如有什么不足之处,欢迎指出. 单链表: package xianxingjiego ...
- 数据结构与算法——线性结构——线性表及其表示
-"一,线性结构 1.顺序储存结构直接表示 多项式. 1).使用数组来表示多项式.(用数组下标来表示指数,值来表示系数) 可以表示成: 2).使用结构数组来表示.(把系数和指数看成一个二元组 ...
- (一)数据结构与算法-线性结构和非线性结构
线性结构和非线性结构 数据结构包括:线性结构和非线性结构 线性结构 线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系 线性结构有两种不同的存储结构,即顺序存储借故偶和链式存储结构 ...
- 一步一步写算法(之线性结构的处理)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 我们知道,在内存中的空间都是连续的.也就是说,0x00000001下面的地址必然是0x0000 ...
- 矩阵LU分解分块算法实现
本文主要描述实现LU分解算法过程中遇到的问题及解决方案,并给出了全部源代码. 1. 什么是LU分解? 矩阵的LU分解源于线性方程组的高斯消元过程.对于一个含有N个变量的N个线性方程组,总可以用高斯消去 ...
最新文章
- 【超级大转载】常用的D3D变换相关函数
- 大龄码农经验那么丰富,为什么很多公司都不招?
- dede调用头条非头条
- Sql Server 2005自定义分页
- [Python人工智能] 七.什么是过拟合及dropout解决神经网络中的过拟合问题
- SAP UI5 CreateBindingContext 方法的实现逻辑
- 结构设计模式 - Flyweight设计模式(享元设计模式)
- Temp文件夹缺少network service权限,webservice能访问,但是不能调用
- jsp模糊查询_[内附完整源码和文档] 基于JSP+Servlet校园二手交易平台
- 6 检验并打印魔方矩阵c语言,检验并打印魔方矩阵
- C# HttpClientHelper
- 跨越OpenGL和D3D的鸿沟[转]
- nyoj-1016-德莱联盟(向量叉乘判断线段相交)
- windows和linux环境下的嵌入式开发区别
- unity3d 压缩文件夹和压缩文件
- 7-3 计算职工工资
- excel插件开发,Smartbi免费版安装流程
- Adversarial Semantic Alignment for Improved Image Captions
- 什么是数据科学?数据科学的基本内容
- 机器学习之路(四)之感知机算法PLA