sparse_fenwick_2d.hpp¶
在坐标稀疏的二维平面上执行点加与矩形和查询;只为实际出现的坐标分配空间。
Complexity: Time: O(p log^2 p) registration/build and O(log^2 p) per point addition, prefix sum, or rectangle sum. Space: O(p log p).
Implementation¶
当前头文件,省略 include guard;依赖见 #include。
/// @complexity Time: O(p log^2 p) registration/build and O(log^2 p) per point
/// addition, prefix sum, or rectangle sum. Space: O(p log p).
#include <algorithm>
#include <cassert>
#include <utility>
#include <vector>
namespace noya {
/// @brief Offline-built sparse two-dimensional Fenwick tree.
/// Register every coordinate that may later be updated, then call build().
/// An x-Fenwick node stores only the registered y-coordinates contributing to
/// it, so the dense coordinate plane is replaced by O(p log p) cells.
template <class T, class Coordinate = int> struct sparse_fenwick_2d {
std::vector<std::pair<Coordinate, Coordinate>> pt;
std::vector<Coordinate> xs;
std::vector<std::vector<Coordinate>> ys;
std::vector<std::vector<T>> dat;
bool ok = false;
/// @brief Remove all registered coordinates and values.
void clear() {
pt.clear();
xs.clear();
ys.clear();
dat.clear();
ok = false;
}
/// @brief Register a coordinate that may be passed to add() after build().
void reserve(Coordinate x, Coordinate y) {
assert(!ok);
pt.emplace_back(x, y);
}
/// @brief Build the compressed Fenwick nodes with every value initially zero.
void build() {
assert(!ok);
xs.reserve(pt.size());
for (auto [x, y] : pt) {
(void)y;
xs.push_back(x);
}
std::sort(xs.begin(), xs.end());
xs.erase(std::unique(xs.begin(), xs.end()), xs.end());
ys.assign(xs.size() + 1, {});
for (auto [x, y] : pt) {
int idx = int(std::lower_bound(xs.begin(), xs.end(), x) - xs.begin());
for (idx++; idx <= int(xs.size()); idx += idx & -idx) {
ys[idx].push_back(y);
}
}
dat.resize(xs.size() + 1);
for (int idx = 1; idx <= int(xs.size()); idx++) {
auto &xs0 = ys[idx];
std::sort(xs0.begin(), xs0.end());
xs0.erase(std::unique(xs0.begin(), xs0.end()), xs0.end());
dat[idx].assign(xs0.size() + 1, T{});
}
pt.clear();
pt.shrink_to_fit();
ok = true;
}
/// @brief Add delta at a coordinate registered before build().
void add(Coordinate x, Coordinate y, const T &dif) {
assert(ok);
auto ix = std::lower_bound(xs.begin(), xs.end(), x);
assert(ix != xs.end() && *ix == x);
int xi = int(ix - xs.begin()) + 1;
for (; xi <= int(xs.size()); xi += xi & -xi) {
auto iy = std::lower_bound(ys[xi].begin(), ys[xi].end(), y);
assert(iy != ys[xi].end() && *iy == y);
int yi = int(iy - ys[xi].begin()) + 1;
for (; yi < int(dat[xi].size()); yi += yi & -yi) {
dat[xi][yi] += dif;
}
}
}
/// @brief Sum values at coordinates (px, py) with px < x and py < y.
T prefix_sum(Coordinate x, Coordinate y) const {
assert(ok);
int xi = int(std::lower_bound(xs.begin(), xs.end(), x) - xs.begin());
T res{};
for (; xi > 0; xi -= xi & -xi) {
int yi = int(std::lower_bound(ys[xi].begin(), ys[xi].end(), y) -
ys[xi].begin());
for (; yi > 0; yi -= yi & -yi) {
res += dat[xi][yi];
}
}
return res;
}
/// @brief Sum values at coordinates (px, py) with px <= x and py <= y.
T prefix_sum_inclusive(Coordinate x, Coordinate y) const {
assert(ok);
int xi = int(std::upper_bound(xs.begin(), xs.end(), x) - xs.begin());
T res{};
for (; xi > 0; xi -= xi & -xi) {
int yi = int(std::upper_bound(ys[xi].begin(), ys[xi].end(), y) -
ys[xi].begin());
for (; yi > 0; yi -= yi & -yi) {
res += dat[xi][yi];
}
}
return res;
}
/// @brief Sum values in [l, r) x [dn, up).
T rectangle_sum(Coordinate l, Coordinate r, Coordinate dn,
Coordinate up) const {
return prefix_sum(r, up) - prefix_sum(l, up) - prefix_sum(r, dn) +
prefix_sum(l, dn);
}
};
} // namespace noya
#ifndef NOYA_SPARSE_FENWICK_2D_HPP
#define NOYA_SPARSE_FENWICK_2D_HPP 1
/// @complexity Time: O(p log^2 p) registration/build and O(log^2 p) per point
/// addition, prefix sum, or rectangle sum. Space: O(p log p).
#include <algorithm>
#include <cassert>
#include <utility>
#include <vector>
namespace noya {
/// @brief Offline-built sparse two-dimensional Fenwick tree.
/// Register every coordinate that may later be updated, then call build().
/// An x-Fenwick node stores only the registered y-coordinates contributing to
/// it, so the dense coordinate plane is replaced by O(p log p) cells.
template <class T, class Coordinate = int> struct sparse_fenwick_2d {
std::vector<std::pair<Coordinate, Coordinate>> pt;
std::vector<Coordinate> xs;
std::vector<std::vector<Coordinate>> ys;
std::vector<std::vector<T>> dat;
bool ok = false;
/// @brief Remove all registered coordinates and values.
void clear() {
pt.clear();
xs.clear();
ys.clear();
dat.clear();
ok = false;
}
/// @brief Register a coordinate that may be passed to add() after build().
void reserve(Coordinate x, Coordinate y) {
assert(!ok);
pt.emplace_back(x, y);
}
/// @brief Build the compressed Fenwick nodes with every value initially zero.
void build() {
assert(!ok);
xs.reserve(pt.size());
for (auto [x, y] : pt) {
(void)y;
xs.push_back(x);
}
std::sort(xs.begin(), xs.end());
xs.erase(std::unique(xs.begin(), xs.end()), xs.end());
ys.assign(xs.size() + 1, {});
for (auto [x, y] : pt) {
int idx = int(std::lower_bound(xs.begin(), xs.end(), x) - xs.begin());
for (idx++; idx <= int(xs.size()); idx += idx & -idx) {
ys[idx].push_back(y);
}
}
dat.resize(xs.size() + 1);
for (int idx = 1; idx <= int(xs.size()); idx++) {
auto &xs0 = ys[idx];
std::sort(xs0.begin(), xs0.end());
xs0.erase(std::unique(xs0.begin(), xs0.end()), xs0.end());
dat[idx].assign(xs0.size() + 1, T{});
}
pt.clear();
pt.shrink_to_fit();
ok = true;
}
/// @brief Add delta at a coordinate registered before build().
void add(Coordinate x, Coordinate y, const T &dif) {
assert(ok);
auto ix = std::lower_bound(xs.begin(), xs.end(), x);
assert(ix != xs.end() && *ix == x);
int xi = int(ix - xs.begin()) + 1;
for (; xi <= int(xs.size()); xi += xi & -xi) {
auto iy = std::lower_bound(ys[xi].begin(), ys[xi].end(), y);
assert(iy != ys[xi].end() && *iy == y);
int yi = int(iy - ys[xi].begin()) + 1;
for (; yi < int(dat[xi].size()); yi += yi & -yi) {
dat[xi][yi] += dif;
}
}
}
/// @brief Sum values at coordinates (px, py) with px < x and py < y.
T prefix_sum(Coordinate x, Coordinate y) const {
assert(ok);
int xi = int(std::lower_bound(xs.begin(), xs.end(), x) - xs.begin());
T res{};
for (; xi > 0; xi -= xi & -xi) {
int yi = int(std::lower_bound(ys[xi].begin(), ys[xi].end(), y) -
ys[xi].begin());
for (; yi > 0; yi -= yi & -yi) {
res += dat[xi][yi];
}
}
return res;
}
/// @brief Sum values at coordinates (px, py) with px <= x and py <= y.
T prefix_sum_inclusive(Coordinate x, Coordinate y) const {
assert(ok);
int xi = int(std::upper_bound(xs.begin(), xs.end(), x) - xs.begin());
T res{};
for (; xi > 0; xi -= xi & -xi) {
int yi = int(std::upper_bound(ys[xi].begin(), ys[xi].end(), y) -
ys[xi].begin());
for (; yi > 0; yi -= yi & -yi) {
res += dat[xi][yi];
}
}
return res;
}
/// @brief Sum values in [l, r) x [dn, up).
T rectangle_sum(Coordinate l, Coordinate r, Coordinate dn,
Coordinate up) const {
return prefix_sum(r, up) - prefix_sum(l, up) - prefix_sum(r, dn) +
prefix_sum(l, dn);
}
};
} // namespace noya
#endif // NOYA_SPARSE_FENWICK_2D_HPP
#include <algorithm>
#include <cassert>
#include <utility>
#include <vector>
/// @complexity Time: O(p log^2 p) registration/build and O(log^2 p) per point
/// addition, prefix sum, or rectangle sum. Space: O(p log p).
namespace noya {
/// @brief Offline-built sparse two-dimensional Fenwick tree.
/// Register every coordinate that may later be updated, then call build().
/// An x-Fenwick node stores only the registered y-coordinates contributing to
/// it, so the dense coordinate plane is replaced by O(p log p) cells.
template <class T, class Coordinate = int> struct sparse_fenwick_2d {
std::vector<std::pair<Coordinate, Coordinate>> pt;
std::vector<Coordinate> xs;
std::vector<std::vector<Coordinate>> ys;
std::vector<std::vector<T>> dat;
bool ok = false;
/// @brief Remove all registered coordinates and values.
void clear() {
pt.clear();
xs.clear();
ys.clear();
dat.clear();
ok = false;
}
/// @brief Register a coordinate that may be passed to add() after build().
void reserve(Coordinate x, Coordinate y) {
assert(!ok);
pt.emplace_back(x, y);
}
/// @brief Build the compressed Fenwick nodes with every value initially zero.
void build() {
assert(!ok);
xs.reserve(pt.size());
for (auto [x, y] : pt) {
(void)y;
xs.push_back(x);
}
std::sort(xs.begin(), xs.end());
xs.erase(std::unique(xs.begin(), xs.end()), xs.end());
ys.assign(xs.size() + 1, {});
for (auto [x, y] : pt) {
int idx = int(std::lower_bound(xs.begin(), xs.end(), x) - xs.begin());
for (idx++; idx <= int(xs.size()); idx += idx & -idx) {
ys[idx].push_back(y);
}
}
dat.resize(xs.size() + 1);
for (int idx = 1; idx <= int(xs.size()); idx++) {
auto &xs0 = ys[idx];
std::sort(xs0.begin(), xs0.end());
xs0.erase(std::unique(xs0.begin(), xs0.end()), xs0.end());
dat[idx].assign(xs0.size() + 1, T{});
}
pt.clear();
pt.shrink_to_fit();
ok = true;
}
/// @brief Add delta at a coordinate registered before build().
void add(Coordinate x, Coordinate y, const T &dif) {
assert(ok);
auto ix = std::lower_bound(xs.begin(), xs.end(), x);
assert(ix != xs.end() && *ix == x);
int xi = int(ix - xs.begin()) + 1;
for (; xi <= int(xs.size()); xi += xi & -xi) {
auto iy = std::lower_bound(ys[xi].begin(), ys[xi].end(), y);
assert(iy != ys[xi].end() && *iy == y);
int yi = int(iy - ys[xi].begin()) + 1;
for (; yi < int(dat[xi].size()); yi += yi & -yi) {
dat[xi][yi] += dif;
}
}
}
/// @brief Sum values at coordinates (px, py) with px < x and py < y.
T prefix_sum(Coordinate x, Coordinate y) const {
assert(ok);
int xi = int(std::lower_bound(xs.begin(), xs.end(), x) - xs.begin());
T res{};
for (; xi > 0; xi -= xi & -xi) {
int yi = int(std::lower_bound(ys[xi].begin(), ys[xi].end(), y) -
ys[xi].begin());
for (; yi > 0; yi -= yi & -yi) {
res += dat[xi][yi];
}
}
return res;
}
/// @brief Sum values at coordinates (px, py) with px <= x and py <= y.
T prefix_sum_inclusive(Coordinate x, Coordinate y) const {
assert(ok);
int xi = int(std::upper_bound(xs.begin(), xs.end(), x) - xs.begin());
T res{};
for (; xi > 0; xi -= xi & -xi) {
int yi = int(std::upper_bound(ys[xi].begin(), ys[xi].end(), y) -
ys[xi].begin());
for (; yi > 0; yi -= yi & -yi) {
res += dat[xi][yi];
}
}
return res;
}
/// @brief Sum values in [l, r) x [dn, up).
T rectangle_sum(Coordinate l, Coordinate r, Coordinate dn,
Coordinate up) const {
return prefix_sum(r, up) - prefix_sum(l, up) - prefix_sum(r, dn) +
prefix_sum(l, dn);
}
};
} // namespace noya