#include <bits/stdc++.h>
using namespace std;
// ================================================================
// GENERAL NOTES FOR ALL DATA STRUCTURES:
// - All indices are 1‑based unless explicitly stated otherwise.
// - Use 'long long' for sums to avoid overflow.
// - The term "BIT" stands for Binary Indexed Tree (Fenwick Tree).
// - "Prefix sum" means sum over rectangle [1..x] × [1..y].
// - "Sweep line" is an offline technique where events are processed in order of one coordinate.
// - "Coordinate compression" replaces large coordinate values with smaller indices to save memory.
// - Some structures are "offline", meaning all updates/queries must be known beforehand.
// ================================================================
// ================================================================
// 1) Fenwick2D – Basic 2D BIT for Point Update & Rectangle Sum Query
// ================================================================
/**
* Fenwick2D – 2D Binary Indexed Tree for point updates and prefix/rectangle sum queries.
*
* PURPOSE:
* Maintains a 2D grid of numbers. Supports adding a value to a single cell and
* querying the sum of any axis‑aligned rectangle.
*
* USAGE:
* Fenwick2D fw(n, m); // n rows, m columns (1‑based indexing)
* fw.add(x, y, delta); // add 'delta' to cell (x, y)
* long long s = fw.sum(x, y); // sum of rectangle [1..x] × [1..y]
* long long rect = fw.query(x1, y1, x2, y2); // sum of [x1..x2] × [y1..y2]
* fw.clear(); // reset all values to zero (O(n*m))
*
* TIME COMPLEXITY:
* add, sum, query: O(log n * log m)
* clear: O(n * m)
*
* CONSTRAINTS / NOTES:
* - n, m can be up to ~2000 for a dense BIT; larger grids should use sparse or offline methods.
* - Indices must be in [1..n] and [1..m].
* - The BIT is initially zero; add initial values manually.
* - clear() is expensive; avoid frequent calls on large grids.
*/
struct Fenwick2D {
int n, m;
vector<vector<long long>> bit;
Fenwick2D() {}
Fenwick2D(int n_, int m_) { init(n_, m_); }
void init(int n_, int m_) {
n = n_;
m = m_;
bit.assign(n + 2, vector<long long>(m + 2, 0));
}
void add(int x, int y, long long delta) {
for (int i = x; i <= n; i += i & -i)
for (int j = y; j <= m; j += j & -j)
bit[i][j] += delta;
}
long long sum(int x, int y) const {
long long res = 0;
for (int i = x; i > 0; i -= i & -i)
for (int j = y; j > 0; j -= j & -j)
res += bit[i][j];
return res;
}
long long query(int x1, int y1, int x2, int y2) const {
return sum(x2, y2) - sum(x1 - 1, y2) - sum(x2, y1 - 1) + sum(x1 - 1, y1 - 1);
}
void clear() {
for (int i = 1; i <= n; ++i)
fill(bit[i].begin(), bit[i].end(), 0);
}
};
// ================================================================
// 2) RangeUpdatePointQuery2D – Range Add + Point Query via Difference BIT
// ================================================================
/**
* RangeUpdatePointQuery2D – Supports adding a value to a whole rectangle and
* then querying the value at a single point (offline or online).
*
* PURPOSE:
* Uses a 2D difference array implemented with a BIT to perform range additions
* and point queries efficiently.
*
* USAGE:
* RangeUpdatePointQuery2D ru(n, m);
* ru.rangeAdd(x1, y1, x2, y2, val); // add 'val' to all cells in that rectangle
* long long v = ru.pointQuery(x, y); // get the current value at cell (x, y)
*
* TIME COMPLEXITY:
* rangeAdd: O(log n * log m) (calls four point updates)
* pointQuery: O(log n * log m)
*
* NOTES:
* - All indices are 1‑based.
* - The BIT is used as a difference array; point queries retrieve the accumulated value.
* - No need to initialize with base values; treat base values as separate updates.
* - Extra space (n+2, m+2) is allocated to avoid out‑of‑bounds when updating at x2+1 etc.
*/
struct RangeUpdatePointQuery2D {
int n, m;
Fenwick2D diff;
RangeUpdatePointQuery2D(int n_, int m_) {
n = n_;
m = m_;
diff.init(n + 2, m + 2);
}
void rangeAdd(int x1, int y1, int x2, int y2, long long val) {
diff.add(x1, y1, val);
diff.add(x2 + 1, y1, -val);
diff.add(x1, y2 + 1, -val);
diff.add(x2 + 1, y2 + 1, val);
}
long long pointQuery(int x, int y) {
return diff.sum(x, y);
}
};
// ================================================================
// 3) RangeUpdateRangeQuery2D – Range Add + Range Sum (using four BITs)
// ================================================================
/**
* RangeUpdateRangeQuery2D – Supports adding a value to any rectangle and
* querying the sum of any rectangle.
*
* PURPOSE:
* Uses four difference BITs to maintain the 2D array so that both range updates
* and range queries are supported in O(log n * log m).
*
* USAGE:
* RangeUpdateRangeQuery2D rurq(n, m);
* rurq.rangeAdd(x1, y1, x2, y2, val); // add val to all cells in rectangle
* long long s = rurq.query(x1, y1, x2, y2); // sum of that rectangle
*
* TIME COMPLEXITY:
* rangeAdd: O(log n * log m)
* query: O(log n * log m)
*
* NOTES:
* - Works with 1‑based indices.
* - Internally stores four BITs; memory is 4 * n * m (may be large).
* - Values and sums are long long.
* - The formula used: prefixSum(x,y) = B1*x*y - B2*y - B3*x + B4
* where B1..B4 are the BITs storing difference components.
*/
struct RangeUpdateRangeQuery2D {
int n, m;
Fenwick2D B1, B2, B3, B4;
RangeUpdateRangeQuery2D(int n_, int m_) {
n = n_;
m = m_;
B1.init(n + 2, m + 2);
B2.init(n + 2, m + 2);
B3.init(n + 2, m + 2);
B4.init(n + 2, m + 2);
}
void _pointAdd(int x, int y, long long val) {
B1.add(x, y, val);
B2.add(x, y, val * (x - 1));
B3.add(x, y, val * (y - 1));
B4.add(x, y, val * (x - 1) * (y - 1));
}
void rangeAdd(int x1, int y1, int x2, int y2, long long val) {
_pointAdd(x1, y1, val);
_pointAdd(x2 + 1, y1, -val);
_pointAdd(x1, y2 + 1, -val);
_pointAdd(x2 + 1, y2 + 1, val);
}
long long prefixSum(int x, int y) {
long long s1 = B1.sum(x, y) * x * y;
long long s2 = B2.sum(x, y) * y;
long long s3 = B3.sum(x, y) * x;
long long s4 = B4.sum(x, y);
return s1 - s2 - s3 + s4;
}
long long query(int x1, int y1, int x2, int y2) {
return prefixSum(x2, y2) - prefixSum(x1 - 1, y2)
- prefixSum(x2, y1 - 1) + prefixSum(x1 - 1, y1 - 1);
}
};
// ================================================================
// 4) SparseFenwick2D (Compressed) – Sparse 2D BIT with Coordinate Compression
// ================================================================
/**
* SparseFenwick2D – Sparse 2D BIT for large coordinates, using offline compression.
*
* PURPOSE:
* When the grid is huge (coordinates up to 1e9) but the number of points is small,
* this structure compresses coordinates and builds a sparse BIT to save memory.
* Supports point updates and rectangle sum queries.
*
* USAGE (Offline):
* 1. Collect all (x,y) points that will ever be updated or queried.
* 2. Build the structure: SparseFenwick2D sfw(coords); // coords: vector<pair<int,int>>
* 3. Add values: sfw.add(x, y, delta);
* 4. Query: sfw.query(x1, y1, x2, y2) // sum in rectangle
*
* TIME COMPLEXITY:
* build: O(P log P) where P = number of distinct points.
* add: O(log N * log K) where N = number of distinct x, K = average y per x-node.
* query: same as add.
*
* CONSTRAINTS / NOTES:
* - All coordinates must be known beforehand (offline).
* - Use 'long long' for sums.
* - The class internally uses unordered_map for fast x‑index lookup.
* - Only points that appear in the input 'coords' can be updated/queried.
* - Queries with x1-1 or y1-1 are handled automatically if those coordinates are included.
* If a queried x does not exist in the compressed list, the sum is safely returned as 0.
* - Build time and memory are proportional to number of points.
*/
struct SparseFenwick2D {
int n;
vector<vector<int>> xs;
vector<vector<long long>> bit;
unordered_map<int,int> xIndex;
SparseFenwick2D() {}
SparseFenwick2D(const vector<pair<int,int>>& coords) {
build(coords);
}
void build(const vector<pair<int,int>>& coords) {
vector<int> allX;
for (auto &p : coords) allX.push_back(p.first);
sort(allX.begin(), allX.end());
allX.erase(unique(allX.begin(), allX.end()), allX.end());
n = allX.size();
xs.assign(n + 1, {});
for (auto &p : coords) {
int x = p.first;
int idx = lower_bound(allX.begin(), allX.end(), x) - allX.begin() + 1;
for (int i = idx; i <= n; i += i & -i) {
xs[i].push_back(p.second);
}
}
bit.assign(n + 1, {});
for (int i = 1; i <= n; ++i) {
sort(xs[i].begin(), xs[i].end());
xs[i].erase(unique(xs[i].begin(), xs[i].end()), xs[i].end());
bit[i].assign(xs[i].size() + 1, 0);
}
xIndex.clear();
for (int i = 0; i < (int)allX.size(); ++i)
xIndex[allX[i]] = i + 1;
}
void add(int x, int y, long long delta) {
int idx = xIndex[x]; // x must be present in the built map
for (int i = idx; i <= n; i += i & -i) {
int pos = lower_bound(xs[i].begin(), xs[i].end(), y) - xs[i].begin() + 1;
for (int j = pos; j < (int)bit[i].size(); j += j & -j)
bit[i][j] += delta;
}
}
long long sum(int x, int y) {
auto it = xIndex.find(x);
if (it == xIndex.end()) return 0; // x not present in compressed list -> prefix sum is 0
int idx = it->second;
long long res = 0;
for (int i = idx; i > 0; i -= i & -i) {
int pos = upper_bound(xs[i].begin(), xs[i].end(), y) - xs[i].begin();
for (int j = pos; j > 0; j -= j & -j)
res += bit[i][j];
}
return res;
}
long long query(int x1, int y1, int x2, int y2) {
return sum(x2, y2) - sum(x1 - 1, y2) - sum(x2, y1 - 1) + sum(x1 - 1, y1 - 1);
}
};
// ================================================================
// 5) Fenwick1D – Basic 1D BIT (for reference and offline methods)
// ================================================================
/**
* Fenwick1D – Standard 1D Binary Indexed Tree for point update and prefix sum.
*
* PURPOSE:
* Supports adding a value at a position and querying prefix sum.
*
* USAGE:
* Fenwick1D bit(N); // 1‑based indices up to N
* bit.add(idx, val); // add 'val' at index idx
* int s = bit.sum(idx); // sum of [1..idx]
* int range = bit.rangeSum(l, r); // sum of [l..r]
*
* TIME COMPLEXITY:
* add, sum, rangeSum: O(log N)
*
* NOTES:
* - Used as a helper in offline sweep‑line algorithms.
* - All values are integers; cast to long long if needed.
*/
struct Fenwick1D {
int n;
vector<int> bit;
Fenwick1D(int n) : n(n), bit(n + 1, 0) {}
void add(int idx, int val) {
for (; idx <= n; idx += idx & -idx) bit[idx] += val;
}
int sum(int idx) {
int res = 0;
for (; idx > 0; idx -= idx & -idx) res += bit[idx];
return res;
}
int rangeSum(int l, int r) {
if (l > r) return 0;
return sum(r) - sum(l - 1);
}
};
// ================================================================
// 6) solveOffline – Count Points in Rectangles (Offline, no updates)
// ================================================================
/**
* solveOffline – Counts the number of points inside each query rectangle.
*
* PURPOSE:
* Given a set of static points and many rectangle queries, this function returns
* for each query the number of points that lie inside the rectangle.
* It uses a sweep line on x‑coordinate and a 1D BIT on y‑coordinate.
*
* USAGE:
* vector<Point> points; // each has (x, y)
* vector<tuple<int,int,int,int>> rectQueries; // each: (x1, y1, x2, y2)
* vector<int> ans = solveOffline(n, m, points, rectQueries);
* // ans[i] = number of points in the i‑th rectangle.
*
* PARAMETERS:
* n, m – not actually used (can be ignored), they are the grid bounds.
* points – list of points (1‑based coordinates).
* rectQueries – each tuple holds (x1, y1, x2, y2) inclusive.
*
* RETURN:
* vector<int> containing answers in the same order as queries.
*
* TIME COMPLEXITY:
* O((P + Q) log Y) where P = number of points, Q = number of queries,
* Y = number of distinct y‑coordinates.
*
* NOTES:
* - All coordinates are 1‑based.
* - The function compresses y‑coordinates automatically.
* - The grid bounds (n,m) are ignored; they are only for reference.
* - The points are static; no updates are allowed.
* - Uses inclusion‑exclusion to turn each rectangle query into 4 prefix queries.
*/
struct Point {
int x, y;
};
struct Query {
int x, y, idx, sign;
};
vector<int> solveOffline(int n, int m, vector<Point>& points, vector<tuple<int,int,int,int>>& rectQueries) {
vector<int> allY;
for (auto &p : points) allY.push_back(p.y);
for (auto &[x1, y1, x2, y2] : rectQueries) {
allY.push_back(y1 - 1);
allY.push_back(y2);
}
sort(allY.begin(), allY.end());
allY.erase(unique(allY.begin(), allY.end()), allY.end());
auto getY = [&](int y) { return lower_bound(allY.begin(), allY.end(), y) - allY.begin() + 1; };
vector<tuple<int, int, int, int>> events;
for (auto &p : points) {
events.push_back({p.x, getY(p.y), -1, 0});
}
int q = rectQueries.size();
vector<int> ans(q, 0);
for (int i = 0; i < q; i++) {
auto [x1, y1, x2, y2] = rectQueries[i];
events.push_back({x2, getY(y2), i, 1});
events.push_back({x1 - 1, getY(y2), i, -1});
events.push_back({x2, getY(y1 - 1), i, -1});
events.push_back({x1 - 1, getY(y1 - 1), i, 1});
}
sort(events.begin(), events.end());
Fenwick1D bit(allY.size() + 5);
for (auto &[x, y, idx, sign] : events) {
if (idx == -1) {
bit.add(y, 1);
} else {
ans[idx] += sign * bit.sum(y);
}
}
return ans;
}
// ================================================================
// 7) SparseFenwick2D (unordered_map) – Sparse 2D BIT using hash maps
// ================================================================
/**
* SparseFenwick2D (with unordered_map) – Another sparse 2D BIT that uses hash maps
* to store only updated cells.
*
* PURPOSE:
* Similar to the compressed sparse version but does not require offline coordinate
* compression. It stores a hash map for each BIT node mapping y -> accumulated value.
* Suitable when the number of updates is small but coordinates can be arbitrary.
*
* USAGE:
* SparseFenwick2D sfw(maxX); // maxX is the maximum x‑coordinate (1‑based)
* sfw.add(x, y, delta);
* long long s = sfw.sum(x, y);
* long long rect = sfw.query(x1, y1, x2, y2);
*
* TIME COMPLEXITY:
* add: O(log X * average hash map insert)
* sum: O(log X * average hash map lookup)
* query: same as sum (4 calls).
*
* NOTES:
* - The first dimension (x) must be within [1..maxX] (maxX given in constructor).
* - Uses unordered_map for each BIT node; memory usage is O(number of updated points * log X).
* - Hash map overhead may be high; prefer the compressed version if coordinates are known.
* - All indices are 1‑based.
*/
struct SparseFenwick2D_hash { // renamed to avoid duplicate name
int n;
vector<unordered_map<int, long long>> bit;
SparseFenwick2D_hash(int n) : n(n), bit(n + 1) {}
void add(int x, int y, long long delta) {
for (int i = x; i <= n; i += i & -i) {
bit[i][y] += delta;
}
}
long long sum(int x, int y) {
long long res = 0;
for (int i = x; i > 0; i -= i & -i) {
auto it = bit[i].find(y);
if (it != bit[i].end()) res += it->second;
}
return res;
}
long long query(int x1, int y1, int x2, int y2) {
return sum(x2, y2) - sum(x1 - 1, y2) - sum(x2, y1 - 1) + sum(x1 - 1, y1 - 1);
}
};
// ================================================================
// 8) Fenwick2DMax – 2D BIT for Max (only non‑decreasing updates)
// ================================================================
/**
* Fenwick2DMax – 2D BIT that supports point updates with 'max' operation
* and prefix maximum queries.
*
* PURPOSE:
* Maintains a grid where each cell holds a value. Supports updating a cell with a
* new value (only if it is larger) and querying the maximum value in the prefix
* rectangle [1..x] × [1..y]. This works correctly only when updates are non‑decreasing.
*
* USAGE:
* Fenwick2DMax fw(n, m);
* fw.update(x, y, val); // sets bit[i][j] = max(bit[i][j], val) for all ancestors
* int maxVal = fw.query(x, y); // maximum value in [1..x] × [1..y]
*
* TIME COMPLEXITY:
* update: O(log n * log m)
* query: O(log n * log m)
*
* NOTES:
* - The BIT initially holds 0. If values can be negative, adjust initial value.
* - Updates must be non‑decreasing (i.e., val should be >= previous values at that cell,
* otherwise the max property breaks). Use only when you insert values in increasing order.
* - Works for 1‑based indices.
*/
struct Fenwick2DMax {
int n, m;
vector<vector<int>> bit;
Fenwick2DMax(int n, int m) : n(n), m(m), bit(n + 1, vector<int>(m + 1, 0)) {}
void update(int x, int y, int val) {
for (int i = x; i <= n; i += i & -i)
for (int j = y; j <= m; j += j & -j)
bit[i][j] = max(bit[i][j], val);
}
int query(int x, int y) {
int res = 0;
for (int i = x; i > 0; i -= i & -i)
for (int j = y; j > 0; j -= j & -j)
res = max(res, bit[i][j]);
return res;
}
};
// ================================================================
// 9) Fenwick3D – 3D BIT for Point Update and Cuboid Sum Query
// ================================================================
/**
* Fenwick3D – 3D Binary Indexed Tree for point updates and cuboid sum queries.
*
* PURPOSE:
* Extends the 2D BIT to three dimensions. Supports adding a value to a point (x,y,z)
* and querying the sum of the box [1..x] × [1..y] × [1..z].
*
* USAGE:
* Fenwick3D fw(n, m, k); // dimensions: x=1..n, y=1..m, z=1..k
* fw.add(x, y, z, delta);
* long long s = fw.sum(x, y, z);
* long long box = fw.cuboidSum(x1,y1,z1, x2,y2,z2); // sum inside the box
*
* TIME COMPLEXITY:
* add, sum: O(log n * log m * log k)
* cuboidSum: O(log n * log m * log k) (8 calls to sum)
*
* NOTES:
* - All indices are 1‑based.
* - Memory is n*m*k; use only for small dimensions (e.g., up to 100 each).
* - Use long long for sums.
* - Inclusion‑exclusion in 3D has 8 terms.
*/
struct Fenwick3D {
int n, m, k;
vector<vector<vector<long long>>> bit;
Fenwick3D(int n, int m, int k) : n(n), m(m), k(k),
bit(n + 1, vector<vector<long long>>(m + 1, vector<long long>(k + 1, 0))) {}
void add(int x, int y, int z, long long delta) {
for (int i = x; i <= n; i += i & -i)
for (int j = y; j <= m; j += j & -j)
for (int l = z; l <= k; l += l & -l)
bit[i][j][l] += delta;
}
long long sum(int x, int y, int z) {
long long res = 0;
for (int i = x; i > 0; i -= i & -i)
for (int j = y; j > 0; j -= j & -j)
for (int l = z; l > 0; l -= l & -l)
res += bit[i][j][l];
return res;
}
long long cuboidSum(int x1, int y1, int z1, int x2, int y2, int z2) {
return sum(x2, y2, z2)
- sum(x1 - 1, y2, z2) - sum(x2, y1 - 1, z2) - sum(x2, y2, z1 - 1)
+ sum(x1 - 1, y1 - 1, z2) + sum(x1 - 1, y2, z1 - 1) + sum(x2, y1 - 1, z1 - 1)
- sum(x1 - 1, y1 - 1, z1 - 1);
}
};
// ================================================================
// 10) BIT1D – Another 1D BIT (helper for offline methods)
// ================================================================
/**
* BIT1D – Simple 1D Fenwick Tree for sum with long long values.
*
* PURPOSE:
* Same as Fenwick1D but with long long support. Used in offline sweep‑line solutions.
*
* USAGE:
* BIT1D bit(N);
* bit.add(idx, val);
* long long s = bit.sum(idx);
* long long range = bit.rangeSum(l, r);
*
* TIME COMPLEXITY:
* O(log N) per operation.
*
* NOTES:
* - 1‑based indices.
* - Internally uses long long to avoid overflow.
*/
struct BIT1D {
int n;
vector<long long> bit;
BIT1D(int n = 0) { init(n); }
void init(int n_) { n = n_; bit.assign(n + 1, 0); }
void add(int idx, long long val) {
for (; idx <= n; idx += idx & -idx) bit[idx] += val;
}
long long sum(int idx) {
long long res = 0;
for (; idx > 0; idx -= idx & -idx) res += bit[idx];
return res;
}
long long rangeSum(int l, int r) {
if (l > r) return 0;
return sum(r) - sum(l - 1);
}
};
// ================================================================
// 11) offlineRectSumWithUpdates – Offline Rectangle Sum with Point Updates
// ================================================================
/**
* offlineRectSumWithUpdates – Solves rectangle sum queries with point updates offline.
*
* PURPOSE:
* Given a set of initial points, point updates (add delta to a point), and rectangle sum
* queries, this function computes the answer for each query efficiently using a sweep line
* over x‑coordinate and a 1D BIT over y‑coordinate.
*
* USAGE:
* vector<pair<int,int>> points; // initial points (x,y)
* vector<tuple<int,int,long long>> pointUpdates; // (x, y, delta)
* vector<tuple<int,int,int,int>> rectQueries; // (x1, y1, x2, y2)
* vector<long long> ans = offlineRectSumWithUpdates(points, pointUpdates, rectQueries);
*
* RETURN:
* vector<long long> where ans[i] is the sum of all point values inside the i‑th rectangle.
*
* TIME COMPLEXITY:
* O((P + U + Q) log Y) where P = #initial points, U = #updates, Q = #queries,
* Y = number of distinct y‑coordinates after compression.
*
* NOTES:
* - All coordinates are 1‑based.
* - The function compresses y‑coordinates automatically.
* - Works offline: all updates and queries must be known in advance.
* - Each rectangle query is transformed into 4 prefix queries using inclusion‑exclusion.
* - Initial points are treated as updates with delta=1 (or any given value? The code adds 1 for each point.
* If you need different values, modify the code accordingly.)
*/
vector<long long> offlineRectSumWithUpdates(
vector<pair<int,int>>& points,
vector<tuple<int,int,long long>>& pointUpdates,
vector<tuple<int,int,int,int>>& rectQueries
) {
// compress y
vector<int> ys;
for (auto &p : points) ys.push_back(p.second);
for (auto &[x,y,delta] : pointUpdates) ys.push_back(y);
for (auto &[x1,y1,x2,y2] : rectQueries) {
ys.push_back(y1 - 1);
ys.push_back(y2);
}
sort(ys.begin(), ys.end());
ys.erase(unique(ys.begin(), ys.end()), ys.end());
auto getY = [&](int y) { return lower_bound(ys.begin(), ys.end(), y) - ys.begin() + 1; };
struct Event {
int x, y, id, sign, type; // type=0: point, type=1: query
long long val;
bool operator<(const Event& o) const {
if (x != o.x) return x < o.x;
return type < o.type;
}
};
vector<Event> events;
for (auto &p : points) {
events.push_back({p.first, getY(p.second), -1, 0, 0, 1});
}
for (auto &[x,y,delta] : pointUpdates) {
events.push_back({x, getY(y), -1, 0, 0, delta});
}
int q = rectQueries.size();
vector<long long> ans(q, 0);
for (int i = 0; i < q; i++) {
auto &[x1,y1,x2,y2] = rectQueries[i];
events.push_back({x2, getY(y2), i, 1, 1, 0});
events.push_back({x1 - 1, getY(y2), i, -1, 1, 0});
events.push_back({x2, getY(y1 - 1), i, -1, 1, 0});
events.push_back({x1 - 1, getY(y1 - 1), i, 1, 1, 0});
}
sort(events.begin(), events.end());
BIT1D bit(ys.size() + 5);
for (auto &e : events) {
if (e.type == 0) {
bit.add(e.y, e.val);
} else {
ans[e.id] += e.sign * bit.sum(e.y);
}
}
return ans;
}
// ================================================================
// 12) FenwickXOR – 1D BIT for XOR (point update, prefix XOR)
// ================================================================
/**
* FenwickXOR – 1D BIT that supports point updates with XOR and prefix XOR queries.
*
* PURPOSE:
* Maintains an array of integers where you can XOR a value at a position and
* query the XOR of elements from 1 to idx.
*
* USAGE:
* FenwickXOR fx(N);
* fx.add(idx, val); // bit[idx] ^= val (XOR update)
* int x = fx.prefixXor(idx); // XOR of [1..idx]
* int rangeXor = fx.rangeXor(l, r); // XOR of [l..r]
*
* TIME COMPLEXITY:
* O(log N) per operation.
*
* NOTES:
* - Works with int; for long long, change type.
* - All indices are 1‑based.
*/
struct FenwickXOR {
int n;
vector<int> bit;
FenwickXOR(int n = 0) { init(n); }
void init(int n_) { n = n_; bit.assign(n + 1, 0); }
void add(int idx, int val) {
for (; idx <= n; idx += idx & -idx) bit[idx] ^= val;
}
int prefixXor(int idx) {
int res = 0;
for (; idx > 0; idx -= idx & -idx) res ^= bit[idx];
return res;
}
int rangeXor(int l, int r) {
return prefixXor(r) ^ prefixXor(l - 1);
}
};
// ================================================================
// 13) Fenwick2DMulti – Multiple BITs for Sum and Sum of Squares
// ================================================================
/**
* Fenwick2DMulti – Maintains two 2D BITs to store both sum and sum of squares.
*
* PURPOSE:
* Useful when you need to compute variance or other statistics from point updates.
* Supports point updates and prefix queries for both sum and sum of squares.
*
* USAGE:
* Fenwick2DMulti fw(n, m);
* fw.add(x, y, val); // add val to cell (x,y)
* auto [s, sq] = fw.sum(x, y); // returns pair: (sum, sum of squares) for prefix [1..x][1..y]
*
* TIME COMPLEXITY:
* add, sum: O(log n * log m)
*
* NOTES:
* - 1‑based indices.
* - The BIT stores sum and sum of squares separately.
* - Use long long for both values; squares can be large.
*/
struct Fenwick2DMulti {
int n, m;
vector<vector<long long>> bitSum, bitSq;
Fenwick2DMulti(int n_, int m_) { init(n_, m_); }
void init(int n_, int m_) {
n = n_; m = m_;
bitSum.assign(n + 1, vector<long long>(m + 1, 0));
bitSq.assign(n + 1, vector<long long>(m + 1, 0));
}
void add(int x, int y, long long val) {
long long sq = val * val;
for (int i = x; i <= n; i += i & -i)
for (int j = y; j <= m; j += j & -j) {
bitSum[i][j] += val;
bitSq[i][j] += sq;
}
}
pair<long long, long long> sum(int x, int y) {
long long s = 0, sq = 0;
for (int i = x; i > 0; i -= i & -i)
for (int j = y; j > 0; j -= j & -j) {
s += bitSum[i][j];
sq += bitSq[i][j];
}
return {s, sq};
}
};
// ================================================================
// 14) Example usage in main()
// ================================================================
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Example 1: Point update, rectangle sum query
int n = 5, m = 5;
Fenwick2D fw(n, m);
// initial values (if any)
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
long long val;
cin >> val; // read initial grid (1‑based)
fw.add(i, j, val);
}
}
// point update: add 10 at (3,3)
fw.add(3, 3, 10);
// query rectangle [2..4] × [2..4]
cout << fw.query(2, 2, 4, 4) << '\n';
// Example 2: Range update, point query
RangeUpdatePointQuery2D ru(n, m);
ru.rangeAdd(2, 2, 4, 4, 5); // add 5 to rectangle
cout << ru.pointQuery(3, 3) << '\n'; // should print 5
// Example 3: Range update, range query
RangeUpdateRangeQuery2D rurq(n, m);
rurq.rangeAdd(1, 1, 3, 3, 2);
rurq.rangeAdd(2, 2, 4, 4, -1);
cout << rurq.query(1, 1, 4, 4) << '\n';
// Example 4: Sparse 2D BIT (compressed)
vector<pair<int,int>> coords = {{100, 200}, {100, 300}, {200, 100}, {300, 400}};
SparseFenwick2D sfw(coords);
sfw.add(100, 200, 5);
sfw.add(200, 100, 7);
// query rectangle [100..300] × [100..400]
cout << sfw.query(100, 100, 300, 400) << '\n'; // should be 12
return 0;
}
// ======================================================================
// ADDITIONAL NOTES ON PERFORMANCE AND USAGE:
// - Standard 2D BIT: O(log n * log m) per operation.
// - Sparse BIT (compressed): O(log N * log K) where N = number of distinct x,
// K = average y per node, but requires offline knowledge.
// - Always prefer 1‑based indexing to avoid confusion.
// - Use long long for sums to avoid overflow.
// - For large grids (n,m up to 1e3) standard 2D BIT is fine;
// for n,m up to 1e5 use sparse or sweep line.
// - The file contains only complete, working structures. Duplicate or incomplete
// versions have been removed or clearly separated.
// ======================================================================