#include #include using namespace std; struct Point { int x, y; Point(int _x = 0, int _y = 0) : x(_x), y(_y) {} bool operator<(const Point &other) const { return x < other.x || (x == other.x && y < other.y); } bool operator==(const Point &other) const { return x == other.x && y == other.y; } }; // Orientáce dvou úseček (a->b, a->c) pomocí skalárního součinu long long orientace(const Point &a, const Point &b, const Point &c) { long long ax = b.x - a.x; long long ay = b.y - a.y; long long bx = c.x - a.x; long long by = c.y - a.y; return ax * by - ay * bx; } // Mají úsečky (a->b, a->c) správnou orientaci v horní/dolní obálce bool je_spravna_orientace(const Point &a, const Point &b, const Point &c, bool je_pro_horni_obalku) { long long cp = orientace(a, b, c); if (je_pro_horni_obalku) { return cp < 0; } else { return cp > 0; } } // Vrací set všech bodů které se změnily set pridej_do_obalu(set &obal, const Point &p, bool horni) { if (obal.size() < 2) { obal.insert(p); return {p}; } auto pozice = obal.lower_bound(p); // Zkontroluj zda je bod uvnitř obalu if (pozice != obal.end() && p < *pozice && pozice != obal.begin()) { auto predchozi = pozice; --predchozi; if (!je_spravna_orientace(*predchozi, p, *pozice, horni)) { return {}; // Bod je uvnitř, žádná změna } } set zmeny; zmeny.insert(p); pozice = obal.insert(pozice, p); // Odstraň body vpravo které porušují konvexitu auto dalsi = pozice; ++dalsi; while (dalsi != obal.end()) { auto za_dalsim = dalsi; ++za_dalsim; if (za_dalsim == obal.end()) break; if (je_spravna_orientace(*pozice, *dalsi, *za_dalsim, horni)) break; zmeny.insert(*dalsi); obal.erase(dalsi); dalsi = pozice; ++dalsi; } // Odstraň body vlevo které porušují konvexitu while (pozice != obal.begin()) { auto predchozi = pozice; --predchozi; if (predchozi == obal.begin()) break; auto pred_predchozim = predchozi; --pred_predchozim; if (je_spravna_orientace(*pred_predchozim, *predchozi, *pozice, horni)) break; zmeny.insert(*predchozi); obal.erase(predchozi); pozice = obal.find(p); } return zmeny; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int N, K; cin >> N >> K; set horni_obal, dolni_obal; for (int i = 0; i < N; i++) { int x, y; cin >> x >> y; Point p(x, y); pridej_do_obalu(horni_obal, p, true); pridej_do_obalu(dolni_obal, p, false); } for (int j = 0; j < K; j++) { int x, y; cin >> x >> y; Point p(x, y); set zmeny_horni = pridej_do_obalu(horni_obal, p, true); set zmeny_dolni = pridej_do_obalu(dolni_obal, p, false); set vysledne_zmeny; // Nenastala žádná změna if (zmeny_horni.empty() && zmeny_dolni.empty()) { continue; } // Přidej změny z horního obalu, které nejsou v dolním for (const Point &bod : zmeny_horni) { if (dolni_obal.find(bod) == dolni_obal.end()) { vysledne_zmeny.insert(bod); } } // Přidej změny z dolního obalu, které nejsou v horním for (const Point &bod : zmeny_dolni) { if (horni_obal.find(bod) == horni_obal.end()) { vysledne_zmeny.insert(bod); } } // Pokud nastala nějaká změna, přidej nový bod if (!zmeny_horni.empty() || !zmeny_dolni.empty()) { vysledne_zmeny.insert(p); } for (const Point &bod : vysledne_zmeny) { cout << bod.x << " " << bod.y << " "; } if (!vysledne_zmeny.empty()) { cout << "\n"; } } return 0; }