概念
严谨来说,分块是一种思想,而不是一种数据结构。
分块的基本思想是,通过对原数据的适当划分,并在划分后的每一个块上预处理部分信息,从而较一般的暴力算法取得更优的时间复杂度。
分块的时间复杂度主要取决于分块的块长,一般可以通过均值不等式求出某个问题下的最优块长,以及相应的时间复杂度,我们一般取根号相关的值。
分块是一种很灵活的思想,相较于树状数组和线段树,分块的优点是通用性更好,可以维护很多树状数组和线段树无法维护的信息。
模板
int Bnum; // 得到每个组的元素的数量
int get_gid(int x) {
return x / Bnum;
}
int get_gl(int x) {
return max(get_gid(x) * Bnum, 1);
}
int get_gr(int x) {
return min(get_gid(x) * Bnum + Bnum - 1, n);
}
例题
单点修改,区间查询
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
int T = ceil(sqrt(n));
vector<int> v(n + 1);
for (int i = 1; i <= n; i++)cin >> v[i];
vector<int> vt(n / T+1);
for (int i = 1; i <= n; i++)vt[i / T] += v[i];
int m;
cin >> m;
while (m--) {
int ch;
cin >> ch;
if (ch == 1) {
int x, a;
cin >> x >> a;
v[x] += a;
vt[x / T] += a;
} else {
int a, b;
cin >> a >> b;
int sum = 0;
if (a / T == b / T)for (int i = a; i <= b; i++)sum += v[i];
else {
for (int i = a; i < a / T * T + T; i++)sum += v[i];
for (int i = a / T + 1; i < b / T; i++)sum += vt[i];
for (int i = b / T * T; i <= b; i++)sum += v[i];
}
cout << sum << endl;
}
}
return 0;
}
区间修改、区间求和
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
int n,q;cin>>n>>q;
int t=ceil(sqrt(n));
vector<int> arr(n+1);
vector<int> sum(n/t+1);
vector<int> add(n/t+1);
for(int i=1;i<=n;i++)cin>>arr[i],sum[i/t]+=arr[i];
while(q--){
int choice;cin>>choice;
if(choice==1){
int l,r,k;
cin>>l>>r>>k;
if(l/t==r/t) {
for(int i=l;i<=r;i++)arr[i]+=k;
sum[l/t]+=(r-l+1)*k;
}
else{
for(int i=l;i<l/t*t+t;i++)arr[i]+=k,sum[l/t]+=k;
for(int i=l/t+1;i<r/t;i++)add[i]+=k;
for(int i=r/t*t;i<=r;i++)arr[i]+=k,sum[r/t]+=k;
}
}
else{
int l,r;cin>>l>>r;
int ans=0;
if(l/t==r/t) {
for(int i=l;i<=r;i++)ans+=arr[i]+add[i/t];
}
else{
for(int i=l;i<l/t*t+t;i++)ans+=arr[i]+add[i/t];
for(int i=l/t+1;i<r/t;i++)ans+=sum[i]+add[i]*t;
for(int i=r/t*t;i<=r;i++)ans+=arr[i]+add[i/t];
}
cout<<ans<<endl;
}
}
return 0;
}
区间最大值
#include <bits/stdc++.h>
using namespace std;
signed main(){
int n,q;cin>>n>>q;
int t=ceil(sqrt(n));
vector<int> arr(n+1);
vector<int> vmax(n/t+1);
for(int i=1;i<=n;i++){
cin>>arr[i];
vmax[i/t]=max(vmax[i/t],arr[i]);
}
while (q--){
int l,r;cin>>l>>r;
int ans=-1e9;
if(l/t==r/t)for(int i=l;i<=r;i++)ans=max(ans,arr[i]);
else{
for(int i=l;i<l/t*t+t;i++)ans=max(ans,arr[i]);
for(int i=l/t+1;i<r/t;i++)ans=max(ans,vmax[i]);
for(int i=r/t*t;i<=r;i++)ans=max(ans,arr[i]);
}
cout<<ans<<endl;
}
return 0;
}