This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub maspypy/library
#include "geo/polygon_triangulation.hpp"
#include "geo/base.hpp" #include "ds/splaytree/splaytree_basic.hpp" #include "graph/planar_graph.hpp" template <typename T> vc<tuple<int, int, int>> monotone_polygon_triangulation(vc<Point<T>> point) { int N = len(point); int rot = min_element(all(point)) - point.begin(); rotate(point.begin(), point.begin() + rot, point.end()); int n = max_element(all(point)) - point.begin(); FOR(i, n) assert(point[i] < point[i + 1]); FOR(i, n, N) assert(point[(i + 1) % N] < point[i]); vc<tuple<int, int, int>> res; auto side = [&](int i) -> int { assert(i != 0 && i != n); return (i < n ? 0 : 1); }; vc<int> I = argsort(point); vc<int> stack = {I[0], I[1]}; int s = side(I[1]); FOR(i, 2, N - 1) { int v = I[i], t = side(v); if (s == 0 && t == 0) { while (len(stack) >= 2 && ccw(point[stack[len(stack) - 2]], point[stack[len(stack) - 1]], point[v]) == 1) { res.eb(stack[len(stack) - 2], stack[len(stack) - 1], v), POP(stack); } stack.eb(v); } elif (s == 1 && t == 1) { while (len(stack) >= 2 && ccw(point[stack[len(stack) - 2]], point[stack[len(stack) - 1]], point[v]) == -1) { res.eb(stack[len(stack) - 2], v, stack[len(stack) - 1]), POP(stack); } stack.eb(v); } elif (s == 0 && t == 1) { FOR(j, len(stack) - 1) res.eb(stack[j], stack[j + 1], v); stack = {stack.back(), v}, s = t; } elif (s == 1 && t == 0) { FOR(j, len(stack) - 1) res.eb(stack[j], v, stack[j + 1]); stack = {stack.back(), v}, s = t; } } if (s == 0) { FOR(j, len(stack) - 1) res.eb(stack[j], stack[j + 1], n); } elif (s == 1) { FOR(j, len(stack) - 1) res.eb(stack[j], n, stack[j + 1]); } for (auto& [a, b, c]: res) a = (a + rot) % N, b = (b + rot) % N, c = (c + rot) % N; return res; } // (i,j,k), ccw template <typename T> vc<tuple<int, int, int>> polygon_triangulation(vc<Point<T>> point) { using P = Point<T>; int N = len(point); enum vtype { MERGE, SPLIT, START, END, UPPER, LOWER }; auto pre = [&](int i) -> int { return (i > 0 ? i - 1 : N - 1); }; auto nxt = [&](int i) -> int { return (i < N - 1 ? i + 1 : 0); }; auto get_vtype = [&](int i) -> vtype { int l = pre(i), r = nxt(i); if (point[i] < point[l] && point[i] < point[r]) { return (ccw(point[l], point[i], point[r]) == 1 ? START : SPLIT); } if (point[l] < point[i] && point[r] < point[i]) { return (ccw(point[l], point[i], point[r]) == 1 ? END : MERGE); } if (point[l] < point[i] && point[i] < point[r]) return LOWER; if (point[r] < point[i] && point[i] < point[l]) return UPPER; assert(0); return END; }; SplayTree_Basic<int> ST(N); using np = decltype(ST)::np; vc<np> nodes(N); FOR(i, N) nodes[i] = ST.new_node(i); np S = ST.new_root(); auto comp = [&](int i, P p) -> bool { P A = point[i], B = point[nxt(i)]; return ccw(A, B, p) == -1; }; vc<int> helper(N, -1); vc<bool> merged(N); Planar_Graph<T> G(N, point); FOR(i, N) G.add(i, nxt(i)); auto add_edge = [&](int v, int w) -> void { merged[w] = 1, G.add(v, w); }; auto fix_up = [&](int v, int e) -> void { int w = helper[e]; if (get_vtype(w) == vtype::MERGE && !merged[w]) { add_edge(v, w); } }; auto I = argsort(point); for (auto& i: I) { vtype t = get_vtype(i); if (t == vtype::MERGE) { ST.splay(nodes[i], 1), S = nodes[i]; int n = (nodes[i]->l ? nodes[i]->l->size : 0); auto [L, M, R] = ST.split3(S, n, n + 1); int j = ST.get(R, 0); S = ST.merge(L, R); fix_up(i, i), fix_up(i, j); helper[j] = i; } if (t == vtype::SPLIT) { auto [L, R] = ST.split_max_right(S, [&](int k) -> bool { return comp(k, point[i]); }); int j = ST.get(R, 0); add_edge(i, helper[j]); helper[j] = i, helper[pre(i)] = i; S = ST.merge3(L, nodes[pre(i)], R); } if (t == vtype::START) { auto [L, R] = ST.split_max_right(S, [&](int k) -> bool { return comp(k, point[i]); }); S = ST.merge3(L, nodes[pre(i)], R), helper[pre(i)] = i; } if (t == vtype::END) { ST.splay(nodes[i], 1), S = nodes[i]; int n = (nodes[i]->l ? nodes[i]->l->size : 0); auto [L, M, R] = ST.split3(S, n, n + 1); S = ST.merge(L, R); fix_up(i, i); } if (t == vtype::UPPER) { ST.splay(nodes[i], 1), S = nodes[i]; int n = (nodes[i]->l ? nodes[i]->l->size : 0); auto [L, M, R] = ST.split3(S, n, n + 1); S = ST.merge3(L, nodes[pre(i)], R); fix_up(i, i); helper[pre(i)] = i; } if (t == vtype::LOWER) { auto [L, R] = ST.split_max_right(S, [&](int k) -> bool { return comp(k, point[i]); }); int j = ST.get(R, 0); S = ST.merge(L, R); fix_up(i, j); helper[j] = i; } } G.build(); vc<tuple<int, int, int>> ANS; FOR(f, 1, G.NF) { auto [vs, es] = G.get_face_data(f); POP(vs); vc<P> sub = rearrange(point, vs); for (auto& [a, b, c]: monotone_polygon_triangulation(sub)) ANS.eb(vs[a], vs[b], vs[c]); } return ANS; }
#line 2 "geo/base.hpp" template <typename T> struct Point { T x, y; Point() : x(0), y(0) {} template <typename A, typename B> Point(A x, B y) : x(x), y(y) {} template <typename A, typename B> Point(pair<A, B> p) : x(p.fi), y(p.se) {} Point operator+=(const Point p) { x += p.x, y += p.y; return *this; } Point operator-=(const Point p) { x -= p.x, y -= p.y; return *this; } Point operator+(Point p) const { return {x + p.x, y + p.y}; } Point operator-(Point p) const { return {x - p.x, y - p.y}; } bool operator==(Point p) const { return x == p.x && y == p.y; } bool operator!=(Point p) const { return x != p.x || y != p.y; } Point operator-() const { return {-x, -y}; } Point operator*(T t) const { return {x * t, y * t}; } Point operator/(T t) const { return {x / t, y / t}; } bool operator<(Point p) const { if (x != p.x) return x < p.x; return y < p.y; } T dot(const Point& other) const { return x * other.x + y * other.y; } T det(const Point& other) const { return x * other.y - y * other.x; } double norm() { return sqrtl(x * x + y * y); } double angle() { return atan2(y, x); } Point rotate(double theta) { static_assert(!is_integral<T>::value); double c = cos(theta), s = sin(theta); return Point{c * x - s * y, s * x + c * y}; } Point rot90(bool ccw) { return (ccw ? Point{-y, x} : Point{y, -x}); } }; #ifdef FASTIO template <typename T> void rd(Point<T>& p) { fastio::rd(p.x), fastio::rd(p.y); } template <typename T> void wt(Point<T>& p) { fastio::wt(p.x); fastio::wt(' '); fastio::wt(p.y); } #endif // A -> B -> C と進むときに、左に曲がるならば +1、右に曲がるならば -1 template <typename T> int ccw(Point<T> A, Point<T> B, Point<T> C) { T x = (B - A).det(C - A); if (x > 0) return 1; if (x < 0) return -1; return 0; } template <typename REAL, typename T, typename U> REAL dist(Point<T> A, Point<U> B) { REAL dx = REAL(A.x) - REAL(B.x); REAL dy = REAL(A.y) - REAL(B.y); return sqrt(dx * dx + dy * dy); } // ax+by+c template <typename T> struct Line { T a, b, c; Line(T a, T b, T c) : a(a), b(b), c(c) {} Line(Point<T> A, Point<T> B) { a = A.y - B.y, b = B.x - A.x, c = A.x * B.y - A.y * B.x; } Line(T x1, T y1, T x2, T y2) : Line(Point<T>(x1, y1), Point<T>(x2, y2)) {} template <typename U> U eval(Point<U> P) { return a * P.x + b * P.y + c; } template <typename U> T eval(U x, U y) { return a * x + b * y + c; } // 同じ直線が同じ a,b,c で表現されるようにする void normalize() { static_assert(is_same_v<T, int> || is_same_v<T, long long>); T g = gcd(gcd(abs(a), abs(b)), abs(c)); a /= g, b /= g, c /= g; if (b < 0) { a = -a, b = -b, c = -c; } if (b == 0 && a < 0) { a = -a, b = -b, c = -c; } } bool is_parallel(Line other) { return a * other.b - b * other.a == 0; } bool is_orthogonal(Line other) { return a * other.a + b * other.b == 0; } }; template <typename T> struct Segment { Point<T> A, B; Segment(Point<T> A, Point<T> B) : A(A), B(B) {} Segment(T x1, T y1, T x2, T y2) : Segment(Point<T>(x1, y1), Point<T>(x2, y2)) {} bool contain(Point<T> C) { T det = (C - A).det(B - A); if (det != 0) return 0; return (C - A).dot(B - A) >= 0 && (C - B).dot(A - B) >= 0; } Line<T> to_Line() { return Line(A, B); } }; template <typename REAL> struct Circle { Point<REAL> O; REAL r; Circle(Point<REAL> O, REAL r) : O(O), r(r) {} Circle(REAL x, REAL y, REAL r) : O(x, y), r(r) {} template <typename T> bool contain(Point<T> p) { REAL dx = p.x - O.x, dy = p.y - O.y; return dx * dx + dy * dy <= r * r; } }; #line 2 "ds/splaytree/splaytree.hpp" /* update でちゃんと prod が計算されてくれれば prod は op(lprod,x,rprod) でなくてもよい. */ // Node 型を別に定義して使う template <typename Node> struct SplayTree { Node *pool; const int NODES; int pid; using np = Node *; using X = typename Node::value_type; using A = typename Node::operator_type; vc<np> FREE; SplayTree(int NODES) : NODES(NODES), pid(0) { pool = new Node[NODES]; } ~SplayTree() { delete[] pool; } void free_subtree(np c) { if (!c) return; auto dfs = [&](auto &dfs, np c) -> void { if (c->l) dfs(dfs, c->l); if (c->r) dfs(dfs, c->r); FREE.eb(c); }; dfs(dfs, c); } void reset() { pid = 0; FREE.clear(); } np new_root() { return nullptr; } np new_node(const X &x) { assert(!FREE.empty() || pid < NODES); np n = (FREE.empty() ? &(pool[pid++]) : POP(FREE)); Node::new_node(n, x); return n; } np new_node(const vc<X> &dat) { auto dfs = [&](auto &dfs, int l, int r) -> np { if (l == r) return nullptr; if (r == l + 1) return new_node(dat[l]); int m = (l + r) / 2; np l_root = dfs(dfs, l, m); np r_root = dfs(dfs, m + 1, r); np root = new_node(dat[m]); root->l = l_root, root->r = r_root; if (l_root) l_root->p = root; if (r_root) r_root->p = root; root->update(); return root; }; return dfs(dfs, 0, len(dat)); } u32 get_size(np root) { return (root ? root->size : 0); } np merge(np l_root, np r_root) { if (!l_root) return r_root; if (!r_root) return l_root; assert((!l_root->p) && (!r_root->p)); splay_kth(r_root, 0); // splay したので prop 済 r_root->l = l_root; l_root->p = r_root; r_root->update(); return r_root; } np merge3(np a, np b, np c) { return merge(merge(a, b), c); } np merge4(np a, np b, np c, np d) { return merge(merge(merge(a, b), c), d); } pair<np, np> split(np root, u32 k) { assert(!root || !root->p); if (k == 0) return {nullptr, root}; if (k == (root->size)) return {root, nullptr}; splay_kth(root, k - 1); np right = root->r; root->r = nullptr, right->p = nullptr; root->update(); return {root, right}; } tuple<np, np, np> split3(np root, u32 l, u32 r) { np nm, nr; tie(root, nr) = split(root, r); tie(root, nm) = split(root, l); return {root, nm, nr}; } tuple<np, np, np, np> split4(np root, u32 i, u32 j, u32 k) { np d; tie(root, d) = split(root, k); auto [a, b, c] = split3(root, i, j); return {a, b, c, d}; } tuple<np, np, np> split_L_root_R(np root) { u32 s = (root->l ? root->l->size : 0); return split3(root, s, s + 1); } // 部分木が区間 [l,r) に対応するようなノードを作って返す // そのノードが root になるわけではないので、 // このノードを参照した後にすぐに splay して根に持ち上げること void goto_between(np &root, u32 l, u32 r) { if (l == 0 && r == root->size) return; if (l == 0) { splay_kth(root, r); root = root->l; return; } if (r == root->size) { splay_kth(root, l - 1); root = root->r; return; } splay_kth(root, r); np rp = root; root = rp->l; root->p = nullptr; splay_kth(root, l - 1); root->p = rp; rp->l = root; rp->update(); root = root->r; } vc<X> get_all(const np &root) { vc<X> res; auto dfs = [&](auto &dfs, np root) -> void { if (!root) return; root->prop(); dfs(dfs, root->l); res.eb(root->get()); dfs(dfs, root->r); }; dfs(dfs, root); return res; } X get(np &root, u32 k) { assert(root == nullptr || !root->p); splay_kth(root, k); return root->get(); } void set(np &root, u32 k, const X &x) { assert(root != nullptr && !root->p); splay_kth(root, k); root->set(x); } void multiply(np &root, u32 k, const X &x) { assert(root != nullptr && !root->p); splay_kth(root, k); root->multiply(x); } X prod(np &root, u32 l, u32 r) { assert(root == nullptr || !root->p); using Mono = typename Node::Monoid_X; if (l == r) return Mono::unit(); assert(0 <= l && l < r && r <= root->size); goto_between(root, l, r); X res = root->prod; splay(root, true); return res; } X prod(np &root) { assert(root == nullptr || !root->p); using Mono = typename Node::Monoid_X; return (root ? root->prod : Mono::unit()); } void apply(np &root, u32 l, u32 r, const A &a) { if (l == r) return; assert(0 <= l && l < r && r <= root->size); goto_between(root, l, r); root->apply(a); splay(root, true); } void apply(np &root, const A &a) { if (!root) return; root->apply(a); } void reverse(np &root, u32 l, u32 r) { assert(root == nullptr || !root->p); if (l == r) return; assert(0 <= l && l < r && r <= root->size); goto_between(root, l, r); root->reverse(); splay(root, true); } void reverse(np root) { if (!root) return; root->reverse(); } void rotate(Node *n) { // n を根に近づける。prop, update は rotate の外で行う。 Node *pp, *p, *c; p = n->p; pp = p->p; if (p->l == n) { c = n->r; n->r = p; p->l = c; } else { c = n->l; n->l = p; p->r = c; } if (pp && pp->l == p) pp->l = n; if (pp && pp->r == p) pp->r = n; n->p = pp; p->p = n; if (c) c->p = p; } void prop_from_root(np c) { if (!c->p) { c->prop(); return; } prop_from_root(c->p); c->prop(); } void splay(Node *me, bool prop_from_root_done) { // これを呼ぶ時点で、me の祖先(me を除く)は既に prop 済であることを仮定 // 特に、splay 終了時点で me は upd / prop 済である if (!prop_from_root_done) prop_from_root(me); me->prop(); while (me->p) { np p = me->p; np pp = p->p; if (!pp) { rotate(me); p->update(); break; } bool same = (p->l == me && pp->l == p) || (p->r == me && pp->r == p); if (same) rotate(p), rotate(me); if (!same) rotate(me), rotate(me); pp->update(), p->update(); } // me の update は最後だけでよい me->update(); } void splay_kth(np &root, u32 k) { assert(0 <= k && k < (root->size)); while (1) { root->prop(); u32 sl = (root->l ? root->l->size : 0); if (k == sl) break; if (k < sl) root = root->l; else { k -= sl + 1; root = root->r; } } splay(root, true); } // check(x), 左側のノード全体が check を満たすように切る template <typename F> pair<np, np> split_max_right(np root, F check) { if (!root) return {nullptr, nullptr}; assert(!root->p); np c = find_max_right(root, check); if (!c) { splay(root, true); return {nullptr, root}; } splay(c, true); np right = c->r; if (!right) return {c, nullptr}; right->p = nullptr; c->r = nullptr; c->update(); return {c, right}; } // check(x, cnt), 左側のノード全体が check を満たすように切る template <typename F> pair<np, np> split_max_right_cnt(np root, F check) { if (!root) return {nullptr, nullptr}; assert(!root->p); np c = find_max_right_cnt(root, check); if (!c) { splay(root, true); return {nullptr, root}; } splay(c, true); np right = c->r; if (!right) return {c, nullptr}; right->p = nullptr; c->r = nullptr; c->update(); return {c, right}; } // 左側のノード全体の prod が check を満たすように切る template <typename F> pair<np, np> split_max_right_prod(np root, F check) { if (!root) return {nullptr, nullptr}; assert(!root->p); np c = find_max_right_prod(root, check); if (!c) { splay(root, true); return {nullptr, root}; } splay(c, true); np right = c->r; if (!right) return {c, nullptr}; right->p = nullptr; c->r = nullptr; c->update(); return {c, right}; } template <typename F> np find_max_right(np root, const F &check) { // 最後に見つけた ok の点、最後に探索した点 np last_ok = nullptr, last = nullptr; while (root) { last = root; root->prop(); if (check(root->x)) { last_ok = root; root = root->r; } else { root = root->l; } } splay(last, true); return last_ok; } template <typename F> np find_max_right_cnt(np root, const F &check) { // 最後に見つけた ok の点、最後に探索した点 np last_ok = nullptr, last = nullptr; ll n = 0; while (root) { last = root; root->prop(); ll ns = (root->l ? root->l->size : 0); if (check(root->x, n + ns + 1)) { last_ok = root; n += ns + 1; root = root->r; } else { root = root->l; } } splay(last, true); return last_ok; } template <typename F> np find_max_right_prod(np root, const F &check) { using Mono = typename Node::Monoid_X; X prod = Mono::unit(); // 最後に見つけた ok の点、最後に探索した点 np last_ok = nullptr, last = nullptr; while (root) { last = root; root->prop(); np tmp = root->r; root->r = nullptr; root->update(); X lprod = Mono::op(prod, root->prod); root->r = tmp; root->update(); if (check(lprod)) { prod = lprod; last_ok = root; root = root->r; } else { root = root->l; } } splay(last, true); return last_ok; } }; #line 2 "ds/splaytree/splaytree_basic.hpp" namespace SplayTreeNodes { template <typename S> struct Node_Basic { using value_type = S; using operator_type = int; using np = Node_Basic *; np p, l, r; bool rev; S x; u32 size; static void new_node(np n, const S &x) { n->p = n->l = n->r = nullptr; n->x = x, n->size = 1, n->rev = 0; } void update() { size = 1; if (l) { size += l->size; } if (r) { size += r->size; } } void prop() { if (rev) { if (l) { l->rev ^= 1, swap(l->l, l->r); } if (r) { r->rev ^= 1, swap(r->l, r->r); } rev = 0; } } // update, prop 以外で呼ばれるものは、splay 後であることが想定されている。 // したがってその時点で update, prop 済であることを仮定してよい。 S get() { return x; } void set(const S &xx) { x = xx; update(); } void reverse() { swap(l, r); rev ^= 1; } }; template <typename S> using SplayTree_Basic = SplayTree<Node_Basic<S>>; } // namespace SplayTreeNodes using SplayTreeNodes::SplayTree_Basic; #line 2 "ds/hashmap.hpp" // u64 -> Val template <typename Val> struct HashMap { // n は入れたいものの個数で ok HashMap(u32 n = 0) { build(n); } void build(u32 n) { u32 k = 8; while (k < n * 2) k *= 2; cap = k / 2, mask = k - 1; key.resize(k), val.resize(k), used.assign(k, 0); } // size を保ったまま. size=0 にするときは build すること. void clear() { used.assign(len(used), 0); cap = (mask + 1) / 2; } int size() { return len(used) / 2 - cap; } int index(const u64& k) { int i = 0; for (i = hash(k); used[i] && key[i] != k; i = (i + 1) & mask) {} return i; } Val& operator[](const u64& k) { if (cap == 0) extend(); int i = index(k); if (!used[i]) { used[i] = 1, key[i] = k, val[i] = Val{}, --cap; } return val[i]; } Val get(const u64& k, Val default_value) { int i = index(k); return (used[i] ? val[i] : default_value); } bool count(const u64& k) { int i = index(k); return used[i] && key[i] == k; } // f(key, val) template <typename F> void enumerate_all(F f) { FOR(i, len(used)) if (used[i]) f(key[i], val[i]); } private: u32 cap, mask; vc<u64> key; vc<Val> val; vc<bool> used; u64 hash(u64 x) { static const u64 FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); x += FIXED_RANDOM; x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; x = (x ^ (x >> 27)) * 0x94d049bb133111eb; return (x ^ (x >> 31)) & mask; } void extend() { vc<pair<u64, Val>> dat; dat.reserve(len(used) / 2 - cap); FOR(i, len(used)) { if (used[i]) dat.eb(key[i], val[i]); } build(2 * len(dat)); for (auto& [a, b]: dat) (*this)[a] = b; } }; #line 3 "graph/base.hpp" template <typename T> struct Edge { int frm, to; T cost; int id; }; template <typename T = int, bool directed = false> struct Graph { static constexpr bool is_directed = directed; int N, M; using cost_type = T; using edge_type = Edge<T>; vector<edge_type> edges; vector<int> indptr; vector<edge_type> csr_edges; vc<int> vc_deg, vc_indeg, vc_outdeg; bool prepared; class OutgoingEdges { public: OutgoingEdges(const Graph* G, int l, int r) : G(G), l(l), r(r) {} const edge_type* begin() const { if (l == r) { return 0; } return &G->csr_edges[l]; } const edge_type* end() const { if (l == r) { return 0; } return &G->csr_edges[r]; } private: const Graph* G; int l, r; }; bool is_prepared() { return prepared; } Graph() : N(0), M(0), prepared(0) {} Graph(int N) : N(N), M(0), prepared(0) {} void build(int n) { N = n, M = 0; prepared = 0; edges.clear(); indptr.clear(); csr_edges.clear(); vc_deg.clear(); vc_indeg.clear(); vc_outdeg.clear(); } void add(int frm, int to, T cost = 1, int i = -1) { assert(!prepared); assert(0 <= frm && 0 <= to && to < N); if (i == -1) i = M; auto e = edge_type({frm, to, cost, i}); edges.eb(e); ++M; } #ifdef FASTIO // wt, off void read_tree(bool wt = false, int off = 1) { read_graph(N - 1, wt, off); } void read_graph(int M, bool wt = false, int off = 1) { for (int m = 0; m < M; ++m) { INT(a, b); a -= off, b -= off; if (!wt) { add(a, b); } else { T c; read(c); add(a, b, c); } } build(); } #endif void build() { assert(!prepared); prepared = true; indptr.assign(N + 1, 0); for (auto&& e: edges) { indptr[e.frm + 1]++; if (!directed) indptr[e.to + 1]++; } for (int v = 0; v < N; ++v) { indptr[v + 1] += indptr[v]; } auto counter = indptr; csr_edges.resize(indptr.back() + 1); for (auto&& e: edges) { csr_edges[counter[e.frm]++] = e; if (!directed) csr_edges[counter[e.to]++] = edge_type({e.to, e.frm, e.cost, e.id}); } } OutgoingEdges operator[](int v) const { assert(prepared); return {this, indptr[v], indptr[v + 1]}; } vc<int> deg_array() { if (vc_deg.empty()) calc_deg(); return vc_deg; } pair<vc<int>, vc<int>> deg_array_inout() { if (vc_indeg.empty()) calc_deg_inout(); return {vc_indeg, vc_outdeg}; } int deg(int v) { if (vc_deg.empty()) calc_deg(); return vc_deg[v]; } int in_deg(int v) { if (vc_indeg.empty()) calc_deg_inout(); return vc_indeg[v]; } int out_deg(int v) { if (vc_outdeg.empty()) calc_deg_inout(); return vc_outdeg[v]; } #ifdef FASTIO void debug() { print("Graph"); if (!prepared) { print("frm to cost id"); for (auto&& e: edges) print(e.frm, e.to, e.cost, e.id); } else { print("indptr", indptr); print("frm to cost id"); FOR(v, N) for (auto&& e: (*this)[v]) print(e.frm, e.to, e.cost, e.id); } } #endif vc<int> new_idx; vc<bool> used_e; // G における頂点 V[i] が、新しいグラフで i になるようにする // {G, es} // sum(deg(v)) の計算量になっていて、 // 新しいグラフの n+m より大きい可能性があるので注意 Graph<T, directed> rearrange(vc<int> V, bool keep_eid = 0) { if (len(new_idx) != N) new_idx.assign(N, -1); int n = len(V); FOR(i, n) new_idx[V[i]] = i; Graph<T, directed> G(n); vc<int> history; FOR(i, n) { for (auto&& e: (*this)[V[i]]) { if (len(used_e) <= e.id) used_e.resize(e.id + 1); if (used_e[e.id]) continue; int a = e.frm, b = e.to; if (new_idx[a] != -1 && new_idx[b] != -1) { history.eb(e.id); used_e[e.id] = 1; int eid = (keep_eid ? e.id : -1); G.add(new_idx[a], new_idx[b], e.cost, eid); } } } FOR(i, n) new_idx[V[i]] = -1; for (auto&& eid: history) used_e[eid] = 0; G.build(); return G; } Graph<T, true> to_directed_tree(int root = -1) { if (root == -1) root = 0; assert(!is_directed && prepared && M == N - 1); Graph<T, true> G1(N); vc<int> par(N, -1); auto dfs = [&](auto& dfs, int v) -> void { for (auto& e: (*this)[v]) { if (e.to == par[v]) continue; par[e.to] = v, dfs(dfs, e.to); } }; dfs(dfs, root); for (auto& e: edges) { int a = e.frm, b = e.to; if (par[a] == b) swap(a, b); assert(par[b] == a); G1.add(a, b, e.cost); } G1.build(); return G1; } HashMap<int> MP_FOR_EID; int get_eid(u64 a, u64 b) { if (len(MP_FOR_EID) == 0) { MP_FOR_EID.build(N - 1); for (auto& e: edges) { u64 a = e.frm, b = e.to; u64 k = to_eid_key(a, b); MP_FOR_EID[k] = e.id; } } return MP_FOR_EID.get(to_eid_key(a, b), -1); } u64 to_eid_key(u64 a, u64 b) { if (!directed && a > b) swap(a, b); return N * a + b; } private: void calc_deg() { assert(vc_deg.empty()); vc_deg.resize(N); for (auto&& e: edges) vc_deg[e.frm]++, vc_deg[e.to]++; } void calc_deg_inout() { assert(vc_indeg.empty()); vc_indeg.resize(N); vc_outdeg.resize(N); for (auto&& e: edges) { vc_indeg[e.to]++, vc_outdeg[e.frm]++; } } }; #line 2 "geo/angle_sort.hpp" #line 4 "geo/angle_sort.hpp" // lower: -1, origin: 0, upper: 1, (-pi,pi] template <typename T> int lower_or_upper(const Point<T> &p) { if (p.y != 0) return (p.y > 0 ? 1 : -1); if (p.x > 0) return -1; if (p.x < 0) return 1; return 0; } // L<R:-1, L==R:0, L>R:1, (-pi,pi] template <typename T> int angle_comp_3(const Point<T> &L, const Point<T> &R) { int a = lower_or_upper(L), b = lower_or_upper(R); if (a != b) return (a < b ? -1 : +1); T det = L.det(R); if (det > 0) return -1; if (det < 0) return 1; return 0; } // 偏角ソートに対する argsort, (-pi,pi] template <typename T> vector<int> angle_sort(vector<Point<T>> &P) { vc<int> I(len(P)); FOR(i, len(P)) I[i] = i; sort(all(I), [&](auto &L, auto &R) -> bool { return angle_comp_3(P[L], P[R]) == -1; }); return I; } // 偏角ソートに対する argsort, (-pi,pi] template <typename T> vector<int> angle_sort(vector<pair<T, T>> &P) { vc<Point<T>> tmp(len(P)); FOR(i, len(P)) tmp[i] = Point<T>(P[i]); return angle_sort<T>(tmp); } #line 4 "graph/planar_graph.hpp" /* ・連結平面グラフになっていないときにどう動作するかは何も考えていない ・N=1 も扱わない ・0番目に外面が入る */ template <typename XY> struct Planar_Graph { using P = Point<XY>; int NV, NE, NF; // 頂点, 辺からなるグラフ. 有向辺を 2 つ入れておく Graph<int, 1> G; // 頂点属性 vc<P> point; // 座標 // 辺属性 vc<int> left_face; // 有向辺の左にある面の番号 vc<int> nxt_edge; // 面を反時計回りにまわるときの次の辺 // 面属性 vc<int> first_edge; Planar_Graph(int N, vc<P> point) : NV(N), G(N), point(point) { assert(N > 1); } void add(int a, int b) { G.add(a, b), G.add(b, a); } void build() { G.build(); NE = G.M / 2; nxt_edge.assign(G.M, -1); left_face.assign(G.M, -1); int v0 = 0; int e0 = 0; FOR(v, NV) { if (point[v] < point[v0]) v0 = v; vc<int> eid; vc<P> dir; for (auto& e: G[v]) { eid.eb(e.id); dir.eb(point[e.to] - point[e.frm]); } auto I = angle_sort(dir); assert(len(I) > 0); FOR(k, len(I)) { int i = (k == 0 ? I.back() : I[k - 1]); int j = I[k]; i = eid[i], j = eid[j]; nxt_edge[j ^ 1] = i; } if (v == v0) e0 = eid[I[0]] ^ 1; } for (auto& x: nxt_edge) assert(x != -1); auto make_face = [&](int e) -> void { int p = len(first_edge); first_edge.eb(e); while (left_face[e] == -1) { left_face[e] = p; e = nxt_edge[e]; } }; make_face(e0); FOR(e, 2 * NE) { if (left_face[e] == -1) make_face(e); } NF = len(first_edge); assert(NV - NE + NF == 2); } // return {vs, es} // vs = [v0,v1,v2,v0], es = [e0,e1,e2] pair<vc<int>, vc<int>> get_face_data(int fid) { vc<int> eid = {first_edge[fid]}; while (1) { int e = nxt_edge[eid.back()]; if (e == first_edge[fid]) break; eid.eb(e); } vc<int> vid; for (auto& e: eid) vid.eb(G.edges[e].frm); vid.eb(vid[0]); return {vid, eid}; } }; #line 4 "geo/polygon_triangulation.hpp" template <typename T> vc<tuple<int, int, int>> monotone_polygon_triangulation(vc<Point<T>> point) { int N = len(point); int rot = min_element(all(point)) - point.begin(); rotate(point.begin(), point.begin() + rot, point.end()); int n = max_element(all(point)) - point.begin(); FOR(i, n) assert(point[i] < point[i + 1]); FOR(i, n, N) assert(point[(i + 1) % N] < point[i]); vc<tuple<int, int, int>> res; auto side = [&](int i) -> int { assert(i != 0 && i != n); return (i < n ? 0 : 1); }; vc<int> I = argsort(point); vc<int> stack = {I[0], I[1]}; int s = side(I[1]); FOR(i, 2, N - 1) { int v = I[i], t = side(v); if (s == 0 && t == 0) { while (len(stack) >= 2 && ccw(point[stack[len(stack) - 2]], point[stack[len(stack) - 1]], point[v]) == 1) { res.eb(stack[len(stack) - 2], stack[len(stack) - 1], v), POP(stack); } stack.eb(v); } elif (s == 1 && t == 1) { while (len(stack) >= 2 && ccw(point[stack[len(stack) - 2]], point[stack[len(stack) - 1]], point[v]) == -1) { res.eb(stack[len(stack) - 2], v, stack[len(stack) - 1]), POP(stack); } stack.eb(v); } elif (s == 0 && t == 1) { FOR(j, len(stack) - 1) res.eb(stack[j], stack[j + 1], v); stack = {stack.back(), v}, s = t; } elif (s == 1 && t == 0) { FOR(j, len(stack) - 1) res.eb(stack[j], v, stack[j + 1]); stack = {stack.back(), v}, s = t; } } if (s == 0) { FOR(j, len(stack) - 1) res.eb(stack[j], stack[j + 1], n); } elif (s == 1) { FOR(j, len(stack) - 1) res.eb(stack[j], n, stack[j + 1]); } for (auto& [a, b, c]: res) a = (a + rot) % N, b = (b + rot) % N, c = (c + rot) % N; return res; } // (i,j,k), ccw template <typename T> vc<tuple<int, int, int>> polygon_triangulation(vc<Point<T>> point) { using P = Point<T>; int N = len(point); enum vtype { MERGE, SPLIT, START, END, UPPER, LOWER }; auto pre = [&](int i) -> int { return (i > 0 ? i - 1 : N - 1); }; auto nxt = [&](int i) -> int { return (i < N - 1 ? i + 1 : 0); }; auto get_vtype = [&](int i) -> vtype { int l = pre(i), r = nxt(i); if (point[i] < point[l] && point[i] < point[r]) { return (ccw(point[l], point[i], point[r]) == 1 ? START : SPLIT); } if (point[l] < point[i] && point[r] < point[i]) { return (ccw(point[l], point[i], point[r]) == 1 ? END : MERGE); } if (point[l] < point[i] && point[i] < point[r]) return LOWER; if (point[r] < point[i] && point[i] < point[l]) return UPPER; assert(0); return END; }; SplayTree_Basic<int> ST(N); using np = decltype(ST)::np; vc<np> nodes(N); FOR(i, N) nodes[i] = ST.new_node(i); np S = ST.new_root(); auto comp = [&](int i, P p) -> bool { P A = point[i], B = point[nxt(i)]; return ccw(A, B, p) == -1; }; vc<int> helper(N, -1); vc<bool> merged(N); Planar_Graph<T> G(N, point); FOR(i, N) G.add(i, nxt(i)); auto add_edge = [&](int v, int w) -> void { merged[w] = 1, G.add(v, w); }; auto fix_up = [&](int v, int e) -> void { int w = helper[e]; if (get_vtype(w) == vtype::MERGE && !merged[w]) { add_edge(v, w); } }; auto I = argsort(point); for (auto& i: I) { vtype t = get_vtype(i); if (t == vtype::MERGE) { ST.splay(nodes[i], 1), S = nodes[i]; int n = (nodes[i]->l ? nodes[i]->l->size : 0); auto [L, M, R] = ST.split3(S, n, n + 1); int j = ST.get(R, 0); S = ST.merge(L, R); fix_up(i, i), fix_up(i, j); helper[j] = i; } if (t == vtype::SPLIT) { auto [L, R] = ST.split_max_right(S, [&](int k) -> bool { return comp(k, point[i]); }); int j = ST.get(R, 0); add_edge(i, helper[j]); helper[j] = i, helper[pre(i)] = i; S = ST.merge3(L, nodes[pre(i)], R); } if (t == vtype::START) { auto [L, R] = ST.split_max_right(S, [&](int k) -> bool { return comp(k, point[i]); }); S = ST.merge3(L, nodes[pre(i)], R), helper[pre(i)] = i; } if (t == vtype::END) { ST.splay(nodes[i], 1), S = nodes[i]; int n = (nodes[i]->l ? nodes[i]->l->size : 0); auto [L, M, R] = ST.split3(S, n, n + 1); S = ST.merge(L, R); fix_up(i, i); } if (t == vtype::UPPER) { ST.splay(nodes[i], 1), S = nodes[i]; int n = (nodes[i]->l ? nodes[i]->l->size : 0); auto [L, M, R] = ST.split3(S, n, n + 1); S = ST.merge3(L, nodes[pre(i)], R); fix_up(i, i); helper[pre(i)] = i; } if (t == vtype::LOWER) { auto [L, R] = ST.split_max_right(S, [&](int k) -> bool { return comp(k, point[i]); }); int j = ST.get(R, 0); S = ST.merge(L, R); fix_up(i, j); helper[j] = i; } } G.build(); vc<tuple<int, int, int>> ANS; FOR(f, 1, G.NF) { auto [vs, es] = G.get_face_data(f); POP(vs); vc<P> sub = rearrange(point, vs); for (auto& [a, b, c]: monotone_polygon_triangulation(sub)) ANS.eb(vs[a], vs[b], vs[c]); } return ANS; }