Apart from std::transform we used two algorithms:
std::minmax_element simply accepts the begin and end iterators of an input range. It loops through the range and records the largest and the smallest element on the way to its end. These values are returned in a pair, which we then used for our scaling function.
The std::clamp function, in contrast, does not operate on an iterable range. It accepts three values: an input value, a min value, and a max value. The output of this function is the input value cut-off in a way that it lies between the allowed minimum and maximum. We could also write max(min_val, min(max_val, x)) instead of std::clamp(x, min_val, max_val).