point_add_rectangle_sum.hpp¶
离线维护二维点权增加与轴对齐矩形求和;题目给出动态加点和矩形统计时可直接套用。
Complexity: Time: \(O(p \log (p + 1))\) preprocessing and \(O(\log^{2} (p + 1))\) per point addition or rectangle query. Space: \(O(1 + p \log (p + 1))\) cells.
AC 记录:point_add_rectangle_sum。
Implementation¶
当前头文件,省略 include guard;依赖见 #include。
/// @complexity Time: O(p log(p+1)) preprocessing and O(log^2(p+1)) per point
/// addition or rectangle query. Space: O(1 + p log(p+1)) cells.
#include "noya/ds/sparse_fenwick_2d.hpp"
namespace noya {
/// @brief Point-add rectangle-sum data structure on sparse coordinates.
/// All future update coordinates are registered before build(); coordinate
/// compression inside each x-Fenwick node then supports online additions and
/// half-open rectangle sums without allocating the full plane.
template <class T, class Coordinate = int>
using point_add_rectangle_sum = sparse_fenwick_2d<T, Coordinate>;
} // namespace noya
// NOYA_POINT_ADD_RECTANGLE_SUM_HPP
#ifndef NOYA_POINT_ADD_RECTANGLE_SUM_HPP
#define NOYA_POINT_ADD_RECTANGLE_SUM_HPP 1
/// @complexity Time: O(p log(p+1)) preprocessing and O(log^2(p+1)) per point
/// addition or rectangle query. Space: O(1 + p log(p+1)) cells.
#include "noya/ds/sparse_fenwick_2d.hpp"
namespace noya {
/// @brief Point-add rectangle-sum data structure on sparse coordinates.
/// All future update coordinates are registered before build(); coordinate
/// compression inside each x-Fenwick node then supports online additions and
/// half-open rectangle sums without allocating the full plane.
template <class T, class Coordinate = int>
using point_add_rectangle_sum = sparse_fenwick_2d<T, Coordinate>;
} // namespace noya
#endif // NOYA_POINT_ADD_RECTANGLE_SUM_HPP
/// @complexity Time: O(p log(p+1)) preprocessing and O(log^2(p+1)) per point
/// addition or rectangle query. Space: O(1 + p log(p+1)) cells.
/// @complexity Time: amortized O(1) registration, O(p log(p+1)) build and
/// O(log^2(p+1)) addition/query. Space: O(1 + p log(p+1)) cells.
#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, {});
// Global y order makes every node's coordinate list sorted as it is built.
std::sort(pt.begin(), pt.end(), [](const auto &a, const auto &b) {
return a.second < b.second;
});
for (const 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) {
// A previous visit with this y also populated every higher ancestor.
if (!ys[idx].empty() && ys[idx].back() == y) break;
ys[idx].push_back(y);
}
}
dat.resize(xs.size() + 1);
for (int idx = 1; idx <= int(xs.size()); idx++) {
dat[idx].assign(ys[idx].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 {
assert(ok);
if (l == r || dn == up) return T{};
int xl = int(std::lower_bound(xs.begin(), xs.end(), l) - xs.begin());
int xr = int(std::lower_bound(xs.begin(), xs.end(), r) - xs.begin());
// Cancel shared ancestors of the two prefix paths in each dimension.
auto row_sum = [&](int x) {
const auto &v = ys[x];
int a = int(std::lower_bound(v.begin(), v.end(), dn) - v.begin());
int b = int(std::lower_bound(v.begin(), v.end(), up) - v.begin());
T sum{};
while (a != b) {
if (a < b) {
sum += dat[x][b];
b -= b & -b;
} else {
sum = sum - dat[x][a];
a -= a & -a;
}
}
return sum;
};
T sum{};
while (xl != xr) {
if (xl < xr) {
sum += row_sum(xr);
xr -= xr & -xr;
} else {
sum = sum - row_sum(xl);
xl -= xl & -xl;
}
}
return sum;
}
};
} // namespace noya
namespace noya {
/// @brief Point-add rectangle-sum data structure on sparse coordinates.
/// All future update coordinates are registered before build(); coordinate
/// compression inside each x-Fenwick node then supports online additions and
/// half-open rectangle sums without allocating the full plane.
template <class T, class Coordinate = int>
using point_add_rectangle_sum = sparse_fenwick_2d<T, Coordinate>;
} // namespace noya
// NOYA_POINT_ADD_RECTANGLE_SUM_HPP