This repository has been archived on 2022-06-22. You can view files and clone it, but cannot push or open issues or pull requests.
usaco-guide/content/5_Gold/PURS.mdx
2020-06-24 16:08:16 -07:00

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} />