分块
概念讲解
什么是分块?
将数组分成 块,每块大小 ,在块上维护信息。
时间复杂度
| 操作 | 时间复杂度 |
|---|---|
| 单点修改 | O(1) |
| 区间修改 | O(√n) |
| 区间查询 | O(√n) |
实现
123456789101112131415161718192021222324252627282930313233343536const int N = 100005;
int a[N], block[N], lazy[N];
int blockSize, n;
void build() {
blockSize = sqrt(n);
for (int i = 0; i < n; i++) {
block[i / blockSize] += a[i];
}
}
void update(int l, int r, int c) {
int bl = l / blockSize, br = r / blockSize;
if (bl == br) {
for (int i = l; i <= r; i++) {
a[i] += c;
block[bl] += c;
}
} else {
for (int i = l; i < (bl+1)*blockSize; i++) a[i] += c, block[bl] += c;
for (int i = bl+1; i < br; i++) lazy[i] += c;
for (int i = br*blockSize; i <= r; i++) a[i] += c, block[br] += c;
}
}
int query(int l, int r) {
int ans = 0, bl = l / blockSize, br = r / blockSize;
if (bl == br) {
for (int i = l; i <= r; i++) ans += a[i] + lazy[bl];
} else {
for (int i = l; i < (bl+1)*blockSize; i++) ans += a[i] + lazy[bl];
for (int i = bl+1; i < br; i++) ans += block[i] + lazy[i] * blockSize;
for (int i = br*blockSize; i <= r; i++) ans += a[i] + lazy[br];
}
return ans;
}考点分析
初赛考查方式
- 程序阅读: 分块程序
- 编程题: 区间操作
常见考点
- 分块思想
- 区间操作
- 复杂度分析
练习题
- 分块的时间复杂度是多少?
查看答案
分块的时间复杂度:
- 单点修改:
- 区间修改:
- 区间查询:
- 分块和线段树的区别?
查看答案
| 特性 | 分块 | 线段树 |
|---|---|---|
| 时间复杂度 | ||
| 实现难度 | 简单 | 较复杂 |
| 空间复杂度 | ||
| 灵活性 | 高 | 中等 |
分块更适合区间修改,线段树更适合单点修改和区间查询。
- 什么情况下用分块?
查看答案
分块适用于:
- 区间修改:需要对区间进行加、减等操作
- 区间查询:需要查询区间的和、最值等
- 实现简单:比线段树更容易实现
- 数据范围适中: 左右
易错点
⚠️ 注意:
- 块大小取 sqrt(n)
- 散块要暴力处理
- lazy 标记要及时下传
- 分块比线段树好写