1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
vector<ll> xs; // IMPORTANT: Initialize before constructing Lichao!
struct Fun{ // Default: Linear function. Change it to needed function type.
ll m, c;
ll operator()(int x){
return m*xs[x] + c;
}
};
// Default: Computes min. Change lines with comment for max.
struct Lichao{
const Fun id = {0, inf}; // {0, -inf}
int n, cap;
vector<Fun> seg;
Lichao(){
n = sz(xs);
for(cap = 1; cap < n; cap *= 2);
seg.assign(2*cap, id);
}
void myInsert(Fun f, int l, int r, int i){
while(i < 2*cap){
int m = (l+r)/2;
if(m >= n) {r = m; i = 2*i; continue;}
Fun &g = seg[i];
if(f(m) < g(m)) swap(f, g); // >
if(f(l) < g(l)) r = m, i = 2*i; // >
else l = m, i = 2*i+1;
}
}
void mySegmentInsert(Fun f, int l, int r, int a, int b, int i){
if(l <= a && b <= r) myInsert(f, a, b, i);
else if(a < r && l < b){
int m = (a+b)/2;
mySegmentInsert(f, l, r, a, m, 2*i);
mySegmentInsert(f, l, r, m, b, 2*i+1);
}
}
void insert(Fun f){myInsert(f, 0, cap, 1);}
void segmentInsert(Fun f, ll l, ll r){
mySegmentInsert(f, lower_bound(all(xs), l)-xs.begin(), lower_bound(all(xs), r)-xs.begin(), 0, cap, 1);
}
ll myQuery(int x){
int i = x+cap;
ll ans = seg[i](x);
while(i > 1) ans = min(ans, seg[i/=2](x)); // max
return ans;
}
ll query(ll x){return myQuery(lower_bound(all(xs),x)-xs.begin());}
};
|