Update:2025.5.25


树状数组是基于二进制划分与倍增的思想,线段树基于分治的思想。之所以能够高效修改和查询,就是把序列分成了大大小小的“段”,花费额外(增加空间,空间换时间)的代价对这些“段”管理的信息进行记录和更新,查询一个区间的信息,可以将这个区间分成几个已有的“段”结合,从而提高效率。

树状数组和线段树也有缺点,当需要维护一些不满足区间可加性、可减性信息时显得吃力,代码也不直观,需要深入理解并注意很多细节。

当维护的信息不满足区间合并性,例如区间众数,要提高效率,就需要对序列进行分块,分块的基本思想就是“大段维护,局部暴力”,预处理一些信息并保存起来,用空间换时间,分块更加通用、容易实现。

经典例题:

例1: 数列分块入门 1

题意:给出一个长为 $n(1 \le n\le 50000)$ 的数列,以及 $n$ 个操作,操作涉及区间加法,单点查值。

分析:可以利用树状数组和线段树在 $O(N\log{N})$ 的时间解决,现在我们使用分块解决本问题。

首先我们设块长为 $L$,那么块的个数就是 $t=\left \lceil n/L \right \rceil \approx n/L $ 。对于任意一个区间 $(l,r)$,区间内整段只需要对其 $lazy$ 标记数组修改,对于开头、结尾不足整段的部分进行朴素修改,单次区间修改复杂度可以表示为 $O(L+t)$,那么根据不等式的性质:

$$L+t=L+n/L \ge 2 \times \sqrt{L*(n/L)}=2\sqrt{n}$$

当 $L=n/L$ 时,不等式等号成立,即 $L=\sqrt{n}$ 。

$n$ 次修改复杂度为 $O(n\sqrt{n})$, 单点询问复杂度 $O(1)$.

参考代码:点击

例2: 数列分块入门 2

题意:给出一个长为 $n(1 \le n\le 50000)$ 的数列,以及 $n$ 个操作,操作涉及区间加法,询问区间内小于某个值 $x$ 的元素个数。

分析:询问区间内小于 $x$ 的个数,如果不带修改,可以利用主席树解决,带上修改后,主席树维护起来也很困难,考虑使用分块。

分块后,可以将块内元素排序(不破坏原序列,使用辅助数组 或 vector),当询问时,整块内可以二分查找快速解决,开头和结尾部分朴素查询,那么单次询问复杂度就是 $O(L+t*\log{L})$ .

区间修改,对于整块,直接修改 $lazy$ 标记,开头和结尾部分朴素修改,然后重构辅助数组。

参考代码:点击

例3:P4168蒲公英

题意:给定一个长度为 $n$ 的序列, $m$ 次询问区间众数。$(1 \leq n \leq 40000,1 \leq m \leq 50000,1S,512M)$

本题是经典的在线求区间众数的问题(不修改,只询问,在线)。区间众数不具有“区间可加性”,用树状数组、线段树维护就很困难。可以用分块加上计数桶数组的思想解决。

定义 $s[i][j]$ 前 $i$ 块 $j$ 出现的次数,$f[i][j]$ 第i块到第j块的众数,提前预处理计算出这两个数组,时间复杂度$O(\sqrt{N}|a_i|+\sqrt{N}\times \sqrt{N} \times \sqrt{N})$,$|a_i|$ 表示 $a_i$ 的值域,离散化后就是 $N$

需要使用一个临时计数数组 $t[j]$ 记录 $j$ 出现的次数。为了清零,不要每次使用的时候都memset,使用完后,修改了那一段整队那一段清零。

询问$[l,r]$区间众数,如果 $p=l/len,q=r/len$( $p$,$q$ 表示所处的块编号),第 $p+1$ 到 $q-1$ 块是整段包含的,众数就是 $f[i][j]$, 局部$[l,ed[p])$和$[st[q],r]$扫描每一个数,计算其出现的次数,保留出现次数最多的数就是答案,查询时间复杂度就是 $O(m \times ( \sqrt{N}+ \sqrt{N}))$

参考代码:点击


其他例题:

P3372 【模板】线段树 1

//分块实现区间修改、区间查询
//线段树模板-1 #include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const int T=1000;
int n,m,a[N],belong[N];
int t,len; //t块 =ceil(sqrt(t))
long long sum[T],add[T],st[T],ed[T];
//belong[i] 表示a[i] 处于第几块
//st[t]、ed[t] 表示第t快左端点、右端点 对应原数组下标
void init()
{
len=sqrt(n);
t=len;
for(int i=1;i<=t;i++)
{
st[i]=(i-1)*len+1;
ed[i]=i*len;
}
if(ed[t]<n)
{
t++;
st[t]=ed[t-1]+1;
ed[t]=n;
}
for(int i=1;i<=t;i++)
for(int j=st[i];j<=ed[i];j++)
{
belong[j]=i;
sum[i]+=a[j];
}
}
void modify(int l,int r,int d)
{
int p=belong[l],q=belong[r];
if(p==q)
{
for(int i=l;i<=r;i++)a[i]+=d;
sum[p]+=(r-l+1)*d;
}
else
{
for(int i=p+1;i<=q-1;i++)add[i]+=d; for(int i=l;i<=ed[p];i++)a[i]+=d;
sum[p]+=(ed[p]-l+1)*d; for(int i=st[q];i<=r;i++)a[i]+=d;
sum[q]+=(r-st[q]+1)*d;
}
}
long long query(int l,int r)
{
int p=belong[l],q=belong[r];
long long ret=0;
if(p==q)
{
for(int i=l;i<=r;i++)ret+=a[i];
ret+=(r-l+1)*add[p];
}
else
{
for(int i=p+1;i<=q-1;i++)ret+=sum[i]+add[i]*(ed[i]-st[i]+1);
for(int i=l;i<=ed[p];i++)ret+=a[i];
ret+=add[p]*(ed[p]-l+1);
for(int i=st[q];i<=r;i++)ret+=a[i];
ret+=add[q]*(r-st[q]+1);
}
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",a+i); init(); while(m--)
{
int op,x,y,k;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&x,&y,&k);
modify(x,y,k);
}
else
{
scanf("%d%d",&x,&y);
printf("%lld\n",query(x,y));
}
}
return 0;
}

P2801教主的魔法

题意:两种操作:

1.给区间$[l,r]$加一个数$c$;

2.查询区间$[l,r]$大于等于$c$的个数

分析:可以使用分块,每一块内排序,块内是有序的,可以利用二分查找,找的大于等于$c$的个数,但是又不能在原始序列上排序,否则修改的到块的内部,就没办法修改了,可以利用增加一个辅助数组,长度与原始数组相等,在辅助数组内进行排序。

假如分成$num$块,则块长度为$n/num$,块内直接暴力修改、查询,块整体修改,只需要在“增量数组”上修改就可以了,查询的时候在辅助有序数组上二分查找。q次修改、查询,时间复杂度就为:$O(q\sqrt{n} \log_{}{n})$

参考代码: 点击

本质就是区间第 $k$ 大问题,对于静态区间第 $k$ 大,使用可持久化线段树效率更高,具体可以参考 线段树2。

P4135作诗

题意:给定长度为 $n$ 的整数序列,$m$ 次询问区间 $[l,r]$ 中出现正偶数次的数的个数。($1 \leq n,m \leq 10^5,512M$)

预处理出:$s[i][j]$ 为前 $i$ 块中 $j$ 出现的次数,$f[i][j]$ 为第 $i$ 块到第 $j$ 块中出现偶数次的数的个数。

P5048 Ynoi2019 模拟赛 Yuno loves sqrt technology III

题意:给你一个长为 $n$ 的序列 $a$,$m$ 次询问,每次查询一个区间的众数的出现次数,强制在线。($1 \leq n,m \leq 10^5,2S,62M$)

本题可以用蒲公英相同的思路解决。

其他分块练习题:

1.P5046 [Ynoi2019 模拟赛] Yuno loves sqrt technology I

题意:给你一个长为 $n$ 的排列,$m$ 次询问,每次查询一个区间的逆序对数,强制在线。

2.P5047 [Ynoi2019 模拟赛] Yuno loves sqrt technology II

题意:给你一个长为 $n$ 的序列 $a$,$m$ 次询问,每次查询一个区间的逆序对数。

P6774 [NOI2020] 时代的眼泪

区间正序对加强版,分块+容斥

[P1494 国家集训队]小Z的袜子](https://www.luogu.com.cn/problem/P1494)

题意:给定一个长度为 $N$ 的序列,多次询问 $[l,r]$ 任意抽中两个相同的数概率。

分析:直接利用分块,会T掉,可以利用莫队。

单点移动需要计算,区间 $[l,r]$ 总共的方法数为 $C_{r-l+1}^2$。

抽中相同的方法数为 $sum$,$col[x]$ 表示 $x$ 的个数。

当新增 $x$ ,抽中相同的方法数 $sum+=col[x]$,然后 $col[x]++$.

当删除 $x$ ,先$col[x]++$, 相同的方法数 $sum-=col[x]$.

参考代码 :点击

分块-byx的更多相关文章

  1. PHP搭建大文件切割分块上传功能

    背景 在网站开发中,文件上传是很常见的一个功能.相信很多人都会遇到这种情况,想传一个文件上去,然后网页提示"该文件过大".因为一般情况下,我们都需要对上传的文件大小做限制,防止出现 ...

  2. POJ2104 K-th Number [分块做法]

    传送:主席树做法http://www.cnblogs.com/candy99/p/6160704.html 做那倒带修改的主席树时就发现分块可以做,然后就试了试 思想和教主的魔法差不多,只不过那个是求 ...

  3. HDU 4467 分块

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4467 题意:给定n个点m条边的无向图,点被染色(黑0/白1),边带边权.然后q个询问.询问分为两种: ...

  4. 2016 ACM/ICPC Asia Regional Dalian Online 1010 Weak Pair dfs序+分块

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submissio ...

  5. CC countari & 分块+FFT

    题意: 求一个序列中顺序的长度为3的等差数列. SOL: 对于这种计数问题都是用个数的卷积来进行统计.然而对于这个题有顺序的限制,不好直接统计,于是竟然可以分块?惊为天人... 考虑分块以后的序列: ...

  6. bzoj2002弹(dan)飞绵羊 分块水过

    据说是道lct求深度的题 但是在小猫大的指点下用分块就n^1.5水过了 = =数据忘记加强系列 代码极其不美观,原因是一开始是听小猫大讲的题意,还以为是弹到最前面... #include <cs ...

  7. C语言两种查找方式(分块查找,二分法)

    二分法(必须要保证数据是有序排列的):   分块查找(数据有如下特点:块间有序,块内无序):    

  8. [New Portal]Windows Azure Storage (14) 使用Azure Blob的PutBlock方法,实现文件的分块、离线上传

    <Windows Azure Platform 系列文章目录> 相关内容 Windows Azure Platform (二十二) Windows Azure Storage Servic ...

  9. BZOJ 3343: 教主的魔法 [分块]【学习笔记】

    3343: 教主的魔法 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1172  Solved: 526[Submit][Status][Discus ...

  10. CodeChef - QCHEF 分块

    题目链接:http://vjudge.net/problem/174774/origin 题意:给定一个长度为n的序列a[],序列的值不大于m,现在有k个询问,每个询问给定(l,r).让你求出max{ ...

随机推荐

  1. 树莓派设置CPU运行的核心数为3,保留核心4号

    具体步骤:1.打开终端,输入 sudo nano /boot/cmdline.txt2.在第一行最后空一格加上isolcpus=33.保存

  2. MYSQL8给新用户grant权限报错的解决方法

    ​MYSQL8用客户端创建用户,无法grant,报错:Access denied for user 'root'@'xxx.xxx.xxx.xxx' (using password: YES) . 解 ...

  3. Powershell 源码批判

    代码里充斥着过程式编程的搞法:比如这里 Utils.PathIsUnc,分散的到处都是 internal static IEnumerable<string> GetDefaultAvai ...

  4. 2024年1月Java项目开发指南5:controller、service、mapper

    准备工作 你知道什么是JSON吗? JSON是什么? 格式是什么? 有什么用? 有什么优点? 有什么缺点? 请自己百度探索一下,对JSON做了个了解,如果你不知道什么是JSON的话,知道就免了,直接下 ...

  5. Docker学习笔记(一) - Docker安装

    1.安装yum-utils yum install yum-utils device-mapper-persistent-data lvm2 复制 安装yum-utils是为方便添加yum源使用的,d ...

  6. Qt编写安防视频监控系统53-串口配置

    一.前言 视频监控系统中,除了核心的显示实时视频以外,可能还需要配合串口网络通信之类的,用于通过指令数据收到和硬件交互,比如机器人监控系统中,除了实时显示机器人移动监控画面以外,还通过多个串口和下面的 ...

  7. Qt编写地图综合应用25-echart动态交互

    一.前言 之前用echart组件做过各种效果,随着各种现场应用现场项目的增多,各种需求也都慢慢增加起来,为了满足各种不同类型的需求,近期又抽空重新整理和封装了echart类,主要就是增加了不少的js函 ...

  8. 微信小程序开发基础详解

    1.结构 util.js      工具类 app.js          全局工具函数 app.json      小程序配置 app.wxss     全局样式 2.生命周期 onLoad(opt ...

  9. 用领域驱动DDD的方式实现购物车-基于abp一代6.2

    废话 之前七七八八看了些DDD相关概念,充血模型.领域事件.领域服务.应用服务等,大致能理解但从未实践.最近在用ABP做个电商模块,尝试用DDD方式来实现购物车功能,感觉还行,下面做个记录. 业务分析 ...

  10. c# WPF convert photo to Sketch effects

    using the online website https://imagetosketch.com/ <Window x:Class="WpfMosaic.PhotoSketchWi ...