分块(简单版树状数组,线段树)
前言
首先,在NOIP的比赛里分块是一个很好的水分神器,因为它可以代替树状数组,线段树,但是如果出题人要卡你的程序的话......
分块思想
包含n个元素的整数数组A,每次可以 C(i, j) : 修改一个元素A[i] = j Q(i, j) : 询问A[i]+A[i+1]+…+A[j]的值
如何设计算法,使得修改和询问操作的时间复杂度尽量低? 显然存在修改O(1),查询O(n)的算法。
每次重新计算,一些未被修改区间也经常被重复求和,于是我们可以将A[1..n]均分成sqrt(n)块,每块内部的元素为sqrt(n)个。
修改操作时只需要修改A[i]及A[i]所在的块。
询问操作时是需要枚举i和j所在的块内部,及其之间的块。
时间复杂度在O(sqrt(n))级别。
主要思想就是将待操作的长度为N的区间分成大小为sqrt(N)的块,然后实现各种操作……
一些常用定义:
MAGIC:定义一个块的大小,如字面意思,一个莫名其妙的数字……
于是,我们把一段长度为N的区间,分成了若干长度为 MAGIC 的区间:[0,magic),[magic, 2magic)....
于是易得,i / MAGIC 就是点 i 所在块的编号,若 i % MAGIC == 0,则证明由点 i 开始是一个新区间
一般来讲,我们在预处理和修改的时候,维护两个信息,一个是序列,另一个是块
例题
讲了这么多还是来看例题吧......
链接点我!!!
#6277. 数列分块入门 1
题目描述
给出一个长为 n的数列,以及 n 个操作,操作涉及区间加法,单点查值。
输入格式
第一行输入一个数字 n。
第二行输入 n 个数字,第 i 个数字为 ai,以空格隔开。
接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。
若 opt=0,表示将位于 [l,r] 的之间的数字都加 c。
若 opt=1,表示询问 ar 的值(l 和 c 忽略)。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入
4
1 2 2 3
0 1 3 1
1 0 1 0
0 1 2 2
1 0 2 0
样例输出
2
5
数据范围与提示
对于 100% 的数据,1≤n≤50000,−231≤others、ans≤231−1。
题解:
(建议大家边看程序边题解)
这是一题区间修改,单点查询可以用树状数组,线段树(这不是放*吗)
但是我们在这里考虑分块;
首先,我们开一个最普通的数组来记录每个元素的权值;
然后再开一个数组来记录每个元素所对应的分块;
然后再再(语文有点不好......)开一个数组来记录每个分块要加的值;
每次寻找 l , r ,之间的区间,在分块内部的直接打上标记;
如果在分块外面的直接暴力修改;
嗯,代码......
1 //NOIPRP++ 2 #include<bits/stdc++.h> 3 #define Re register int 4 using namespace std; 5 int N,a[50005],f[50005],opt,l,r,c,Sqr,Tage[50005]; 6 inline void read(int &x){ 7 x=0; char c=getchar(); bool p=1; 8 for (;'0'>c||c>'9';c=getchar()) if (c=='-') p=0; 9 for (;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48); 10 p?:x=-x; 11 } 12 inline void Add(int l,int r,int c){ 13 for (Re i=l;i<=min(f[l]*Sqr,r);i++) a[i]+=c; 14 if (f[l]^f[r]) for (Re i=(f[r]-1)*Sqr+1;i<=r;i++) a[i]+=c; 15 for (Re i=f[l]+1;i<=f[r]-1;i++) Tage[i]+=c; 16 } 17 int main(){ 18 Re i,j; 19 read(N);Sqr=sqrt(N); 20 for (i=1;i<=N;i++) f[i]=(i-1)/Sqr+1; 21 for (i=1;i<=N;i++) read(a[i]); 22 for (i=1;i<=N;i++){ 23 read(opt);read(l);read(r);read(c); 24 if (opt==0) Add(l,r,c); 25 if (opt==1) printf("%d\n",a[r]+Tage[f[r]]); 26 } 27 return 0; 28 } 29 //NOIPRP++
这里由于博主懒,所以就不再讲其他扩展的例题了,如果有大佬还想要更多有关分块的好题的话请点我,当然也不能少了这些题目的题解......