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:Â
CPP
// 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; } |
Python3
# Python3 implementation of the above approach class Line:     def __init__( self , a = 0 , b = 0 ):         self .m = a;         self .c = b;           # Sort the line in decreasing     # order of their slopes     def __gt__( self , l):               # If slopes arent equal         if ( self .m ! = l.m):             return self .m > l.m; Â
        # If the slopes are equal         else :             return self .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     def check( self , L1, L2, L3):               return (L3.c - L1.c) * (L1.m - L2.m) < (L2.c - L1.c) * (L1.m - L3.m);       class Convex_HULL_Trick : Â
    # To store the lines     def __init__( self ):               self .l = [];           # Add the line to the set of lines     def add( self , newLine):         n = len ( self .l) Â
        # To check if after adding the new line         # whether old lines are         # losing significance or not         while (n > = 2 and newLine.check(( self .l)[n - 2 ], ( self .l)[n - 1 ], newLine)):             n - = 1 ;                   # Add the present line         ( self .l).append(newLine);           # Function to return the y coordinate     # of the specified line for the given coordinate     def value( self , ind, x):         return ( self .l)[ind].m * x + ( self .l)[ind].c;                 # Function to Return the maximum value     # of y for the given x coordinate     def maxQuery( self , x):              # if there is no lines         if ( len ( self .l) = = 0 ):             return 999999999 ; Â
        low = 0         high = len ( self .l) - 2 ; Â
        # Binary search         while (low < = high):             mid = int ((low + high) / 2 ); Â
            if ( self .value(mid, x) < self .value(mid + 1 , x)):                 low = mid + 1 ;             else :                 high = mid - 1 ;                  return self .value(low, x);      # Driver code lines = [ Line( 1 , 1 ), Line( 0 , 0 ), Line( - 3 , 3 )] Â
Q = [ - 2 , 2 , 1 ]; n = 3 q = 3 ; cht = Convex_HULL_Trick(); Â
# Sort the lines lines.sort(reverse = True ) Â
# Add the lines for i in range (n): Â Â Â Â cht.add(lines[i]); Â
# For each query in Q for i in range (q): Â Â Â Â x = Q[i]; Â Â Â Â print (cht.maxQuery(x)); Â Â # This code is contributed by phasing17. |
C#
// C# implementation of // the above approach Â
using System; using System.Collections.Generic; Â
class Line : IComparable<Line> { Â Â public int m, c; Â
  public Line( int m1, int c1)   {     m = m1;     c = c1;   } Â
  // Sort the line in decreasing   // order of their slopes   public int CompareTo(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   public 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);   } }; Â
class Convex_HULL_Trick { Â
  // To store the lines   List<Line> l; Â
  public Convex_HULL_Trick() { l = new List<Line>(); } Â
  // Add the line to the set of lines   public void add(Line newLine)   { Â
    int n = l.Count; Â
    // 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--;     } Â
    // Add the present line     l.Add(newLine);   } Â
  // Function to return the y coordinate   // of the specified line   // for the given coordinate   public int value( int ind, int x)   {     return l[ind].m * x + l[ind].c;   } Â
  // Function to Return the maximum value   // of y for the given x coordinate   public int maxQuery( int x)   {     // if there is no lines     if (l.Count == 0)       return Int32.MaxValue; Â
    int low = 0, high = ( int )l.Count - 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);   } }; Â
class GFG { Â
  public static void Main( string [] args)   {     Line[] lines = { new Line(1, 1), new Line(0, 0),                     new Line(-3, 3) };     int [] Q = { -2, 2, 1 };     int n = 3, q = 3;     Convex_HULL_Trick cht = new Convex_HULL_Trick(); Â
    // Sort the lines     Array.Sort(lines); Â
    // 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];       Console.WriteLine(cht.maxQuery(x));     }   } } Â
// This code is contributed by phasing17 |
Javascript
// JS implementation of // the above approach Â
class Line {     constructor(a = 0, b = 0 )     {         this .m = a         this .c = b     } Â
Â
Â
    // Sort the line in decreasing     // order of their slopes      compare (l)     { Â
        // If slopes aren't equal         if ( this .m != l.m)             return this .m > l.m; Â
        // If the slopes are equal         else             return this .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      check(L1, L2, L3)     {         return (L3.c - L1.c) * (L1.m - L2.m)             < (L2.c - L1.c) * (L1.m - L3.m);     } }; Â
class Convex_HULL_Trick { Â
    // To store the lines     constructor()     {         this .l = new Array();      } Â
    // Add the line to the set of lines      add( newLine)     { Â
        let n = ( this .l).length; Â
        // To check if after adding the new line         // whether old lines are         // losing significance or not         while (n >= 2             && newLine.check(( this .l)[n - 2],                                 ( this .l)[n - 1],                                 newLine)) {             n--;         }                  while (( this .l).length > n)             ( this .l).pop();                   while (( this .l).length < n)             ( this .l).push( new Line());          Â
        // Add the present line         ( this .l).push(newLine);     } Â
    // Function to return the y coordinate     // of the specified line     // for the given coordinate      value(ind, x)     {         return ( this .l)[ind].m * x + ( this .l)[ind].c;     } Â
    // Function to Return the maximum value     // of y for the given x coordinate      maxQuery( x)     {         // if there is no lines         if (( this .l).length == 0)             return 999999999; Â
        let low = 0,             high = ( this .l).length - 2; Â
        // Binary search         while (low <= high) {             let mid = Math.floor((low + high) / 2); Â
            if ( this .value(mid, x)    < this .value(mid + 1, x))                 low = mid + 1;             else                 high = mid - 1;         } Â
        return this .value(low, x);     } }; Â
// Driver code let lines = [ new Line(1, 1), new Line(0, 0), new Line(-3, 3)] Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â let Q = [ -2, 2, 1 ]; let n = 3, q = 3; let cht = new Convex_HULL_Trick(); Â
    // Sort the lines     lines.sort( function (a, b)     {         if (a.m == b.m)             return a.c < b.c;        return a.m < b.c;     })      Â
    // Add the lines     for ( var i = 0; i < n; i++)         cht.add(lines[i]); Â
    // For each query in Q     for ( var i = 0; i < q; i++) {         var x = Q[i];         console.log(cht.maxQuery(x))     } Â
// This code is contributed by phasing17 |
Java
// Java implementation of // the above approach Â
import java.util.*; Â
Â
class GFG { Â
static class Line implements Comparable<Line> { Â Â public int m, c; Â
  public Line( int m1, int c1)   {     m = m1;     c = c1;   } Â
  // Sort the line in decreasing   // order of their slopes   public int compareTo(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   public boolean check(Line L1, Line L2, Line L3)   {     return (L3.c - L1.c) * (L1.m - L2.m)       < (L2.c - L1.c) * (L1.m - L3.m);   } }; Â
static class Convex_HULL_Trick { Â
  // To store the lines   ArrayList<Line> l; Â
  public Convex_HULL_Trick() { l = new ArrayList<Line>(); } Â
  // Add the line to the set of lines   public 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.get(n - 2 ), l.get(n - 1 ), newLine)) {       n--;     } Â
    // Add the present line     l.add(newLine);   } Â
  // Function to return the y coordinate   // of the specified line   // for the given coordinate   public int value( int ind, int x)   {     return (l.get(ind)).m * x + (l.get(ind)).c;   } Â
  // Function to Return the maximum value   // of y for the given x coordinate   public int maxQuery( int x)   {     // if there is no lines     if (l.size() == 0 )       return Integer.MAX_VALUE; Â
    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);   } }; Â
  public static void main(String[] args)   {     Line[] lines = { new Line( 1 , 1 ), new Line( 0 , 0 ),                     new Line(- 3 , 3 ) };     int [] Q = { - 2 , 2 , 1 };     int n = 3 , q = 3 ;     Convex_HULL_Trick cht = new Convex_HULL_Trick(); Â
    // Sort the lines     Arrays.sort(lines); Â
    // 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];       System.out.println(cht.maxQuery(x));     }   } } Â
// This code is contributed by phasing17 |
9 3 2
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!