Fenwick Tree Algorithm
The Fenwick Tree Algorithm, also known as the Binary Indexed Tree (BIT), is an advanced data structure that efficiently supports the operations of updating elements and querying prefix sums in an array. It was first introduced by Peter M. Fenwick in 1994 as a means to improve the efficiency of arithmetic coding compression algorithms. It has since been widely adopted in various applications, such as computational geometry, numerical analysis, and data mining, where cumulative frequency tables and cumulative sums are frequently needed.
The primary advantage of the Fenwick Tree is that it reduces the time complexity of both update and query operations to O(log n), compared to O(n) for a naive implementation using an array or O(log n) for a segment tree. This efficiency is achieved by storing elements in the tree in such a way that each node is responsible for a specific range of indices, allowing for quick updates and queries. To perform an update, the algorithm traverses up the tree, updating nodes responsible for the index range containing the updated element. Similarly, to query the prefix sum, the algorithm traverses down the tree, summing the ranges that make up the queried prefix. The compact representation of the Fenwick Tree allows it to consume less memory than other data structures, such as segment trees, that offer similar functionalities.
#include<iostream>
using namespace std;
/**
* ` lowbit(x) ` aims to find the last 1 in binary of a positive number
* twos complement works good on this
* also using ` x - (x & (x - 1)) `
*/
#define lowbit(x) (x & (-x) )
const int maxn = 1e5 + 7;
int tree[maxn] = {0},
range; // segement of [1...range], notice it must be less than `maxn`
void update(int x, int c) {
while(x <= range) {
tree[x] += c;
x += lowbit(x);
}
}
int query(int x) {
int ans = 0;
while(x) {
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
int query_segement(int l, int r) {
return query(r) - query(l - 1);
}
int main() {
cin >> range;
for(int i = 1; i <= range; i++) {
int num;
cin >> num;
update(i, num);
}
int q;
cin >> q;
while(q--) {
int op;
cin >> op;
if(op == 0) {
int l, r;
cin >> l >> r;
cout << query_segement(l, r) << endl;
} else {
int x, c;
cin >> x >> c;
update(x, c);
}
}
return 0;
}