分块

分块算法简介

分块(Square Root Decomposition)是一种将数据分成若干块,通过预处理和分块处理来优化区间操作的数据结构。它在信息学奥赛中广泛应用于解决区间查询和更新问题,是平衡代码复杂度和时间效率的利器。

分块的核心思想是将数据分成大小为√n的块,每个块维护一些预处理信息(如区间和、最大值等),从而将区间操作的时间复杂度从O(n)降低到O(√n)。


分块的核心思想

  1. 数据分块:将长度为n的数组分成√n个块,每个块的大小为√n。
  2. 预处理:对每个块维护一些统计信息(如区间和、最大值等)。
  3. 区间操作
    • 对于完整的块,直接利用预处理信息快速计算。
    • 对于不完整的块(残块),暴力处理。
  4. 复杂度平衡:通过分块,将区间操作的时间复杂度从O(n)降低到O(√n)。

分块的实现步骤

以区间求和为例

const int MAXN = 1e5 + 5;
const int BLOCK_SIZE = 350; // √1e5 ≈ 316,取稍大值

int a[MAXN];         // 原始数组
int sum[BLOCK_SIZE]; // 每个块的和
int tag[BLOCK_SIZE]; // 每个块的懒标记
int bel[MAXN];       // 每个元素所属的块

// 初始化分块
void init(int n) {
    int block_num = (n + BLOCK_SIZE - 1) / BLOCK_SIZE;
    for (int i = 1; i <= n; i++) {
        bel[i] = (i - 1) / BLOCK_SIZE + 1;
        sum[bel[i]] += a[i];
    }
}

// 区间更新
void update(int l, int r, int val) {
    // 处理左残块
    while (l <= r && bel[l] == bel[l - 1]) {
        a[l] += val;
        sum[bel[l]] += val;
        l++;
    }
    // 处理整块
    while (bel[l] < bel[r]) {
        sum[bel[l]] += val * BLOCK_SIZE;
        tag[bel[l]] += val;
        l += BLOCK_SIZE;
    }
    // 处理右残块
    while (l <= r) {
        a[l] += val;
        sum[bel[l]] += val;
        l++;
    }
}

// 区间查询
int query(int l, int r) {
    int res = 0;
    // 处理左残块
    while (l <= r && bel[l] == bel[l - 1]) {
        res += a[l] + tag[bel[l]];
        l++;
    }
    // 处理整块
    while (bel[l] < bel[r]) {
        res += sum[bel[l]] + tag[bel[l]] * BLOCK_SIZE;
        l += BLOCK_SIZE;
    }
    // 处理右残块
    while (l <= r) {
        res += a[l] + tag[bel[l]];
        l++;
    }
    return res;
}
posted @ 2025-02-27 22:25  健康铀  阅读(45)  评论(0)    收藏  举报