-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathlowerConcaveHull.cpp
75 lines (75 loc) · 1.93 KB
/
lowerConcaveHull.cpp
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/*maintain a "concave hull" that support the following
1. insertion of a line
2. query of height(y) on specific x on the hull
****/
/* set as needed */
typedef long double LD;
const LD eps=1e-9;
const LD inf=1e19;
class Seg {
public:
LD m,c,x1,x2; // y=mx+c
bool flag;
Seg(
LD _m,LD _c,LD _x1=-inf,LD _x2=inf,bool _flag=0)
:m(_m),c(_c),x1(_x1),x2(_x2),flag(_flag) {}
LD evaly(LD x) const { return m*x+c;}
const bool operator<(LD x) const{return x2-eps<x;}
const bool operator<(const Seg &b) const {
if(flag||b.flag) return *this<b.x1;
return m+eps<b.m;
}
};
class LowerConcaveHull { // maintain a hull like: \__/
public:
set<Seg> hull;
/* functions */
LD xintersection(Seg a,Seg b)
{ return (a.c-b.c)/(b.m-a.m); }
inline set<Seg>::iterator replace(set<Seg> &
hull,set<Seg>::iterator it,Seg s) {
hull.erase(it);
return hull.insert(s).first;
}
void insert(Seg s) {
// insert a line and update hull
set<Seg>::iterator it=hull.find(s);
// check for same slope
if(it!=hull.end()) {
if(it->c+eps>=s.c) return;
hull.erase(it);
}
// check if below whole hull
it=hull.lower_bound(s);
if(it!=hull.end()&&
s.evaly(it->x1)<=it->evaly(it->x1)+eps) return;
// update right hull
while(it!=hull.end()) {
LD x=xintersection(s,*it);
if(x>=it->x2-eps) hull.erase(it++);
else {
s.x2=x;
it=replace(hull,it,Seg(it->m,it->c,x,it->x2));
break;
}
}
// update left hull
while(it!=hull.begin()) {
LD x=xintersection(s,*(--it));
if(x<=it->x1+eps) hull.erase(it++);
else {
s.x1=x;
it=replace(hull,it,Seg(it->m,it->c,it->x1,x));
break;
}
}
// insert s
hull.insert(s);
}
void insert(LD m,LD c) { insert(Seg(m,c)); }
LD query(LD x) { // return y @ given x
set<Seg>::iterator it =
hull.lower_bound(Seg(0.0,0.0,x,x,1));
return it->evaly(x);
}
};