【数据结构-分块】分块
引入
观看例题,这是一个区修点查问题。
如果暴力操作是 \(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 ;
}

浙公网安备 33010602011771号