Introduction To C++
Introduction To C++
Introduction
This guide covers some USACO basics, a review of common data structures and algorithms, and some tips and
tricks for the USACO contests.
Like our C++ doc, it is a work in progress. If you find that you would like more detail on one of these topics, or on a
topic that’s not covered here, please let Ian know.
C++ Vectors
In C++, a vector is a dynamic array that can grow or shrink as needed. The memory representation is similar to
that of a regular array. It stores the elements in a contiguous block of memory, and each element is accessed using
an index. If more elements are added to the vector than the allocated memory can hold, the vector automatically
allocates a larger block of memory and copies the existing elements to the new block. (It’s important to remember
that even though C++ does this resizing and copying for you under the hood, you still pay the cost of it!)
Some competitive programmers use arrays with a defined maximum size instead of vectors. This runs slightly
faster, as it avoids reallocation of memory and other overhead. However, vectors are more convenient overall, as
they have more built-in functions than arrays. Using an array instead of a vector will rarely mean the difference
between passing and failing a test case.
Binary Search
Binary search is a technique that can be used to find the first value in some search space S that satisfies some
condition f (x) in O(log N ) time. The idea is to split S in half each time, and to check if the value at the midpoint
satisfies the condition. If it does, then we can search the left half of S, and if it doesn’t, then we can search the right
half of S.
This is a little abstract, so let’s give a concrete example. You can play the following guessing game with a friend:
ask them to secretly think of a number between 1 and 1000, and claim you will guess their number after asking at
most ten questions of the form: is it larger than, smaller than, or equal to ¡some number¿? 4 Our strategy is to use
3 This is a singly-linked list. In a doubly linked list, each node also has a reference back to its predecessor. Sometimes, when designing a data
structure that involves a linked list, you will find that you need this property.
4 We leave it as an exercise to figure out how the ”ten” and 1000 are related. One elegant way to look at it is: what are all the possible sequences
of responses that your friend could give you, and how many of those are there? Could we even offer our friend a range larger than [1, 1000], while
still guaranteeing that we only need at most ten guesses?
Example Implementation
Suppose we need to search for the smallest value in a sorted vector v that is greater than or equal to some value
x.
The below code implements the algorithm from the previous section. At every step, we check the value of the
midpoint is in relation to x, and change the bounds of our search space accordingly.
int lo = 0, hi = v.size() - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (v[mid] < x) lo = mid + 1;
else hi = mid;
}
// lo is now the index of the first element in v that is >= x
// if no such element exists, then lo == v.size()
// we should also check if v[lo] == x, if that’s necessary
We use lo + (hi - lo) / 2 instead of (lo + hi) / 2 to avoid overflow, as lo + hi could be greater than
INT MAX.
Built-in Functions
There are two functions in C++ that are very similar to binary search, called lower bound and upper bound.
lower bound returns an iterator5 to the first element in a sorted vector that is greater than or equal to some value x,
and upper bound returns an iterator to the first element in a sorted vector that is greater than x.
int index = lower_bound(v.begin(), v.end(), x) - v.begin();
5 Iterators are memory addresses to elements in a vector. To get the index of an iterator, you can subtract the iterator from the beginning of
the vector.