Consider the following problem. There are <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>n</mi></math>$n$ cities. You want to travel from city <math xmlns="http://www.w3.org/1998/Math/MathML"><mn>1</mn></math>$1$ to city <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>n</mi></math>$n$ by car. To do this you have to buy some gasoline. It is known that a liter of gasoline costs <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>c</mi><mi>o</mi><mi>s</mi><msub><mi>t</mi><mi>k</mi></msub></math>$cost_k$ in the <math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>k</mi><mrow data-mjx-texclass="ORD"><mi>t</mi><mi>h</mi></mrow></msup></math>$k^{th}$ city. Initially your fuel tank is empty and you spend one liter of gasoline per kilometer. Cities are located on the same line in ascending order with <math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>k</mi><mrow data-mjx-texclass="ORD"><mi>t</mi><mi>h</mi></mrow></msup></math>$k^{th}$ city having coordinate <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>x</mi><mi>k</mi></msub></math>$x_k$. Also you have to pay <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>t</mi><mi>o</mi><mi>l</mi><msub><mi>l</mi><mi>k</mi></msub></math>$toll_k$ to enter <math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mi>k</mi><mrow data-mjx-texclass="ORD"><mi>t</mi><mi>h</mi></mrow></msup></math>$k^{th}$ city. Your task is to make the trip with minimum possible cost. It's obvious that the solution can be calculated via dynamic programming:
Naive approach will give you <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>O</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mn>2</mn></msup><mo stretchy="false">)</mo></math>$O(n^2)$ complexity which can be improved to <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mi>log</mi><mo data-mjx-texclass="NONE"></mo><mi>n</mi><mo stretchy="false">)</mo></math>$O(n \log n)$ or <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>O</mi><mo stretchy="false">(</mo><mi>n</mi><mi>log</mi><mo data-mjx-texclass="NONE"></mo><mo stretchy="false">[</mo><mi>C</mi><msup><mi>ε</mi><mrow data-mjx-texclass="ORD"><mo>−</mo><mn>1</mn></mrow></msup><mo stretchy="false">]</mo><mo stretchy="false">)</mo></math>$O(n \log [C \varepsilon^{-1}])$ where <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>C</mi></math>$C$ is largest possible <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">|</mo><msub><mi>x</mi><mi>i</mi></msub><mo stretchy="false">|</mo></math>$|x_i|$ and <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>ε</mi></math>$\varepsilon$ is precision with which <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>x</mi><mi>i</mi></msub></math>$x_i$ is considered (<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>ε</mi><mo>=</mo><mn>1</mn></math>$\varepsilon = 1$ for integers which is usually the case). To do this one should note that the problem can be reduced to adding linear functions <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi><mo>⋅</mo><mi>x</mi><mo>+</mo><mi>b</mi></math>$k \cdot x + b$ to the set and finding minimum value of the functions in some particular point <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>$x$. There are two main approaches one can use here.
The idea of this approach is to maintain a lower convex hull of linear functions.
Actually it would be a bit more convenient to consider them not as linear functions, but as points <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>k</mi><mo>;</mo><mi>b</mi><mo stretchy="false">)</mo></math>$(k;b)$ on the plane such that we will have to find the point which has the least dot product with a given point <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>x</mi><mo>;</mo><mn>1</mn><mo stretchy="false">)</mo></math>$(x;1)$, that is, for this point <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi><mi>x</mi><mo>+</mo><mi>b</mi></math>$kx+b$ is minimized which is the same as initial problem.
Such minimum will necessarily be on lower convex envelope of these points as can be seen below:
One has to keep points on the convex hull and normal vectors of the hull's edges.
When you have a <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>x</mi><mo>;</mo><mn>1</mn><mo stretchy="false">)</mo></math>$(x;1)$ query you'll have to find the normal vector closest to it in terms of angles between them, then the optimum linear function will correspond to one of its endpoints.
To see that, one should note that points having a constant dot product with <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>x</mi><mo>;</mo><mn>1</mn><mo stretchy="false">)</mo></math>$(x;1)$ lie on a line which is orthogonal to <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>x</mi><mo>;</mo><mn>1</mn><mo stretchy="false">)</mo></math>$(x;1)$, so the optimum linear function will be the one in which tangent to convex hull which is collinear with normal to <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>x</mi><mo>;</mo><mn>1</mn><mo stretchy="false">)</mo></math>$(x;1)$ touches the hull.
This point is the one such that normals of edges lying to the left and to the right of it are headed in different sides of <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>x</mi><mo>;</mo><mn>1</mn><mo stretchy="false">)</mo></math>$(x;1)$.
This approach is useful when queries of adding linear functions are monotone in terms of <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$ or if we work offline, i.e. we may firstly add all linear functions and answer queries afterwards.
So we cannot solve the cities/gasoline problems using this way.
That would require handling online queries.
When it comes to deal with online queries however, things will go tough and one will have to use some kind of set data structure to implement a proper convex hull.
Online approach will however not be considered in this article due to its hardness and because second approach (which is Li Chao tree) allows to solve the problem way more simply.
Worth mentioning that one can still use this approach online without complications by square-root-decomposition.
That is, rebuild convex hull from scratch each <math xmlns="http://www.w3.org/1998/Math/MathML"><msqrt><mi>n</mi></msqrt></math>$\sqrt n$ new lines.
To implement this approach one should begin with some geometric utility functions, here we suggest to use the C++ complex number type.
typedefintftype;typedefcomplex<ftype>point;#define x real#define y imagftypedot(pointa,pointb){return(conj(a)*b).x();}ftypecross(pointa,pointb){return(conj(a)*b).y();}
Here we will assume that when linear functions are added, their <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>k</mi></math>$k$ only increases and we want to find minimum values.
We will keep points in vector <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>h</mi><mi>u</mi><mi>l</mi><mi>l</mi></math>$hull$ and normal vectors in vector <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>v</mi><mi>e</mi><mi>c</mi><mi>s</mi></math>$vecs$.
When we add a new point, we have to look at the angle formed between last edge in convex hull and vector from last point in convex hull to new point.
This angle has to be directed counter-clockwise, that is the dot product of the last normal vector in the hull (directed inside hull) and the vector from the last point to the new one has to be non-negative.
As long as this isn't true, we should erase the last point in the convex hull alongside with the corresponding edge.
Now to get the minimum value in some point we will find the first normal vector in the convex hull that is directed counter-clockwise from <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">(</mo><mi>x</mi><mo>;</mo><mn>1</mn><mo stretchy="false">)</mo></math>$(x;1)$. The left endpoint of such edge will be the answer. To check if vector <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>a</mi></math>$a$ is not directed counter-clockwise of vector <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>b</mi></math>$b$, we should check if their cross product <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><mi>a</mi><mo>,</mo><mi>b</mi><mo stretchy="false">]</mo></math>$[a,b]$ is positive.
Assume you're given a set of functions such that each two can intersect at most once. Let's keep in each vertex of a segment tree some function in such way, that if we go from root to the leaf it will be guaranteed that one of the functions we met on the path will be the one giving the minimum value in that leaf. Let's see how to construct it.
Assume we're in some vertex corresponding to half-segment <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><mi>l</mi><mo>,</mo><mi>r</mi><mo stretchy="false">)</mo></math>$[l,r)$ and the function <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>f</mi><mrow data-mjx-texclass="ORD"><mi>o</mi><mi>l</mi><mi>d</mi></mrow></msub></math>$f_{old}$ is kept there and we add the function <math xmlns="http://www.w3.org/1998/Math/MathML"><msub><mi>f</mi><mrow data-mjx-texclass="ORD"><mi>n</mi><mi>e</mi><mi>w</mi></mrow></msub></math>$f_{new}$. Then the intersection point will be either in <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><mi>l</mi><mo>;</mo><mi>m</mi><mo stretchy="false">)</mo></math>$[l;m)$ or in <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><mi>m</mi><mo>;</mo><mi>r</mi><mo stretchy="false">)</mo></math>$[m;r)$ where <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>m</mi><mo>=</mo><mrow data-mjx-texclass="INNER"><mo data-mjx-texclass="OPEN">⌊</mo><mstyle displaystyle="false" scriptlevel="0"><mfrac><mrow><mi>l</mi><mo>+</mo><mi>r</mi></mrow><mn>2</mn></mfrac></mstyle><mo data-mjx-texclass="CLOSE">⌋</mo></mrow></math>$m=\left\lfloor\tfrac{l+r}{2}\right\rfloor$. We can efficiently find that out by comparing the values of the functions in points <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>l</mi></math>$l$ and <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>m</mi></math>$m$. If the dominating function changes, then it is in <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><mi>l</mi><mo>;</mo><mi>m</mi><mo stretchy="false">)</mo></math>$[l;m)$ otherwise it is in <math xmlns="http://www.w3.org/1998/Math/MathML"><mo stretchy="false">[</mo><mi>m</mi><mo>;</mo><mi>r</mi><mo stretchy="false">)</mo></math>$[m;r)$. Now for the half of the segment with no intersection we will pick the lower function and write it in the current vertex. You can see that it will always be the one which is lower in point <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>m</mi></math>$m$. After that we recursively go to the other half of the segment with the function which was the upper one. As you can see this will keep correctness on the first half of segment and in the other one correctness will be maintained during the recursive call. Thus we can add functions and check the minimum value in the point in <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>O</mi><mo stretchy="false">(</mo><mi>log</mi><mo data-mjx-texclass="NONE"></mo><mo stretchy="false">[</mo><mi>C</mi><msup><mi>ε</mi><mrow data-mjx-texclass="ORD"><mo>−</mo><mn>1</mn></mrow></msup><mo stretchy="false">]</mo><mo stretchy="false">)</mo></math>$O(\log [C\varepsilon^{-1}])$.
Here is the illustration of what is going on in the vertex when we add new function:
Let's go to implementation now. Once again we will use complex numbers to keep linear functions.
typedeflonglongftype;typedefcomplex<ftype>point;#define x real#define y imagftypedot(pointa,pointb){return(conj(a)*b).x();}ftypef(pointa,ftypex){returndot(a,{x,1});}
We will keep functions in the array <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>l</mi><mi>i</mi><mi>n</mi><mi>e</mi></math>$line$ and use binary indexing of the segment tree. If you want to use it on large numbers or doubles, you should use a dynamic segment tree.
The segment tree should be initialized with default values, e.g. with lines <math xmlns="http://www.w3.org/1998/Math/MathML"><mn>0</mn><mi>x</mi><mo>+</mo><mi mathvariant="normal">∞</mi></math>$0x + \infty$.
Now to get the minimum in some point <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>$x$ we simply choose the minimum value along the path to the point.