1
- //! A generic implementation of Mo's algorithm, aka Query Sqrt Decomposition.
2
- //! It answers q offline queries over intervals in 0..n by shifting the query
3
- //! interval's endpoints by one position at a time.
4
- //! Each endpoint incurs a total cost of at most n * sqrt(q * L_OP * R_OP).
5
-
1
+ /// A generic implementation of Mo's algorithm, aka Query Sqrt Decomposition.
2
+ /// It answers q offline queries over intervals in 0..n by shifting the query
3
+ /// interval's endpoints by one position at a time.
4
+ /// Each endpoint incurs a total cost of at most n * sqrt(q * L_OP * R_OP).
6
5
pub trait MoState {
7
6
type Q ;
8
7
type A ;
@@ -102,6 +101,53 @@ impl MoState for DistinctVals {
102
101
}
103
102
}
104
103
104
+ /// Represents a minimum (lower envelope) of a collection of linear functions of a variable,
105
+ /// evaluated using the convex hull trick with square root decomposition.
106
+ pub struct PiecewiseLinearFn {
107
+ sorted_lines : Vec < ( i64 , i64 ) > ,
108
+ recent_lines : Vec < ( i64 , i64 ) > ,
109
+ merge_threshold : usize ,
110
+ }
111
+
112
+ impl PiecewiseLinearFn {
113
+ /// For N inserts interleaved with Q queries, a threshold of N/sqrt(Q) yields
114
+ /// O(N sqrt Q + Q log N) time complexity. If all queries come after all inserts,
115
+ /// a threshold of 0 yields O(N + Q log N) time complexity.
116
+ pub fn with_merge_threshold ( merge_threshold : usize ) -> Self {
117
+ Self {
118
+ sorted_lines : vec ! [ ] ,
119
+ recent_lines : vec ! [ ] ,
120
+ merge_threshold,
121
+ }
122
+ }
123
+
124
+ /// Replaces this function with the minimum of itself and a provided line
125
+ pub fn min_with ( & mut self , slope : i64 , intercept : i64 ) {
126
+ self . recent_lines . push ( ( slope, intercept) ) ;
127
+ }
128
+
129
+ fn update_envelope ( & mut self ) {
130
+ self . recent_lines . extend ( self . sorted_lines . drain ( ..) ) ;
131
+ self . recent_lines . sort_unstable ( ) ;
132
+ for ( slope, intercept) in self . recent_lines . drain ( ..) {
133
+ // TODO: do convex hull trick algorithm
134
+ self . sorted_lines . push ( ( slope, intercept) ) ;
135
+ }
136
+ }
137
+
138
+ fn eval_helper ( & self , x : i64 ) -> i64 {
139
+ 0 // TODO: pick actual minimum, or infinity if empty
140
+ }
141
+
142
+ /// Evaluates the function at x
143
+ pub fn evaluate ( & mut self , x : i64 ) -> i64 {
144
+ if self . recent_lines . len ( ) > self . merge_threshold {
145
+ self . update_envelope ( ) ;
146
+ }
147
+ self . eval_helper ( x)
148
+ }
149
+ }
150
+
105
151
#[ cfg( test) ]
106
152
mod test {
107
153
use super :: * ;
@@ -115,4 +161,10 @@ mod test {
115
161
116
162
assert_eq ! ( answers, vec![ 2 , 1 , 5 , 5 ] ) ;
117
163
}
164
+
165
+ #[ test]
166
+ fn test_convex_hull_trick ( ) {
167
+ let mut func = PiecewiseLinearFn :: with_merge_threshold ( 3 ) ;
168
+ // TODO: make test
169
+ }
118
170
}
0 commit comments