多层分块
简介
本篇题解以双层分块例,讲解了多层分块解决本题的方法。
双层分块
算法流程
将序列分块后,对散块暴力,剩下的问题又变回了单点修改、区间求和。于是可以将每个块看着整体,权值为块内数的和,再次进行分块。本篇题解提供一种简洁的写法。
首先取一个
对于第一层,第
记
用
考虑查询
对于查询区间和,差分为两个后缀即可。
代码实现:
// d(x)=x/(2^7)=x>>7
// 求 [x,n] 的和
int ask(int x) { return s1[x] + s2[x >> 7] + s3[x >> 14]; }
// 求 [l,r] 的和
int ask(int l, int r) { return ask(l) - ask(r + 1); }
考虑加
- 对于
A ,只有和x 同块且i\le x 的有影响。对于i\in[d(x)B,x],A_i\gets A_i+y 。 - 对于
B ,只有和d(x) 同块且i+1\le d(x) 的有影响。对于i\in[d(d(x))B,d(x)\boldsymbol),B_i\gets A_i+y 。 - 对于
C ,只有i+1\le d(d(x)) 的有影响。对于i\in[0,d(d(x))\boldsymbol),C_i\gets A_i+y 。
代码实现:
void upd(int x, int y) {
REP(i, x >> 7 << 7, x) s1[i] += y;
REP(i, x >> 14 << 7, (x >> 7) - 1) s2[i] += y;
REP(i, 0, (x >> 14) - 1) s3[i] += y;
}
考虑时间复杂度。查询复杂度显然为
代码实现
#include <bits/stdc++.h>
#define REP(i, l, r) for (int i = (l); i <= (r); ++ i)
#define DEP(i, r, l) for (int i = (r); i >= (l); -- i)
#define fi first
#define se second
#define pb emplace_back
#define mems(x, v) memset((x), (v), sizeof(x))
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(), (x).end()
using namespace std;
namespace Milkcat {
typedef long long LL;
typedef pair<LL, LL> pii;
const int N = 5e5 + 5;
namespace BLK {
int s1[N], s2[N], s3[N];
void upd(int x, int y) {
REP(i, x >> 7 << 7, x) s1[i] += y;
REP(i, x >> 14 << 7, (x >> 7) - 1) s2[i] += y;
REP(i, 0, (x >> 14) - 1) s3[i] += y;
}
int ask(int x) { return s1[x] + s2[x >> 7] + s3[x >> 14]; }
int ask(int l, int r) { return ask(l) - ask(r + 1); }
}
int n, q, o, x, y;
int main() {
cin >> n >> q;
REP(i, 1, n) cin >> x, BLK::upd(i, x);
REP(te, 1, q) {
cin >> o >> x >> y;
if (o == 1) BLK::upd(x, y);
if (o == 2) cout << BLK::ask(x, y) << '\n';
}
return 0;
}
}
int main() {
cin.tie(0)->sync_with_stdio(0);
int T = 1;
while (T --) Milkcat::main();
return 0;
}
多层分块
算法流程
对于
维护
修改时,
查询时,对于
考虑复杂度,查询为
代码实现
这是本题三层分块的实现,取
#include <bits/stdc++.h>
#define REP(i, l, r) for (int i = (l); i <= (r); ++ i)
#define DEP(i, r, l) for (int i = (r); i >= (l); -- i)
#define fi first
#define se second
#define pb emplace_back
#define mems(x, v) memset((x), (v), sizeof(x))
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(), (x).end()
using namespace std;
namespace Milkcat {
typedef long long LL;
typedef pair<LL, LL> pii;
const int N = 5e5 + 5;
namespace BLK {
int s1[N], s2[N], s3[N], s4[N];
void upd(int x, int y) {
REP(i, x >> 5 << 5, x) s1[i] += y;
REP(i, x >> 10 << 5, (x >> 5) - 1) s2[i] += y;
REP(i, x >> 15 << 5, (x >> 10) - 1) s3[i] += y;
REP(i, 0, (x >> 15) - 1) s4[i] += y;
}
int ask(int x) { return s1[x] + s2[x >> 5] + s3[x >> 10] + s4[x >> 15]; }
int ask(int l, int r) { return ask(l) - ask(r + 1); }
}
int n, q, o, x, y;
int main() {
cin >> n >> q;
REP(i, 1, n) cin >> x, BLK::upd(i, x);
REP(te, 1, q) {
cin >> o >> x >> y;
if (o == 1) BLK::upd(x, y);
if (o == 2) cout << BLK::ask(x, y) << '\n';
}
return 0;
}
}
int main() {
cin.tie(0)->sync_with_stdio(0);
int T = 1;
while (T --) Milkcat::main();
return 0;
}