前言
这是我个人使用的一些模板封装,限于个人能力,可能存在诸多不足与漏洞,在未加测试直接使用前请务必小心谨慎。更新可能会滞后于我本地的文档,如有疑问或者催更之类的可以在评论区留言。
全文模板测试均基于以下版本信息,请留意版本兼容问题。
Windows, 64bit
G++ (ISO C++20)
stack=268435456
开启O2优化
树状数组部分
树状数组
struct BIT {
int n;
vector<int> w;
BIT() {}
BIT(int n) {
this->n = n; // 这里必须写 n ,否则会RE
w.resize(n + 1);
}
void add(int x, int k) {
for (; x <= n; x += x & -x) {
w[x] += k;
}
}
void add(int x, int y, int k) {
add(x, k), add(y, -k);
}
int ask(int x) {
int ans = 0;
for (; x; x -= x & -x) {
ans += w[x];
}
return ans;
}
int ask(int x, int y) {
return ask(y) - ask(x - 1);
}
int kth(int k) { // 查找第k大的值
int ans = 0;
for (int i = __lg(n); i >= 0; i--) {
int val = ans + (1 << i);
if (val < n && w[val] < k) {
k -= w[val];
ans = val;
}
}
return ans + 1;
}
};
树状数组套树状数组(二维树状数组)1
请注意,该版本不能同时进行区间修改+区间查询。无离散化版本的空间占用为 \(\mathcal O(NM)\) 、建树复杂度为 \(\mathcal O(NM)\) 、单次查询复杂度为 \(\mathcal O(\log N\cdot \log M)\) 。
大致有以下两种写法,均通过模板题测试。
该部分模板题可参考:LOJ #133. 二维树状数组 1:单点修改,区间查询、LOJ #134. 二维树状数组 2:区间修改,单点查询。
借助一维树状数组进行拓展
struct BIT_2D {
struct BIT {
int n;
vector<int> w;
BIT() {}
BIT(int n) {
this->n = n; // 这里必须写 n ,否则会RE
w.resize(n + 1);
}
void add(int x, int k) {
for (; x <= n; x += x & -x) {
w[x] += k;
}
}
int ask(int x) {
int ans = 0;
for (; x; x -= x & -x) {
ans += w[x];
}
return ans;
}
};
int n;
vector<BIT> w;
BIT_2D() {}
BIT_2D(int n, int m) {
this->n = n;
w.resize(n + 1);
for (int i = 1; i <= n; i++) {
w[i] = BIT(m);
}
}
void add(int x, int y, int k) {
for (; x <= n; x += x & -x) {
w[x].add(y, k);
}
}
void add(int x, int y, int X, int Y, int k) { // 区块修改:二维差分
X++, Y++;
add(x, y, k), add(X, y, -k);
add(X, Y, k), add(x, Y, -k);
}
int ask(int x, int y) { // 单点查询
int ans = 0;
for (; x; x -= x & -x) {
ans += w[x].ask(y);
}
return ans;
}
int ask(int x, int y, int X, int Y) { // 区块查询:二维前缀和
x--, y--;
return ask(X, Y) - ask(x, Y) - ask(X, y) + ask(x, y);
}
};
压缩优化
struct BIT_2D {
int n, m;
vector<vector<int>> w;
BIT_2D(int n, int m) : n(n), m(m) {
w.resize(n + 1, vector<int>(m + 1));
}
void add(int x, int y, int k) {
for (int i = x; i <= n; i += i & -i) {
for (int j = y; j <= m; j += j & -j) {
w[i][j] += k;
}
}
}
void add(int x, int y, int X, int Y, int k) { // 区块修改:二维差分
X++, Y++;
add(x, y, k), add(X, y, -k);
add(X, Y, k), add(x, Y, -k);
}
int ask(int x, int y) { // 单点查询
int ans = 0;
for (int i = x; i; i -= i & -i) {
for (int j = y; j; j -= j & -j) {
ans += w[i][j];
}
}
return ans;
}
int ask(int x, int y, int X, int Y) { // 区块查询:二维前缀和
x--, y--;
return ask(X, Y) - ask(x, Y) - ask(X, y) + ask(x, y);
}
};
树状数组套树状数组(二维树状数组)2
该版本支持全部操作。但是全部复杂度均比上一个版本多 \(4\) 倍。
这里仅提供压缩优化版。
该部分模板题可参考:LOJ #135. 二维树状数组 3:区间修改,区间查询。
struct BIT_2D {
int n, m;
vector<vector<int>> b1, b2, b3, b4;
BIT_2D(int n, int m) : n(n), m(m) {
b1.resize(n + 1, vector<int>(m + 1));
b2.resize(n + 1, vector<int>(m + 1));
b3.resize(n + 1, vector<int>(m + 1));
b4.resize(n + 1, vector<int>(m + 1));
}
void add(auto &w, int x, int y, int k) { // 单点修改
for (int i = x; i <= n; i += i & -i) {
for (int j = y; j <= m; j += j & -j) {
w[i][j] += k;
}
}
}
void add(int x, int y, int k) { // 多了一步计算
add(b1, x, y, k);
add(b2, x, y, k * (x - 1));
add(b3, x, y, k * (y - 1));
add(b4, x, y, k * (x - 1) * (y - 1));
}
void add(int x, int y, int X, int Y, int k) { // 区块修改:二维差分
X++, Y++;
add(x, y, k), add(X, y, -k);
add(X, Y, k), add(x, Y, -k);
}
int ask(auto &w, int x, int y) { // 单点查询
int ans = 0;
for (int i = x; i; i -= i & -i) {
for (int j = y; j; j -= j & -j) {
ans += w[i][j];
}
}
return ans;
}
int ask(int x, int y) { // 多了一步计算
int ans = 0;
ans += x * y * ask(b1, x, y);
ans -= y * ask(b2, x, y);
ans -= x * ask(b3, x, y);
ans += ask(b4, x, y);
return ans;
}
int ask(int x, int y, int X, int Y) { // 区块查询:二维前缀和
x--, y--;
return ask(X, Y) - ask(x, Y) - ask(X, y) + ask(x, y);
}
};
标签:树套,树状,int,vector,resize,数组,BIT,数据结构,高维
From: https://www.cnblogs.com/WIDA/p/17592060.html