【数据结构-分块】分块

引入

观看例题,这是一个区修点查问题。

如果暴力操作是 \(O(n^2)\) 的,也就是 \(2.5 \times 10^9\)。

考虑一部分操作是重复的:

\[\text{Pic}_1 \]

可以对一部分进行记忆化/懒标记。

那么需要将其分成块。

定义及思想

将一个数列分成 \(k\) 块,从而对每个块进行记忆化和懒标记。

作用及实现

一次操作的复杂度从 \(O(n)\) 变成了 \(O(k)\)。

使用均值不等式求证 \(k = \sqrt{n}\) 时最优。

那么将一个数列分成 \(\lceil\sqrt{n}\rceil\) 个块,每个块中至多有 \(\lfloor\sqrt{n}\rfloor\) 个数。

\[\text{Pic}_2 \]

在修改区间 \([l, r]\) 的时候分讨:

  • \(idx_l = idx_r\):如 \(\text{Pic}_1\) 中第 \(3\) 个更改:直接朴素地更改 \(val\),再将本段 \(sum\) 增加;
  • 否则:如 \(\text{Pic}_1\) 中第 \(1\)、\(2\)、\(4\) 或 \(6\) 个更改:设 \(l\) 处于第 \(p\) 块, \(r\) 处于第 \(q\) 块,对于开头结尾两个不足一段的部分朴素地操作(像第一个一样),而中间的整块部分分别更改 \(sum\) 和 \(upd\)。

查询基本相同。

例题

点击查看代码
/*
compiling in 
standard C++14 -O2
ide VScode
g++ test.cpp -o test && ./test
*/
#include <bits/stdc++.h>
#include <bits/extc++.h>
namespace {
#define filein(x) freopen(x".in", "r", stdin)
#define fileout(x) freopen(x".out", "w", stdout)
#define file(x) filein(x), fileout(x)
using namespace std;
using namespace __gnu_pbds;
#define ll long long
#define db double
#define un unsigned
#define ui un int
#define ull un ll
#define udb un db
template <typename T>
using pr = pair<T, T>;
#define pii pr<int>
#define pll pr<ll>
#define pdb pr<db>
#define fir first
#define sec second
#define mp(x, y) make_pair(x, y)
const int man = 5e4+10, sqn = 225;
class Blocking {
public:
    int n, k, cnt = 1;
    ll a[man], idx[man], tag[sqn];
    ll sum[sqn];
    void build () {
        for (int i = 1; i <= n; ++ i) {
            scanf("%lld", a+i);
            idx[i] = cnt, sum[cnt] += a[i];
            if (!(i%int(sqrt(n)))) ++ cnt;
        } return ;
    }
    void add (int l, int r, int x) {
        ll bl = idx[l], br = idx[r];
        if (bl == br) 
            for (ll i = l; i <= r; ++ i) a[i] += x, sum[idx[i]] += x;
        else {
            for (ll i = l; i <= bl*k; ++ i) a[i] += x, sum[idx[i]] += x;
            for (ll i = (br-1)*k+1; i <= r; ++ i) a[i] += x, sum[idx[i]] += x;
            for (ll i = bl+1; i < br; ++ i) tag[i] += x, sum[i] += k*x;
        } return ;
    }
    // ll query (int l, int r) {
    //     int bl = idx[l], br = idx[r];
    //     ll res = 0;
    //     if (bl == br) 
    //         for (int i = l; i <= r; ++ i) res += a[i];
    //     else {
    //         for (int i = l; i <= bl*k; ++ i) res += a[i]+tag[bl];
    //         for (int i = (br-1)*k+1; i <= r; ++ i) res += a[i]+tag[rl];
    //         for (int i = bl+1; i < br; ++ i) res += sum[i];
    //     } return res;
    // }
} B;
}

void pres ();
int main () {
    pres();
    scanf("%d", &B.n);
    B.k = sqrt(B.n);
    B.build();

    for (int f, l, r, c, i = 1; i <= B.n; ++ i) {
        scanf("%d%d%d%d", &f, &l, &r, &c);
        if (!f) B.add(l, r, c);
        else printf("%lld\n", B.a[r]+B.tag[B.idx[r]]);
    } return 0;
}

// --- 

void pres () {
#ifndef ONLINE_JUDGE
    file("test");
#endif
    return ;
}

扩展

posted @ 2023-10-06 18:47  STA_Morlin  阅读(41)  评论(0)    收藏  举报