111 lines
5.4 KiB
Text
111 lines
5.4 KiB
Text
---
|
|
id: PURS
|
|
title: "Point Update Range Sum"
|
|
author: Benjamin Qi
|
|
prerequisites:
|
|
- Silver - Prefix Sums
|
|
description: Introducing Binary Indexed Trees & Indexed Sets (C++ only).
|
|
---
|
|
|
|
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, ""),
|
|
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, ""),
|
|
]
|
|
}
|
|
};
|
|
|
|
## Sample Problems
|
|
|
|
<problems-list problems={metadata.problems.sample} />
|
|
|
|
## Binary Indexed Tree
|
|
|
|
A *Binary Indexed 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.
|
|
|
|
Aka *Fenwick Tree*.
|
|
|
|
### Tutorials
|
|
|
|
* CPH 9.2, 9.4
|
|
* very good
|
|
* [CSAcademy BIT](https://csacademy.com/lesson/fenwick_trees)
|
|
* also very good
|
|
* [cp-algorithms Fenwick Tree](https://cp-algorithms.com/data_structures/fenwick.html)
|
|
* extends to range increment and range query, although this is not necessary for gold
|
|
* [Topcoder BIT](https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/)
|
|
|
|
My implementation can be found [here](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/1D%20Range%20Queries%20(9.2)/BIT%20(9.2).h), and can compute range sum queries for any number of dimensions.
|
|
|
|
## Finding K-th Element in BIT?
|
|
|
|
## Indexed Set
|
|
|
|
In the special case where all elements of the array are either zero or one (which is the case for several gold problems), users of C++ will find [indexed set](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/STL%20(5)/IndexedSet.h) useful. Using this, we can solve "Inversion Counting" in just a few lines (with template). `Tree<int>` behaves mostly the same way as `set<int>` with the additional functions
|
|
|
|
* `order_of_key(x)`: counts the number of elements in the indexed 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).
|
|
|
|
See the link for more examples of usage.
|
|
|
|
<spoiler title="INVCNT with Indexed Set">
|
|
|
|
```cpp
|
|
#include <bits/stdc++.h>
|
|
using namespace std;
|
|
|
|
#include <ext/pb_ds/tree_policy.hpp>
|
|
#include <ext/pb_ds/assoc_container.hpp>
|
|
using namespace __gnu_pbds;
|
|
template <class T> using Tree = tree<T, null_type, less<T>,
|
|
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<int> 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";
|
|
}
|
|
}
|
|
```
|
|
|
|
</spoiler>
|
|
|
|
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<int>` would remove duplicates. Instead, we would use an indexed set of pairs (`Tree<pair<int,int>>`), where the first element of each pair would denote the value while the second would denote the array position.
|
|
|
|
## Practice Problems
|
|
|
|
- Haircut, Balanced Photo, and Circle Cross are just variations on inversion counting.
|
|
|
|
<problems-list problems={metadata.problems.practice} />
|