1use crate::math::linear::*;
7use std::{
8 collections::VecDeque,
9 ops::{Add, Mul, Sub},
10};
11
12#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
14pub enum Mode {
15 Max,
17 Min,
19}
20
21impl Mode {
22 fn cmp<T: Ord + Copy>(self, a: T, b: T) -> bool {
23 match self {
24 Self::Max => a <= b,
25 Self::Min => a >= b,
26 }
27 }
28}
29
30fn is_needless<T>(a: &Linear<T>, b: &Linear<T>, c: &Linear<T>) -> bool
31where
32 T: Copy + Ord + Sub<Output = T> + Mul<Output = T>,
33{
34 (a.b - b.b) * (a.a - c.a) >= (a.b - c.b) * (a.a - b.a)
35}
36
37#[derive(Clone, Debug)]
39pub struct ConvexHullTrick<T> {
40 lines: VecDeque<Linear<T>>,
41 mode: Mode,
42 last_query: Option<T>,
43 last_slope: Option<T>,
44}
45
46impl<T> ConvexHullTrick<T>
47where
48 T: Copy + Ord + Sub<Output = T> + Mul<Output = T> + Add<Output = T>,
49{
50 pub fn new(mode: Mode) -> Self {
52 Self {
53 lines: VecDeque::new(),
54 mode,
55 last_query: None,
56 last_slope: None,
57 }
58 }
59
60 pub fn add(&mut self, line @ Linear { a, b }: Linear<T>) {
66 if let Some(p) = self.last_slope {
67 if !self.mode.cmp(p, a) {
68 panic!("`mode`が`Max`/`Min`ならば、`a`は単調増加/減少でなければならない。");
69 }
70 }
71 self.last_slope = Some(a);
72
73 if let Some(l) = self.lines.back() {
74 if l.a == a {
75 if !self.mode.cmp(l.b, b) {
76 return;
77 }
78 self.lines.pop_back();
79 }
80 }
81 while self.lines.len() >= 2
82 && is_needless(
83 &line,
84 self.lines.back().unwrap(),
85 self.lines.get(self.lines.len() - 2).unwrap(),
86 )
87 {
88 self.lines.pop_back();
89 }
90
91 self.lines.push_back(line);
92 }
93
94 pub fn query(&mut self, x: T) -> T {
98 if let Some(p) = self.last_query {
99 if x < p {
100 panic!("`x`はクエリ全体を通して単調増加でなければならない。");
101 }
102 }
103 self.last_query = Some(x);
104
105 while self.lines.len() >= 2
106 && self
107 .mode
108 .cmp(self.lines[0].apply(x), self.lines[1].apply(x))
109 {
110 self.lines.pop_front();
111 }
112
113 self.lines[0].apply(x)
114 }
115}