Skip to content

Commit b27ef3b

Browse files
committed
feat: Add PointAddRangeSum class for efficient range sum queries and updates
1 parent d3b2a0d commit b27ef3b

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed

test/point_add_range_sum.test.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#define PROBLEM "https://judge.yosupo.jp/problem/point_add_range_sum"
2+
3+
#include "../weilycoder/ds/point_add_range_sum.hpp"
4+
#include <cstdint>
5+
#include <iostream>
6+
#include <vector>
7+
using namespace std;
8+
using namespace weilycoder;
9+
10+
int main() {
11+
cin.tie(nullptr)->sync_with_stdio(false);
12+
cin.exceptions(cin.failbit | cin.badbit);
13+
size_t n, q;
14+
cin >> n >> q;
15+
16+
vector<uint64_t> initial(n, 0);
17+
for (size_t i = 0; i < n; ++i)
18+
cin >> initial[i];
19+
20+
PointAddRangeSum<AddGroup<uint64_t>> pasr(initial);
21+
while (q--) {
22+
int type;
23+
cin >> type;
24+
if (type == 0) {
25+
size_t i, x;
26+
cin >> i >> x;
27+
pasr.point_add(i, x);
28+
} else {
29+
size_t l, r;
30+
cin >> l >> r;
31+
cout << pasr.range_sum(l, r) << '\n';
32+
}
33+
}
34+
return 0;
35+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#ifndef WEILYCODER_POINT_ADD_RANGE_SUM_HPP
2+
#define WEILYCODER_POINT_ADD_RANGE_SUM_HPP
3+
4+
#include "group.hpp"
5+
#include <cstddef>
6+
#include <vector>
7+
8+
namespace weilycoder {
9+
/**
10+
* @brief Point Add Range Sum using Fenwick Tree (Binary Indexed Tree)
11+
* @tparam Group A group defining the operation and identity element,
12+
* must be associative and commutative (i.e. Abelian group).
13+
*/
14+
template <typename Group> struct PointAddRangeSum {
15+
using value_type = typename Group::value_type;
16+
using T = value_type;
17+
18+
private:
19+
std::vector<T> data;
20+
21+
public:
22+
/**
23+
* @brief Constructs a PointAddRangeSum for n elements initialized to the
24+
* identity element
25+
* @param n Number of elements
26+
*/
27+
explicit PointAddRangeSum(size_t n) : data(n + 1, Group::identity()) {}
28+
29+
/**
30+
* @brief Constructs a PointAddRangeSum from an initial array
31+
* @param initial Initial array of elements
32+
*/
33+
explicit PointAddRangeSum(const std::vector<T> &initial)
34+
: data(initial.size() + 1, Group::identity()) {
35+
for (size_t i = 1; i <= initial.size(); ++i) {
36+
data[i] = Group::operation(data[i], initial[i - 1]);
37+
size_t j = i + (i & -i);
38+
if (j < data.size())
39+
data[j] = Group::operation(data[j], data[i]);
40+
}
41+
}
42+
43+
/**
44+
* @brief Constructs a PointAddRangeSum from an initial range
45+
* @tparam InputIt Input iterator type
46+
* @param first Beginning of the range
47+
* @param last End of the range
48+
*/
49+
template <typename InputIt>
50+
explicit PointAddRangeSum(InputIt first, InputIt last)
51+
: data(std::distance(first, last) + 1, Group::identity()) {
52+
size_t i = 1;
53+
for (auto it = first; it != last; ++it, ++i) {
54+
data[i] = Group::operation(data[i], *it);
55+
size_t j = i + (i & -i);
56+
if (j < data.size())
57+
data[j] = Group::operation(data[j], data[i]);
58+
}
59+
}
60+
61+
/**
62+
* @brief Adds value x to element at index i
63+
* @param i Index to update
64+
* @param x Value to add
65+
*/
66+
void point_add(size_t i, const T &x) {
67+
for (++i; i < data.size(); i += i & -i)
68+
data[i] = Group::operation(data[i], x);
69+
}
70+
71+
/**
72+
* @brief Computes the prefix sum [0, i)
73+
* @param i Index (exclusive)
74+
* @return The sum of elements in the range [0, i)
75+
*/
76+
T prefix_sum(size_t i) const {
77+
T result = Group::identity();
78+
for (; i > 0; i -= i & -i)
79+
result = Group::operation(result, data[i]);
80+
return result;
81+
}
82+
83+
/**
84+
* @brief Computes the range sum [l, r)
85+
* @param l Left index (inclusive)
86+
* @param r Right index (exclusive)
87+
* @return The sum of elements in the range [l, r)
88+
*/
89+
T range_sum(size_t l, size_t r) const {
90+
return Group::operation(prefix_sum(r), Group::inverse(prefix_sum(l)));
91+
}
92+
};
93+
} // namespace weilycoder
94+
95+
#endif

0 commit comments

Comments
 (0)