分块详解(优雅的暴力)

本文详细介绍了分块技术在解决区间操作问题中的应用,通过实例展示了如何利用分块优化复杂度,包括区间加法、区间求和、区间逆序对计数等场景,同时提供了具体的C++代码实现,揭示了分块在非线段树解决方案中的价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       

        作者: hsez_yyh

       链接: ​​​​​​​​​​​​​​https://blog.youkuaiyun.com/yyh_getAC/article/details/126823013

       来源:湖北省黄石二中信息竞赛组
       著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

        分块,顾名思义,就是把问题分成很多块,然后对每块单独求解,最终的答案就是每块的答案的并。        在信息学中,我们通常将分块定义为 把一个长度为 N 的序列分成若干块,然后对于每次在序列上的操作 ( 一般是区间的修改和查询),我们们分别在操作设计的那些块上进行即可。 简单的来说,分块其实就是一种暴力的优化。

        还是先来看一个小问题: 243. 一个简单的整数问题2 - AcWing题库

        该题要支持区间加以及区间求和,很显然,这是一个线段树的板子题,然而我们今天不用线段树来做。首先我们想一想这道题暴力慢在哪,每次操作如果我们暴力进行的话,那将会是 O(N^2) 的复杂度,但是我们好好想一想,每次区间加法的时候,我们其实是没必要过多关注每个元素的具体值的,例如我们将区间 [ l , r ] 这段区间内的所有数都+1,其实相当于将[ l , r ] 这个区间内所有元素的和+( r-l+1 ),类比于线段树,要是我们能简化这个过程就好了,也就是说,我们要是能采取一种非线段树的方式给每次操作的区间打上标记(即增删改了些什么)就好了。        为了不使用线段树,并且要使复杂度尽可能的优,那就得请出我们今天的主角: 分块

分块的实现

        分块的思路很简单。 首先,我们先把给定的数组进行分块处理,即把他们分成若干个相同的区间,一般的,我们把每个块的长度定为 \sqrt{N} ;为什么是 \sqrt{N} 呢 ? 因为我们的操作是基于块的:        假设我们当前要操作的区间为 [ l , r ] ,那么我们可以先看有多少个块完全处于这个区间中,对于这些块,我们将只需要在块上打上操作标记即可,并不用真正地每个元素修改,而我们最多会有 \sqrt{N}  个块,所以这个过程的复杂度为\sqrt{N}  的 ; 特别的我们还会有一些块只有一部分在我们的区间中,而根据常识,这样的块最多只会存在两块,那么我们对于这两块,直接暴力地修改包含在区间的部分的元素即可,很显然,这两块的元素最多有 2\times \sqrt{N}  个,所以过程的复杂度也在\sqrt{N} 的级别。 而每次操作,我们最坏会把上述的两个过程都跑满,但是除去我们小小的常数,单次操作的复杂度还是可以保证在\sqrt{N}  级别的。,所以这样算下来,我们分块的总复杂度大约为 O(N\times \sqrt{N}) ,虽然不及线段树,但是速度还是很快的,爆切几道题目还是可以的。

我们还是画个图来感性理解一下,就以上述那道题目为例:

         然后我们来进行一个修改操作,比如说把区间 [ 3,8 ] 内的所有元素 + 2 

        

         修改操作非常简单,我们再来看看查询操作,例如:求区间[ 4,8 ] 内的元素和:

        

可见 求和操作也非常的简单,那么我们就能愉快的切掉例题了:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
LL a[N];
int loc
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值