structpoint { ll x, y; booloperator<(point rhs) const { return x != rhs.x ? x < rhs.x : y < rhs.y; } ll cross(point rhs)const{ return x * rhs.y - y * rhs.x; } point operator-(point rhs) const { return {x - rhs.x, y - rhs.y}; } point operator+(point rhs) const { return {x + rhs.x, y + rhs.y}; } booloperator==(point rhs) const { return x == rhs.x && y == rhs.y; } };
classDynConvex { std::set<point> lower, upper; // 上下凸壳 void _insert_lower(point p) { auto position = lower.lower_bound(p); std::vector<point> trash;
if (position != lower.end()) { auto it = position; if (it != lower.end()) { auto itt = std::next(it); while (it != lower.end() && itt != lower.end() && (*it - p).cross(*itt - p) <= 0) { trash.push_back(*it); it++, itt++; } } }
if (position != lower.begin()) { auto it = std::prev(position); if (it != lower.begin()) { auto itt = std::prev(it);
while ((*it - *itt).cross(p - *itt) <= 0) { trash.push_back(*it); if (itt == lower.begin()) break; it--, itt--; } } }
if (position == lower.begin() || position == lower.end()) lower.insert(p); else { auto pv = std::prev(position), nx = position; if ((p - *pv).cross(p - *nx) <= 0) lower.insert(p); } for (auto x : trash) lower.erase(x); } void _insert_upper(point p) { auto position = upper.lower_bound(p); std::vector<point> trash;
if (position != upper.end()) { auto it = position; if (it != upper.end()) { auto itt = std::next(it); while (true) { if (it == upper.end() || itt == upper.end()) break; if ((*it - *itt).cross(p - *itt) > 0) break; trash.push_back(*it); it++, itt++; } } }
if (position != upper.begin()) { auto it = std::prev(position); if (it != upper.begin()) { auto itt = std::prev(it);
while ((*it - p).cross(*itt - p) <= 0) { trash.push_back(*it); if (itt == upper.begin()) break; it--, itt--; } } }
if (position == upper.begin() || position == upper.end()) upper.insert(p); else { auto pv = std::prev(position), nx = position; if ((p - *pv).cross(p - *nx) >= 0) upper.insert(p); } for (auto x : trash) upper.erase(x); }