qwerty787788

Dynamic Convex Hull

Aug 30th, 2020
1,787
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 4.92 KB | None | 0 0
  1. import java.util.*;
  2.  
  3. public class DynamicConvexHullTest {
  4.     static class Line {
  5.         // ax + b
  6.         final long a, b;
  7.  
  8.         public Line(long a, long b) {
  9.             this.a = a;
  10.             this.b = b;
  11.         }
  12.  
  13.         long getValue(long x) {
  14.             return a * x + b;
  15.         }
  16.  
  17.         @Override
  18.         public String toString() {
  19.             return "Line{" +
  20.                     "a=" + a +
  21.                     ", b=" + b +
  22.                     '}';
  23.         }
  24.     }
  25.  
  26.     static class ConvexHull {
  27.         // find max
  28.         Line[] hull;
  29.  
  30.         ConvexHull(Line[] lines) {
  31.             Arrays.sort(lines, new Comparator<Line>() {
  32.                 @Override
  33.                 public int compare(Line o1, Line o2) {
  34.                     if (o1.b != o2.b) {
  35.                         return -Long.compare(o1.b, o2.b);
  36.                     }
  37.                     return -Long.compare(o1.a, o2.a);
  38.                 }
  39.             });
  40.             int sz = 1;
  41.             for (int i = 1; i < lines.length; i++) {
  42.                 while (sz > 1) {
  43.                     Line l2 = lines[sz - 2], l1 = lines[sz - 1];
  44.                     Line cur = lines[i];
  45.                     double t1 = whenBetter(l2, l1), t2 = whenBetter(l1, cur);
  46.                     if (t2 <= t1) {
  47.                         sz--;
  48.                     } else {
  49.                         break;
  50.                     }
  51.                 }
  52.                 lines[sz++] = lines[i];
  53.             }
  54.             hull = Arrays.copyOf(lines, sz);
  55.         }
  56.  
  57.         double whenBetter(Line l1, Line l2) {
  58.             // a1x + b1 < a2x + b2
  59.             // x * (a1 - a2) < b2 - b1
  60.             if (l1.a >= l2.a) {
  61.                 return Double.MAX_VALUE;
  62.             }
  63.             return (l1.b - l2.b) / (double) (l2.a - l1.a);
  64.         }
  65.  
  66.         long getMax(long x) {
  67.             if (hull.length == 1 || whenBetter(hull[0], hull[1]) > x) {
  68.                 return hull[0].getValue(x);
  69.             }
  70.             int l = 0, r = hull.length - 1;
  71.             while (r - l > 1) {
  72.                 int m = (l + r) >> 1;
  73.                 if (whenBetter(hull[m], hull[m + 1]) > x) {
  74.                     r = m;
  75.                 } else {
  76.                     l = m;
  77.                 }
  78.             }
  79.             return hull[r].getValue(x);
  80.         }
  81.  
  82.         static ConvexHull join(ConvexHull a, ConvexHull b) {
  83.             Line[] allLines = new Line[a.hull.length + b.hull.length];
  84.             System.arraycopy(a.hull, 0, allLines, 0, a.hull.length);
  85.             System.arraycopy(b.hull, 0, allLines, a.hull.length, b.hull.length);
  86.             return new ConvexHull(allLines);
  87.         }
  88.     }
  89.  
  90.     static class DynamicConvexHull {
  91.         final int LOG = 20;
  92.         ConvexHull[] hulls;
  93.  
  94.         DynamicConvexHull() {
  95.             hulls = new ConvexHull[LOG];
  96.         }
  97.  
  98.         void addConvexHull(ConvexHull convexHull) {
  99.             int id = Math.min(LOG - 1, (int) (Math.log(convexHull.hull.length) / Math.log(2)));
  100.             if (hulls[id] != null) {
  101.                 convexHull = ConvexHull.join(convexHull, hulls[id]);
  102.                 hulls[id] = null;
  103.                 addConvexHull(convexHull);
  104.             } else {
  105.                 hulls[id] = convexHull;
  106.             }
  107.         }
  108.  
  109.         void addLine(Line l) {
  110.             ConvexHull hull = new ConvexHull(new Line[]{l});
  111.             addConvexHull(hull);
  112.         }
  113.  
  114.         long getMax(long x) {
  115.             long res = Long.MIN_VALUE;
  116.             for (ConvexHull hull : hulls) {
  117.                 if (hull == null) {
  118.                     continue;
  119.                 }
  120.                 res = Math.max(res, hull.getMax(x));
  121.             }
  122.             return res;
  123.         }
  124.  
  125.     }
  126.  
  127.     static long slowFindMax(List<Line> lines, long pos) {
  128.         long res = Long.MIN_VALUE;
  129.         for (Line l : lines) {
  130.             res = Math.max(res, l.getValue(pos));
  131.         }
  132.         return res;
  133.     }
  134.  
  135.     public static void main(String[] args) {
  136.         Random rnd = new Random(123);
  137.         final int MAX = 1000;
  138.         for (int it = 0; it < 123123; it++) {
  139.             System.err.println("it = " + it);
  140.             final int lines = 1 + rnd.nextInt(100);
  141.             DynamicConvexHull dynamicConvexHull = new DynamicConvexHull();
  142.             List<Line> usedLines = new ArrayList<>();
  143.             for (int i = 0; i < lines; i++) {
  144.                 Line l = new Line(rnd.nextInt(MAX) - MAX / 2, rnd.nextInt(MAX) - MAX / 2);
  145.                 usedLines.add(l);
  146.                 dynamicConvexHull.addLine(l);
  147.                 long pos = rnd.nextInt(MAX);
  148.                 long checkedMax = dynamicConvexHull.getMax(pos);
  149.                 long correctMax = slowFindMax(usedLines, pos);
  150.                 if (checkedMax != correctMax) {
  151.                     throw new AssertionError("Incorrect max: " + correctMax + ", fast = " + checkedMax + ", i = " + i + ", pos = " + pos);
  152.                 }
  153.             }
  154.         }
  155.     }
  156. }
  157.  
Advertisement
Add Comment
Please, Sign In to add comment