Given a set of lines represented by a 2-dimensional array arr consisting of slope(m) and intercept(c) respectively and Q queries such that each query contains a value x. The task is to find the maximum value of y for each value of x from all the given a set of lines.
The given lines are represented by the equation y = m*x + c.
Examples:
Input: arr[][2] ={ {1, 1}, {0, 0}, {-3, 3} }, Q = {-2, 2, 1}
Output: 9, 3, 2
For query x = -2, y values from the equations are -1, 0, 9. So the maximum value is 9
Similarly, for x = 2, y values are 3, 0, -3. So the maximum value is 3
And for x = 1, values of y = 2, 0, 0. So the maximum value is 2.Input: arr[][] ={ {5, 6}, {3, 2}, {7, 3} }, Q = { 1, 2, 30 }
Output: 10, 17, 213
Naive Approach: The naive approach is to substitute the values of x in every line and compute the maximum of all the lines. For each query, it will take O(N) time and so the complexity of the solution becomes O(Q * N) where N is the number of lines and Q is the number of queries.
Efficient approach: The idea is to use convex hull trick:
- From the given set of lines, the lines which carry no significance (for any value of x they never give the maximal value y) can be found and deleted thereby reducing the set.
- Now, if the ranges (l, r) can be found where each line gives the maximum value, then each query can be answered using binary search.
- Therefore, a sorted vector of lines, with decreasing order of slopes, is created and the lines are inserted in decreasing order of the slopes.
Below is the implementation of the above approach:
// C++ implementation of // the above approach #include <bits/stdc++.h> using namespace std; struct Line { int m, c; public : // Sort the line in decreasing // order of their slopes bool operator<(Line l) { // If slopes aren't equal if (m != l.m) return m > l.m; // If the slopes are equal else return c > l.c; } // Checks if line L3 or L1 is better than L2 // Intersection of Line 1 and // Line 2 has x-coordinate (b1-b2)/(m2-m1) // Similarly for Line 1 and // Line 3 has x-coordinate (b1-b3)/(m3-m1) // Cross multiplication will // give the below result bool check(Line L1, Line L2, Line L3) { return (L3.c - L1.c) * (L1.m - L2.m) < (L2.c - L1.c) * (L1.m - L3.m); } }; struct Convex_HULL_Trick { // To store the lines vector<Line> l; // Add the line to the set of lines void add(Line newLine) { int n = l.size(); // To check if after adding the new line // whether old lines are // losing significance or not while (n >= 2 && newLine.check(l[n - 2], l[n - 1], newLine)) { n--; } l.resize(n); // Add the present line l.push_back(newLine); } // Function to return the y coordinate // of the specified line // for the given coordinate int value( int in, int x) { return l[in].m * x + l[in].c; } // Function to Return the maximum value // of y for the given x coordinate int maxQuery( int x) { // if there is no lines if (l.empty()) return INT_MAX; int low = 0, high = ( int )l.size() - 2; // Binary search while (low <= high) { int mid = (low + high) / 2; if (value(mid, x) < value(mid + 1, x)) low = mid + 1; else high = mid - 1; } return value(low, x); } }; // Driver code int main() { Line lines[] = { { 1, 1 }, { 0, 0 }, { -3, 3 } }; int Q[] = { -2, 2, 1 }; int n = 3, q = 3; Convex_HULL_Trick cht; // Sort the lines sort(lines, lines + n); // Add the lines for ( int i = 0; i < n; i++) cht.add(lines[i]); // For each query in Q for ( int i = 0; i < q; i++) { int x = Q[i]; cout << cht.maxQuery(x) << endl; } return 0; } |
9 3 2
Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.