Find minimum value of y for the given x values in Q queries from all the given set of lines
Last Updated :
16 Sep, 2022
Given a 2-dimensional array arr[][] consisting of slope(m) and intercept(c) for a large number of lines of the form y = mx + c and Q queries such that each query contains a value x. The task is to find the minimum value of y for the given x values from all the given sets of lines.
Examples:
Input: arr[][] ={ {1, 1}, {0, 0}, {-3, 3} }, Q = {-2, 2, 0}
Output: -1, -3, 0
Explanation:
For query x = -2, y values from the equations are -1, 0, 9. So the minimum value is -1
Similarly, for x = 2, y values are 3, 0, -3. So the minimum value is -3
And for x = 0, values of y = 1, 0, 3 so min value is 0.
Input: arr[][] ={ {5, 6}, {3, 2}, {7, 3} }, Q = { 1, 2, 30 }
Output: 5, 8, 92
Naive Approach: The naive approach is to substitute the values of x in every line and compute the minimum 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 minimal 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 minimum 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++
// 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 arent 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 minimum value
// of y for the given x coordinate
int minQuery(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, 0 };
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.minQuery(x) << endl;
}
return 0;
}
Java
// Java implementation of the above approach
import java.util.ArrayList;
import java.util.Arrays;
class GFG{
static class Line implements Comparable<Line>
{
int m, c;
public Line(int m, int c)
{
this.m = m;
this.c = c;
}
// Sort the line in decreasing
// order of their slopes
@Override
public int compareTo(Line l)
{
// If slopes arent equal
if (m != l.m)
return l.m - this.m;
// If the slopes are equal
else
return l.c - this.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
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 = new ArrayList<>();
// 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.get(n - 2),
l.get(n - 1), newLine))
{
n--;
}
// l = new Line[n];
// Add the present line
l.add(newLine);
}
// Function to return the y coordinate
// of the specified line for the given
// coordinate
int value(int in, int x)
{
return l.get(in).m * x + l.get(in).c;
}
// Function to Return the minimum value
// of y for the given x coordinate
int minQuery(int x)
{
// If there is no lines
if (l.isEmpty())
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);
}
};
// Driver code
public static void main(String[] args)
{
Line[] lines = { new Line(1, 1),
new Line(0, 0),
new Line(-3, 3) };
int Q[] = { -2, 2, 0 };
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.minQuery(x));
}
}
}
// This code is contributed by sanjeev2552
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 minimum value
# of y for the given x coordinate
def minQuery(self, x):
# if there is no lines
if (len(self.l) == 0):
return 99999999999;
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, 0 ];
n = 3
q = 3;
cht = Convex_HULL_Trick();
# Sort the lines
lines.sort()
# 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.minQuery(x));
# This code is contributed by phasing17
C#
// C# implementation of the above approach
using System;
using System.Collections.Generic;
using System.Collections;
class Line : IComparable<Line> {
public int m, c;
public Line(int m, int c)
{
this.m = m;
this.c = c;
}
// Sort the line in decreasing
// order of their slopes
public int CompareTo(Line l)
{
// If slopes arent equal
if (m != l.m)
return l.m - this.m;
// If the slopes are equal
else
return l.c - this.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
public List<Line> 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--;
}
// l = new Line[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 minimum value
// of y for the given x coordinate
public int minQuery(int x)
{
// If there is no lines
if (l.Count == 0)
return Int32.MaxValue;
int low = 0, high = 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 {
// Driver code
public static void Main(string[] args)
{
Line[] lines = { new Line(1, 1), new Line(0, 0),
new Line(-3, 3) };
int[] Q = { -2, 2, 0 };
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.minQuery(x));
}
}
}
// This code is contributed by phasing17
JavaScript
// JavaScript 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
cmp()
{
// If slopes arent 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 = [];
}
// 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--;
}
// 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 minimum value
// of y for the given x coordinate
minQuery( x)
{
// if there is no lines
if ((this.l).length == 0)
return 99999999999;
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, 0 ];
let n = 3, q = 3;
let cht = new Convex_HULL_Trick();
// Sort the lines
lines.sort()
// 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++) {
let x = Q[i];
console.log(cht.minQuery(x));
}
// This code is contributed by phasing17
Time Complexity: O(max(N*logN, Q*logN)), as we are using an inbuilt sort function to sort an array of size N which will cost O(N*logN) and we are using a loop to traverse Q times and in each traversal, we are calling the method minQuery which costs logN time. Where N is the number of lines and Q is the number of queries.
Auxiliary Space: O(N), as we are using extra space.
Similar Reads
Find the maximum value of Y for a given X from given set of lines 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
12 min read
Find X and Y intercepts of a line passing through the given points Given two points on a 2D plane, the task is to find the x - intercept and the y - intercept of a line passing through the given points.Examples: Input: points[][] = {{5, 2}, {2, 7}} Output: 6.2 10.333333333333334Input: points[][] = {{3, 2}, {2, 4}} Output: 4.0 8.0 Approach: Find the slope using the
7 min read
Replace all occurrences of X by Y or add element K in Array for Q queries Given an empty array A[] & Q queries of two types 1 and 2 represented by queries1 and queries2 respectively, the task is to find the final state of the array. The queries are of the following type: If type[i]=1, insert queries1[i] (say K) to the end of the array A. The value of queries2[i] = -1
7 min read
Count of intersecting lines formed from every possible pair of given points Given two arrays of integers, X and Y representing points in the X-Y plane. Calculate the number of intersecting pairs of line segments formed from every possible pair of coordinates. Example: Input: X = [0, 1, 0, 1], Y = [0, 1, 3, 2] Output: 14 Explanation: For simplicity let's denote A = [0, 0], B
15+ min read
Find points at a given distance on a line of given slope Given the co-ordinates of a 2-dimensional point p(x0, y0). Find the points at a distance L away from it, such that the line formed by joining these points has a slope of M.Examples: Input : p = (2, 1) L = sqrt(2) M = 1Output :3, 2 1, 0Explanation:The two points are sqrt(2) distance away from the sou
8 min read
Find the sum of diagonals passing through given coordinates for Q query Given a 2D matrix of size N x M and Q queries where each query represents a coordinate (x, y) of the matrix, the task is to find the sum of all elements lying in the diagonals that pass through the given point. Examples: Input: N = 4, M = 4, mat[][] = {{1, 2, 2, 1}, {2, 4, 2, 4}, {2, 2, 3, 1}, {2, 4
12 min read