--- id: PURS title: "Point Update Range Sum" author: Benjamin Qi prerequisites: - Silver - Prefix Sums description: Introducing Binary Indexed Trees & Indexed Sets (C++ only). frequency: 3 --- import { Problem } from "../models"; export const metadata = { problems: { sample: [ new Problem("YS", "Point Add Range Sum", "point_add_range_sum", "Easy", false, ["PURS"], ""), new Problem("CSES", "Range Sum Queries II", "1648", "Easy", false, ["PURS"], "Can also do range XOR queries w/ update."), new Problem("SPOJ", "Inversion Counting", "INVCNT", "Easy", false, ["PURS"]), ], practice: [ new Problem("CSES", "List Removals", "1749", "Easy", false, undefined, "easy with indexed set"), new Problem("CSES", "Salary Queries", "1144", "Easy", false, undefined, "easy with indexed set"), new Problem("CSES", "Range Update Queries", "1651", "Easy", false, undefined, "not harder than point update range query"), new Problem("CSES", "Increasing Subsequence II", "1748", "Easy", false, undefined, ""), new Problem("CSES", "Intersection Points", "1740", "Easy", false, undefined, ""), new Problem("Kattis", "Mega Inversions", "megainversions", "Easy", false, undefined, "also just inversion counting"), new Problem("HackerEarth", "Twin Permutations", "https://www.hackerearth.com/practice/data-structures/advanced-data-structures/fenwick-binary-indexed-trees/practice-problems/algorithm/mancunian-and-twin-permutations-d988930c/description/", "Easy", false, undefined, "Offline 2D queries can be done with a 1D data structure"), new Problem("CSES", "Distinct Values Queries", "1734", "Normal", false, undefined, "Do queries in increasing order of $a$."), new Problem("CSES", "Robot Path", "1742", "Hard", false, undefined, ""), ], usaco: [ new Problem("Gold", "Haircut", "1041", "Easy", false, undefined, ""), new Problem("Gold", "Balanced Photo", "693", "Easy", false, undefined, ""), new Problem("Gold", "Circle Cross", "719", "Easy", false, undefined, ""), new Problem("Gold", "Sleepy Cow Sort", "898", "Easy", false, undefined, "All USACO problems (aside from some special exceptions) have only one possible output."), new Problem("Plat", "Mincross", "720", "Easy", false, undefined, ""), new Problem("Silver", "Out of Sorts", "834", "Normal", false, undefined, "aka Sorting Steps: https://csacademy.com/contest/round-42/task/sorting-steps/ - Of course, this doesn't require anything other than sorting but fast range sum queries may make this easier."), new Problem("Gold", "Out of Sorts", "837", "Hard", false, undefined, ""), new Problem("Old Gold", "Cow Hopscotch", "532", "Hard", false, [], ""), new Problem("Plat", "Out of Sorts", "840", "Hard", false, [], ""), ], } }; ## Binary Indexed Tree A *Binary Indexed Tree* (aka *Fenwick Tree*) allows you to perform the following tasks in $O(\log N)$ time each on an array of size $N$: - Update the element at a single position (point). - Query the sum of a prefix of the array. ### Resources interactive similar to above also similar to above ### Implementations based off above ## Finding $k$-th Element Suppose that we want a data structure that supports all the operations as a `set` in C++ in addition to the following: * `order_of_key(x)`: counts the number of elements in the set that are strictly less than `x`. * `find_by_order(k)`: similar to `find`, returns the iterator corresponding to the `k`-th lowest element in the set (0-indexed). ### Indexed Set Luckily, such a built-in data structure already exists in C++. Using this, we can solve "Inversion Counting" in just a few lines (with template). ```cpp #include using namespace std; #include #include using namespace __gnu_pbds; template using Tree = tree, rb_tree_tag, tree_order_statistics_node_update>; int main() { int T; cin >> T; for (int i = 0; i < T; ++i) { int n; cin >> n; Tree TS; long long numInv = 0; for (int j = 0; j < n; ++j) { int x; cin >> x; numInv += j-TS.order_of_key(x); // gives # elements before it > x TS.insert(x); } cout << numInv << "\n"; } } ``` Note that if it were not the case that all elements of the input array were distinct, then this code would be incorrect since `Tree` would remove duplicates. Instead, we would use an indexed set of pairs (`Tree>`), where the first element of each pair would denote the value while the second would denote the position of the value in the array. ### Using a BIT Assumes all updates are in the range $[1,N]$. log N log^2 N ## Practice Problems ## USACO Problems Haircut, Balanced Photo, and Circle Cross are just variations on inversion counting.