diff --git a/README.md b/README.md index 6200a46..b51f54d 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,7 @@ You can use the codes for *any purpose without any warranty*. author: Takanori MAEHARA (web: http://www.prefield.com, e-mail: maehara@prefield.com, twitter: @tmaehara) + +# Recruiting + +I am a researcher at *RIKEN Center for Advanced Intelligence Project*, which is a Japanese governmental academic research institute. I am working on discrete algorithms (including topics in this github repository). We are hiring *strong programmers* who has some achievements in some competitions. If you are interested in, please feel free to contact me. diff --git a/data_structure/cartesian_tree.cc b/data_structure/cartesian_tree.cc index 45a40c8..7efa2b2 100644 --- a/data_structure/cartesian_tree.cc +++ b/data_structure/cartesian_tree.cc @@ -2,35 +2,28 @@ // Cartesian Tree // // Description: -// For a given sequence x, the Cartesian tree is recursively +// For a given sequence xs, the Cartesian tree is recursively // defined as follows: -// - root is the minimum in x. -// - the left child is the Cartesian tree for the the left of the min., -// and the right child is the Cartesian tree for the right of the min. -// -// Algorithm: -// Left-to-right construction. -// -// Applications: -// In order traversal gives the original sequence. -// Sorting can be performed in O(n log k) -// LCA of two element gives RMQ in original sequence. -// -// Complexity: -// construction: O(n) -// sort: O(n log k) by using priority queue. -// offline RMQ: O(n + q) by Tarjan's offline LCA. +// - the root is the minimum in xs. +// - the left child is the Cartesian tree for the the left segment, +// and the right child is the Cartesian tree for the right segment. +// It is constructed in O(n) time by the left-to-right traversal. // +// By using the Cartesian tree, we can solve +// - Sorting in O(n log k) time, where k is the number of consecutive +// sorted subsegments. +// - LCA(i,j) = RMQ(i,j). Thus, by using the Tarjan's Offline LCA, +// we can solve m RMQs in O(m a(n)) time. +// // Verified: -// SPOJ11772, SPOJ1005604 for RMQ. -// +// SPOJ RPLN: http://www.spoj.com/problems/RPLN/ +// // References: // C. Levcopoulos and O. Petersson (1989): // Heapsort - Adapted for Presorted Files. // in Proceedings of the Workshop on Algorithms and Data Structures, // pp. 499-509. - #include #include #include @@ -45,76 +38,83 @@ using namespace std; #define all(c) ((c).begin()), ((c).end()) template -struct cartesian_tree { +struct CartesianTree { int n, root; - vector x; - vector l, r, p; - cartesian_tree(const vector &x) - : n(x.size()), x(x), l(n,-1), r(n,-1), p(n,-1) { + vector xs; + struct Node { + int left = -1, right = -1, parent = -1; + }; + vector node; + CartesianTree(const vector &xs) : n(xs.size()), xs(xs), node(n) { root = 0; for (int i = 1; i < n; ++i) { int j = i-1; - while (p[j] >=0 && x[i] < x[j]) j = p[j]; - if (x[i] < x[j]) { - p[j] = i; - l[i] = j; + while (node[j].parent >=0 && xs[i] < xs[j]) + j = node[j].parent; + if (xs[i] < xs[j]) { + node[j].parent = i; + node[i].left = j; root = i; } else { - if (r[j] >= 0) p[r[j]] = i; - l[i] = r[j]; - p[i] = j; - r[j] = i; + if (node[j].right >= 0) node[node[j].right].parent = i; + node[i].left = node[j].right; + node[i].parent = j; + node[j].right = i; } } } // In-order traverse gives an original sequence void traverse(int t, int tab = 0) { if (t < 0) return; - traverse(l[t], tab + 2); + traverse(node[t].left, tab + 2); for (int i = 0; i < tab; ++i) cout << " "; - cout << x[t] << endl; - traverse(r[t], tab + 2); + cout << xs[t] << endl; + traverse(node[t].right, tab + 2); } void traverse() { traverse(root); } // Sorting in O(n log k) by Levcopoulos-Petersson void sort() { - auto comp = [&](int i, int j) { return x[i] > x[j]; }; + auto comp = [&](int i, int j) { return xs[i] > xs[j]; }; priority_queue, decltype(comp)> que(comp); que.push(root); while (!que.empty()) { int t = que.top(); que.pop(); - cout << x[t] << " "; - if (l[t] >= 0) que.push(l[t]); - if (r[t] >= 0) que.push(r[t]); + cout << xs[t] << " "; + if (node[t].left >= 0) que.push(node[t].left); + if (node[t].right >= 0) que.push(node[t].right); } cout << endl; } - struct union_find { - vector p; - union_find(int n) : p(n, -1) { }; + struct UnionFind { + vector parent; // parent[root] is the negative of the size. + UnionFind(int n) : parent(n, -1) { }; bool unite(int u, int v) { - if ((u = root(u)) == (v = root(v))) return false; - if (p[u] > p[v]) swap(u, v); - p[u] += p[v]; p[v] = u; + u = root(u); v = root(v); + if (u == v) return false; + if (parent[u] > parent[v]) swap(u, v); + parent[u] += parent[v]; parent[v] = u; return true; } - int root(int u) { return p[u] < 0 ? u : p[u] = root(p[u]); } + bool find(int u, int v) { return root(u) == root(v); } + int root(int u) { return parent[u] < 0 ? u : parent[u] = root(parent[u]); } + int size(int u) { return -parent[root(u)]; } }; + struct query { int u, v, a; }; - void range_min_queries(vector &queries) { + void rangeMinQueries(vector &queries) { vector> Q(n); for (auto &q: queries) { Q[q.u].push_back(&q); Q[q.v].push_back(&q); } - union_find uf(n); + UnionFind uf(n); vector anc(n), color(n); iota(all(anc), 0); function rec = [&](int u) { - for (int c: {l[u], r[u]}) { + for (int c: {node[u].left, node[u].right}) { if (c < 0) continue; rec(c); uf.unite(c, u); @@ -140,14 +140,14 @@ int main() { vector x(n); for (int i = 0; i < n; ++i) scanf("%d", &x[i]); - cartesian_tree T(x); + CartesianTree T(x); - vector::query> qs(q); + vector::query> qs(q); for (int i = 0; i < q; ++i) { scanf("%d %d", &qs[i].u, &qs[i].v); --qs[i].u; --qs[i].v; } - T.range_min_queries(qs); + T.rangeMinQueries(qs); for (auto q: qs) printf("%d\n", x[q.a]); } diff --git a/data_structure/disjoint_sparse_table.cc b/data_structure/disjoint_sparse_table.cc new file mode 100644 index 0000000..87dced4 --- /dev/null +++ b/data_structure/disjoint_sparse_table.cc @@ -0,0 +1,78 @@ +// +// Disjoint Sparse Table +// +// Description: +// +// Let `otimes` be a binary associative operator. +// The disjoint sparse table is a data structure for a +// sequence xs that admits a query +// prod(i,j) = xs[i] `otimes` ... `otimes` xs[j-1] +// in time O(1). +// +// The structure is a segment tree whose node maintains +// prod(i,m) and prod(m,j) for all i, j in the segment. +// Then prod(i,j) is evaluated by finding the node that +// splits [i,j) and returning prod(i,m)*prod(m,j). +// +// Complexity: +// +// preprocessing O(n log n) +// query O(1) +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +template +struct DisjointSparseTable { + vector> ys; + Op otimes; + DisjointSparseTable(vector xs, Op otimes_) : otimes(otimes_) { + int n = 1; + while (n <= xs.size()) n *= 2; + xs.resize(n); + ys.push_back(xs); + for (int h = 1; ; ++h) { + int range = (2 << h), half = (range /= 2); + if (range > n) break; + ys.push_back(xs); + for (int i = half; i < n; i += range) { + for (int j = i-2; j >= i-half; --j) + ys[h][j] = otimes(ys[h][j], ys[h][j+1]); + for (int j = i+1; j < min(n, i+half); ++j) + ys[h][j] = otimes(ys[h][j-1], ys[h][j]); + } + } + } + T prod(int i, int j) { // [i, j) query + --j; + int h = sizeof(int)*__CHAR_BIT__-1-__builtin_clz(i ^ j); + return otimes(ys[h][i], ys[h][j]); + } +}; +template +auto makeDisjointSparseTable(vector xs, Op op) { + return DisjointSparseTable(xs, op); +} + +int main() { + vector xs = {3,1,4,1,5,1}; + int n = xs.size(); + auto otimes = [](int a, int b) { return max(a, b); }; + auto dst = makeDisjointSparseTable(xs, otimes); + + for (int i = 0; i < n; ++i) { + for (int j = i+1; j <= n; ++j) { + cout << i << " " << j << " " << dst.prod(i, j) << " "; + int a = xs[i]; + for (int k = i+1; k < j; ++k) + a = otimes(a, xs[k]); + cout << a << endl; + } + } +} diff --git a/data_structure/initializable_array.cc b/data_structure/initializable_array.cc new file mode 100644 index 0000000..37c45a3 --- /dev/null +++ b/data_structure/initializable_array.cc @@ -0,0 +1,66 @@ +// +// Initializable Array +// +// Description: +// It allows the following operations in O(1) time. +// - init(a): initialize xs[i] = a for all i +// - xs[i]: return xs[i] +// - set(i, a): set xs[i] = a +// The important operation is "init", which usually +// requires O(n) time. By maintaining timestamps, +// we can "emulate" the initialization. +// +// Complexity: +// O(1). +// +// References: +// J. Bentley (1986): Programming pearls. Addison-Wesley. +// +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +template +struct InitializableArray { + T initv, *value; + size_t b, *from, *to; + InitializableArray(int n) { + value = new T[n]; + from = new size_t[n]; + to = new size_t[n]; + } + bool chain(int i) { + int j = from[i]; + return j < b && to[j] == i; + } + void init(T a) { + initv = a; + b = 0; + } + T operator[](int i) { + return chain(i) ? value[i] : initv; + } + void set(int i, T a) { + if (!chain(i)) { + from[i] = b; + to[b++] = i; + } + value[i] = a; + } +}; + +int main() { + InitializableArray a(3); + cout << a.value[0] << endl; + a.init(0); + a.init(2); + a.set(1, 5); + cout << a[0] << endl; + cout << a[1] << endl; + cout << a[2] << endl; + a.set(2, 3); + a.init(0); +} diff --git a/data_structure/leftist_heap.cc b/data_structure/leftist_heap.cc new file mode 100644 index 0000000..62e3609 --- /dev/null +++ b/data_structure/leftist_heap.cc @@ -0,0 +1,84 @@ +// +// Leftist Heap +// +// Description: +// +// Leftist heap is a heap data structure that allows +// the meld (merge) operation in O(log n) time. +// Use this for persistent heaps. +// +// Complexity: +// +// O(1) for top, O(log n) for push/pop/meld +// +// g++ -std=c++17 -O3 -fmax-errors=1 -fsanitize=undefined +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +template +struct LeftistHeap { + struct Node { + T key; + Node *left = 0, *right = 0; + int dist = 0; + } *root = 0; + static Node *merge(Node *x, Node *y) { + if (!x) return y; + if (!y) return x; + if (x->key > y->key) swap(x, y); + x->right = merge(x->right, y); + if (!x->left || x->left->dist < x->dist) swap(x->left, x->right); + x->dist = (x->right ? x->right->dist : 0) + 1; + return x; + } + void push(T key) { root = merge(root, new Node({key})); } + void pop() { root = merge(root->left, root->right); } + T top() { return root->key; } +}; + +// +// Persistent Implementaiton. (allow copy) +// +template +struct PersistentLeftistHeap { + struct Node { + T key; + Node *left = 0, *right = 0; + int dist = 0; + } *root = 0; + static Node *merge(Node *x, Node *y) { + if (!x) return y; + if (!y) return x; + if (x->key > y->key) swap(x, y); + x = new Node(*x); + x->right = merge(x->right, y); + if (!x->left || x->left->dist < x->dist) swap(x->left, x->right); + x->dist = (x->right ? x->right->dist : 0) + 1; + return x; + } + void push(T key) { root = merge(root, new Node({key})); } + void pop() { root = merge(root->left, root->right); } + T top() { return root->key; } +}; + +int main() { + PersistentLeftistHeap heap; + heap.push(3); + heap.push(1); + heap.push(4); + heap.push(1); + heap.push(5); + cout << heap.top() << endl; heap.pop(); + cout << heap.top() << endl; heap.pop(); + auto temp = heap; + cout << heap.top() << endl; heap.pop(); + cout << heap.top() << endl; heap.pop(); + cout << temp.top() << endl; temp.pop(); + cout << temp.top() << endl; temp.pop(); +} diff --git a/data_structure/order_maintenance.cc b/data_structure/order_maintenance.cc new file mode 100644 index 0000000..4555199 --- /dev/null +++ b/data_structure/order_maintenance.cc @@ -0,0 +1,122 @@ +// +// Order Maintenance +// +// - create_node(): return new node x +// - insert(x, y): insert node y after node x +// - erase(x): erase node x from the list +// - order(x, y): return true if x is before y +// +// Running Time: +// worst case O(1) for create_node, erase, and order. +// amortized O(log n) for insert; very small constant. +// +// Reference: +// P. Dietz and D. Sleator (1987): +// "Two algorithms for maintaining order in a list". +// STOC. +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define fst first +#define snd second +#define all(c) (c).begin(), (c).end() + +using namespace std; + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +struct order_maintenance { + using label_type = unsigned long long; + using signed_label_type = long long; + const label_type M = ~((~label_type(0))>>1); + struct node { + node *prev = 0, *next = 0; + label_type label; // allows to contain at most sqrt(M) elements + } *head; + + order_maintenance() { + head = new node(); + head->next = head->prev = head; + } + label_type width(node *x, node *y) { + label_type ret = y->label - x->label; + if (ret - 1 >= M) ret += M; + return ret; + } + void insert(node *x, node *u) { + label_type label = x->label; + if (width(x, x->next) <= 1) { + node *mid = x->next, *end = mid->next; + label_type required = 3; + while (width(x, end) <= 4 * width(x, mid) && end != x) { + ++required; + end = end->next; + if (end == x) break; + ++required; + end = end->next; + mid = mid->next; + } + label_type gap = (x == end ? M : width(x, end)) / required; + label_type val = end->label; + while (1) { + if (end == head) val += M; + end = end->prev; + if (end == x) break; + val -= gap; + end->label = val; + } + } + u->label = label + width(x, x->next)/2; + u->next = x->next; + u->prev = x; + u->next->prev = u; + u->prev->next = u; + } + void erase(node *u) { + u->prev->next = u->next->prev; + u->next->prev = u->prev->next; + } + node *create_node() { + return new node; + } + bool order(node *x, node *y) { + return x->label < y->label; + } +}; + +int main() { + order_maintenance T; + int n = 1000000; + vector nodes(n); + vector order(n); + for (int i = 0; i < n; ++i) { + nodes[i] = T.create_node(); + order[i] = i; + } + random_shuffle(all(order)); + tick(); + T.insert(T.head, nodes[order[0]]); + for (int i = 1; i < n; ++i) { + //cout << i << endl; + T.insert(nodes[order[i-1]], nodes[order[i]]); + } + cout << tick() << endl; +} diff --git a/data_structure/parallel_binary_search.cc b/data_structure/parallel_binary_search.cc new file mode 100644 index 0000000..1323f80 --- /dev/null +++ b/data_structure/parallel_binary_search.cc @@ -0,0 +1,149 @@ +// +// Parallel Binary Search +// +// Description: +// +// Let W(t) be a data structure depending on time t. +// Suppose that there are n agents. Each agent j wants to +// find the smallest time t(j) such that cond(j, W(t(j))) == true +// where cond(j, W(t)) is monotone in t. +// +// If we perform n binary searches independently, we will construct +// W(t) multiple times. Thus, we avoid the redundant construction +// by performing n binary searches in parallel. Imagine a binary +// search tree on t. For each node, we first construct W(t). +// Then we process multiple agents in parallel. Then, the total +// number of constructions is O(log T), which is independent to +// the number of agents. +// +// Complexity: +// +// Suppose that W(t) is constructed from W(t') in time M(|t-t'|), +// and the condition cond(j,W(t)) is evaluated in time Q. +// Then, it runs in O(M(T log T) + n Q log T) time. +// +// Even if W does not have decremental operations, i.e., W(t) +// cannot be constructed from W(t') with t' > t, we can still use +// the parallel binary search that runs in O(M(T) log T + n Q log T); +// time. The constant factor is twice worse than the above. +// Similar result holds if W does not have incremental operations. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +using Int = __int128_t; + +// Point Query, Range Update +template +struct FenwickTree { + vector x; + FenwickTree(int n) : x(n) { } + void add(int k, T a) { // aux + for (; k < x.size(); k |= k+1) x[k] += a; + } + void add(int i, int j, T a) { // add x[k] += a for all k in [i,j] + add(i, a); + if (j+1 < x.size()) add(j+1, -a); + } + T get(int k) { // return x[k] + T sum = 0; + for (; k >= 0; k = (k&(k+1))-1) sum += x[k]; + return sum; + } +}; + +template +vector parallelBinarySearch( + int n, int lo, int hi, Update update, Cond cond) { + using It = vector::iterator; + vector agents(n), solution(n, lo); + iota(all(agents), 0); + + It begin = agents.begin(), end = agents.end(); + deque> stack = {make_tuple(lo, hi, begin, end)}; + while (!stack.empty()) { + // invariant: elems in [begin, end) satisfy "!cond(lo) and cond(hi)" + tie(lo, hi, begin, end) = stack.back(); + stack.pop_back(); + + if (begin == end) continue; + if (lo+1 == hi) { + for_each(begin, end, [&](int k) { solution[k] = hi; }); + continue; + } + int mi = (lo + hi) / 2; + update(mi); + It mid = partition(begin, end, [&](int k) { return cond(k); }); + stack.push_back(make_tuple(mi, hi, mid, end)); + stack.push_back(make_tuple(lo, mi, begin, mid)); + } + return solution; +} + +void SPOJ_METEORS() { + int n, m, k; + scanf("%d %d", &n, &m); + vector> S(n); + vector p(n); + for (int i = 0; i < m; ++i) { + int j; scanf("%d", &j); + S[j-1].push_back(i); + } + for (int i = 0; i < n; ++i) + scanf("%lld", &p[i]); + scanf("%d", &k); + vector l(k), r(k); + vector a(k); + for (int i = 0; i < k; ++i) { + scanf("%d %d %lld", &l[i], &r[i], &a[i]); + --l[i]; --r[i]; + } + + FenwickTree FT(m); + int curr = -1; + auto update = [&](int time) { + while (curr < time) { + ++curr; + if (l[curr] <= r[curr]) { + FT.add(l[curr], r[curr], a[curr]); + } else { + FT.add(l[curr], m-1, a[curr]); + FT.add(0, r[curr], a[curr]); + } + } + while (curr > time) { + if (l[curr] <= r[curr]) { + FT.add(l[curr], r[curr], -a[curr]); + } else { + FT.add(l[curr], m-1, -a[curr]); + FT.add(0, r[curr], -a[curr]); + } + --curr; + } + }; + // minimum time such that cond = true. + auto cond = [&](int j) { + Int total = 0; + for (int i: S[j]) { + total += FT.get(i); + } + return total >= p[j]; + }; + + auto solution = parallelBinarySearch(n, -1, k, update, cond); + + for (int i = 0; i < n; ++i) { + if (solution[i] >= k) cout << "NIE" << endl; + else cout << 1+solution[i] << endl; + } +} + +int main() { + SPOJ_METEORS(); +} diff --git a/data_structure/partially_persistent_union_find.cc b/data_structure/partially_persistent_union_find.cc new file mode 100644 index 0000000..1375395 --- /dev/null +++ b/data_structure/partially_persistent_union_find.cc @@ -0,0 +1,77 @@ +// +// Partially Persistent Union Find +// +// Description: +// It is a persistent version of union find data structure. +// It allows us to apply "find" to the all versions and +// "unite" to the latest version. +// +// Complexity: +// O(log n) for each query. +// +// Verified: +// CODE THANKS FESTIVAL 2017, Union Set: +// https://code-thanks-festival-2017-open.contest.atcoder.jp/tasks/code_thanks_festival_2017_h +// + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +using namespace std; + +struct PartiallyPersistentUnionFind { + vector>> parent; // (parent index, modified time) + int now = 0; // time = 0 is the initial state + PartiallyPersistentUnionFind(int n) : parent(n, {{-1,0}}) { } + bool unite(int u, int v) { + ++now; + u = root(u, now); v = root(v, now); + if (u == v) return false; + if (parent[u].back().fst > parent[v].back().fst) swap(u, v); + parent[u].push_back({parent[u].back().fst+parent[v].back().fst, now}); + parent[v].push_back({u, now}); + return true; + } + bool find(int u, int v, int t) { return root(u, t) == root(v, t); } + int root(int u, int t) { + if (parent[u].back().fst >= 0 && parent[u].back().snd <= t) + return root(parent[u].back().fst, t); + return u; + } + int size(int u, int t) { + u = root(u, t); + int lo = 0, hi = parent[u].size(); + while (lo + 1 < hi) { + int mi = (lo + hi) / 2; + if (parent[u][mi].snd <= t) lo = mi; + else hi = mi; + } + return -parent[u][lo].fst; + } +}; + +int main() { + int n, m, q, a, b; + scanf("%d %d", &n, &m); + + PartiallyPersistentUnionFind uf(n); + for (int i = 0; i < m; ++i) { + scanf("%d %d", &a, &b); --a; --b; + uf.unite(a, b); + } + scanf("%d", &q); + for (int i = 0; i < q; ++i) { + scanf("%d %d", &a, &b); --a; --b; + int lo = 0, hi = uf.now+1; + while (lo+1 < hi) { + int mi = (lo + hi) / 2; + if (uf.find(a, b, mi)) hi = mi; + else lo = mi; + } + if (hi == uf.now+1) printf("-1\n"); + else printf("%d\n", hi); + } +} diff --git a/data_structure/radix_heap.cc b/data_structure/radix_heap.cc index 9685dfc..16c9b33 100644 --- a/data_structure/radix_heap.cc +++ b/data_structure/radix_heap.cc @@ -1,9 +1,31 @@ -#include -#include -#include -#include -#include -#include +// +// Radix Heap +// +// Description: +// +// A radix heap is a monotonic heap for keys of type unsigned int. +// Here, a monotonic heap is a heap that allows push(key) only for +// key >= top(). It is useful in the Dijkstra shortest path algorithm +// with integral edge weights. +// see: https://en.wikipedia.org/wiki/Radix_heap +// +// Complexity: +// +// O(|bit|) for all operations. Moreover, +// O(1), amortized, for pop. +// +// Verified: +// +// SPOJ_SHPATH +// +// References: +// +// B. V. Cherkassky, A. V. Goldberg, C. Silverstein (1997): +// "Buckets, Heaps, Lists and Monotone Priority Queues." +// in Proceedings of the 8th Annual ACM-SIAM Symposium on +// Discrete Algorithms (SODA'97), pp. 83-92. +// +#include using namespace std; @@ -12,23 +34,23 @@ using namespace std; #define all(c) ((c).begin()), ((c).end()) #define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } -// min heap +// Min Heap template -struct radix_heap { - typedef unsigned int uint; +struct RadixHeap { + using uint = uint32_t; // fix bit size static int bsr(uint a) { return a ? 31 - __builtin_clz(a) : -1; } uint size, last; vector> v[33]; - radix_heap() : size(0), last(0) { } + RadixHeap() : size(0), last(0) { } bool empty() const { return size == 0; } - void aux(const pair &p) { v[bsr(p.fst^last)+1].push_back(p); } + void aux(pair p) { v[bsr(p.fst^last)+1].push_back(p); } pair top() { if (v[0].empty()) { int i = 1; while (v[i].empty()) ++i; last = min_element(all(v[i]))->fst; - for (auto &p: v[i]) aux(p); + for (auto p: v[i]) aux(p); v[i].clear(); } return v[0].back(); @@ -37,15 +59,132 @@ struct radix_heap { void pop() { --size; top(); v[0].pop_back(); } }; -int main() { - radix_heap heap; - heap.push(strlen("test"), "test"); - heap.push(strlen("a"), "a"); - heap.push(strlen("ab"), "ab"); - heap.push(strlen("aaa"), "aaa"); - heap.push(strlen("xyzz"), "xyzz"); - while (!heap.empty()) { - cout << heap.top().snd << endl; - heap.pop(); +template +struct WeightedGraph { + struct Edge { + int to; + Weight weight; + }; + int n; + vector> adj, rdj; + WeightedGraph(int n) : n(n), adj(n), rdj(n) { } + void addEdge(int u, int v, Weight w) { + adj[u].push_back({v, w}); + rdj[v].push_back({u, w}); // can be omitted for the standard dijkstra + } +}; + +template +struct ShortestPath { }; // omit + +template <> +struct ShortestPath { + using Weight = int; + WeightedGraph g; + + vector dist; + vector prev; + ShortestPath(WeightedGraph g) : g(g), dist(g.n), prev(g.n) { } + + void solve(int s) { + fill(all(prev), -1); + fill(all(dist), -1); dist[s] = 0; + + RadixHeap que; + que.push(0,s); + while (!que.empty()) { + auto d = que.top().fst; + auto u = que.top().snd; + que.pop(); + if (dist[u] < d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u]+w) continue; + dist[v] = dist[u] + w; + prev[v] = u; + que.push(dist[v], v); + } + } } + // Bidirectional Dijkstra + int solve(int s, int t) { + if (s == t) return dist[s] = 0; + + fill(all(dist), -1); dist[s] = 0; + vector drev(g.n, -1); drev[t] = 0; + RadixHeap qs, qt; + qs.push(0,s); qt.push(0,t); + int mu = -1; + while (!qs.empty() && !qt.empty()) { + if (mu >= 0 && qs.top().fst + qt.top().fst >= mu) break; + if (qs.top().fst <= qt.top().fst) { + auto d = qs.top().fst; + auto u = qs.top().snd; + qs.pop(); + if (dist[u] > d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u] + w) continue; + dist[v] = dist[u] + w; + qs.push(dist[v], v); + if (drev[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } else { + auto d = qt.top().fst; + auto u = qt.top().snd; + qt.pop(); + if (drev[u] > d) continue; + for (auto e: g.rdj[u]) { + auto v = e.to; + auto w = e.weight; + if (drev[v] >= 0 && drev[v] <= drev[u] + w) continue; + drev[v] = drev[u] + w; + qt.push(drev[v], v); + if (dist[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } + } + return mu; + } +}; + +void SPOJ_SHPATH() { + int ncase; scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + int n; + scanf("%d", &n); + WeightedGraph g(n); + map id; + for (int u = 0; u < n; ++u) { + char name[1024]; + scanf("%s", name); + id[name] = u; + int k; + scanf("%d", &k); + for (int j = 0; j < k; ++j) { + int v, d; + scanf("%d %d", &v, &d); + g.addEdge(u, v-1, d); + } + } + ShortestPath solver(g); + int k; + scanf("%d", &k); + for (int i = 0; i < k; ++i) { + char s[1024], t[1024]; + scanf("%s %s", s, t); + printf("%d\n", solver.solve(id[s], id[t])); + } + } +} +int main() { + SPOJ_SHPATH(); } diff --git a/data_structure/retroactive_queue.cc b/data_structure/retroactive_queue.cc new file mode 100644 index 0000000..ca63da9 --- /dev/null +++ b/data_structure/retroactive_queue.cc @@ -0,0 +1,169 @@ +// +// Fully Retroactive Queue +// +// Description: +// It maintains a list of actions ("push" and "pop"). +// We can insert/erase the actions and ask status ("front") in +// any position of the list. +// +// To implement this structure, we maintain the list by a BST +// and keep track the number of pushs/pops in each position +// by using the range addition and range minimum. +// +// Complexity: +// O(n log n). +// +// References: +// E. Demaine, J. Iacono, and S. Langerman (2007): +// "Retroactive data structures". ACM Transactions of Algorithms, +// vol.3, no.2, pp.1--21. +// + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +template +struct RetroactiveQueue { + struct Node { // Splay Tree + int type; // 0: none, 1: push, 2: pop + T value; + Node *child[2], *parent; + int a_push, d_push, a_pop, d_pop, min_remain; + } *head; + int remain(Node *x) { + return !x ? 0 : x->a_push + x->d_push - x->a_pop - x->d_pop; + } + RetroactiveQueue() : head(new Node({0})) { } + Node *update(Node *x) { + if (!x) return x; + x->min_remain = remain(x); + for (int i: {0, 1}) + if (x->child[i]) + x->min_remain = min(x->min_remain, x->child[i]->min_remain); + return x; + } + Node *pushdown(Node *x) { + if (!x) return x; + for (int i: {0, 1}) { + if (x->child[i]) { + x->child[i]->d_push += x->d_push; + x->child[i]->d_pop += x->d_pop; + } + } + x->a_push += x->d_push; + x->a_pop += x->d_pop; + x->d_push = x->d_pop = 0; + return x; + } + int dir(Node *x) { return x->parent && x->parent->child[1] == x; } + void link(Node *x, Node *y, int d) { + if (x) x->child[d] = y; + if (y) y->parent = x; + } + void rot(Node *x) { + int d = dir(x); + Node *p = x->parent; + pushdown(p->parent); pushdown(p); pushdown(x); + link(p->parent, x, dir(p)); + link(p, x->child[!d], d); + link(x, p, !d); + update(p); update(x); + } + void splay(Node *x) { + if (!x) return; + while (x->parent) { + if (x->parent->parent) { + if (dir(x) == dir(x->parent)) rot(x->parent); + else rot(x); + } + rot(x); + } + pushdown(x); + } + Node *insert(Node *x, Node *y) { + splay(x); + y->child[0] = x; + x->parent = y; + y->child[1] = x->child[1]; + x->child[1] = 0; + if (y->child[1]) { + y->child[1]->parent = y; + if (y->type == 1) y->child[1]->d_push += 1; + else if (y->type == 2) y->child[1]->d_pop += 1; + } + y->a_push = x->a_push + x->d_push + (y->type & 1); + y->a_pop = x->a_pop + x->d_pop + (y->type >> 1); + update(y->child[0]); + update(y->child[1]); + update(y); + return y; + } + Node *insert_push(Node *x, T a) { return insert(x, new Node({1, a})); } + Node *insert_pop(Node *x) { return insert(x, new Node({2})); } + Node *erase(Node *x) { + splay(x); + Node *y = x->child[1]; + if (!y) { + x = x->child[0]; + x->parent = 0; + return x; + } + if (x->type == 1) y->d_push -= 1; + else if (x->type == 2) y->d_pop -= 1; + y->parent = 0; + update(y); + while (y->child[0]) y = y->child[0]; + splay(y); + y->child[0] = x->child[0]; + if (y->child[0]) y->child[0]->parent = y; + update(y->child[0]); + update(y); + return y; + } + bool valid(Node *x) { splay(x); return x->min_remain >= 0; } + T front(Node *x) { + splay(x); + int k = x->a_pop + x->d_pop; + for (Node *y = x; y; ) { + pushdown(y); + if (y->a_push > k) { + x = y; + y = y->child[0]; + } else { + y = y->child[1]; + } + } + return x->value; + } + + + void display() { + splay(head); + display(head, 0); + } + void display(Node *x, int tab = 0) { + if (!x) return; + display(x->child[0], tab+2); + cout << string(tab, ' ') << x->type << " " << x->value << " " << x->a_push << " " << x->d_push << " " << x->a_pop << " " << x->d_pop << " " << x->min_remain << endl; + display(x->child[1], tab+2); + } +}; + +int main() { + RetroactiveQueue que; + auto i1 = que.insert_push(que.head, 10); + auto i2 = que.insert_push(i1, 20); + auto i3 = que.insert_push(i2, 30); + auto i4 = que.insert_pop(i3); + //auto i5 = que.insert_pop(i2); + que.erase(i1); + que.display(); + cout << que.front(i1) << endl; + cout << que.front(i2) << endl; + cout << que.front(i3) << endl; + cout << que.front(i4) << endl; +} diff --git a/data_structure/segment_recognizer.cc b/data_structure/segment_recognizer.cc new file mode 100644 index 0000000..6e87b4b --- /dev/null +++ b/data_structure/segment_recognizer.cc @@ -0,0 +1,149 @@ +// +// Segment Recognizer +// +// Description: +// Let M be an automaton and x be a sequence of alphabets. +// The segment recognizer computes the transitioned state +// starting from s and reading x[i,j) in O(|M|) time. +// The preprocessing requires O(|M| |x|) time and space. +// +// The same method is implemented by the segment tree, +// where the time complexity is O(log n) and the space +// complexity is O(n log n). Thus, the segment recognizer +// is efficient if |M| is small. +// +// Algorithm: +// Basically, it stores all the runs from all initial +// position i and initial state s. To reduce the space, +// it merges two runs if they yields the same state. +// +// Reference +// Mikola Bojanczyk (2009): "Factorization forests", +// International Conference on Developments in Language Theory, +// pp. 1--17. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +template +struct ModuloAutomaton { + const int init = 0; + int size() const { return MOD; } + int next(int s, int d) const { return (s+d)%MOD; } + int accept(int s) const { return s==0; } +}; + +// 0: free +// 1: selected +// 2: bottom +struct IndependenceAutomaton { + const int init = 0; + int size() const { return 3; } + int next(int s, int d) const { + if (s == 0) return d; + if (s == 1) return 2*d; + if (s == 2) return s; + } + int accept(int s) const { return s!=2; } +}; + +template +struct SegmentRecognizer { + Automaton M; + vector x; + + struct Tape { + int begin; + vector sequence; + }; + vector> index; + vector tapes; + + SegmentRecognizer(Automaton M, vector x) : M(M), x(x) { + index.assign(x.size()+1, vector(M.size())); + vector stripe; + for (int r = 0; r < M.size(); ++r) { + stripe.push_back(r); + index[0][r] = stripe[r]; + tapes.push_back({0, {r}}); + } + for (int i = 0; i < x.size(); ++i) { + unordered_set available; + for (int s = 0; s < M.size(); ++s) + available.insert(s); + vector reallocate; + for (int r = 0; r < M.size(); ++r) { + int next = M.next(tapes[stripe[r]].sequence.back(), x[i]); + if (available.count(next)) { + available.erase(next); + index[i+1][next] = stripe[r]; + tapes[stripe[r]].sequence.push_back(next); + } else { + reallocate.push_back(r); + } + } + for (int r: reallocate) { + int s = *available.begin(); + stripe[r] = tapes.size(); + index[i+1][s] = stripe[r]; + tapes.push_back({i+1, {s}}); + available.erase(s); + } + } + } + + int getState(int i, int s, int j) { + while (1) { + auto &tape = tapes[index[i][s]]; + if (j - tape.begin < tape.sequence.size()) { + return tape.sequence[j - tape.begin]; + } else { + i = tape.begin + tape.sequence.size(); + s = M.next(tape.sequence.back(), x[i-1]); + } + } + } +}; +template +SegmentRecognizer makeSegmentRecognizer(Automaton M, vector s) { + return SegmentRecognizer(M, s); +} + +int main() { + IndependenceAutomaton M; + + for (int n = 2; n < (1<<24); n*=2) { + vector x(n); + for (int i = 0; i < n; ++i) { + x[i] = (rand() % 10 == 0); + } + auto recognizer = makeSegmentRecognizer(M, x); + + tick(); + int count = 0; + for (int iter = 0; iter < n; ++iter) { + int v = (rand() % n) + 1; + int u = rand() % v; + count += recognizer.getState(u, 0, v); + } + double t = tick(); + cout << n << " " << t / n << endl; + } +} diff --git a/data_structure/union_find.cc b/data_structure/union_find.cc index 2cc999d..6a56b5e 100644 --- a/data_structure/union_find.cc +++ b/data_structure/union_find.cc @@ -1,17 +1,150 @@ +// +// Union Find Data Structure +// +// Description: +// An union-find data structure (aka. disjoint set data structure) +// maintains a disjoint sets and supports the following operations. +// - unite(u, v): merge sets containing u and v. +// - find(u, v) : return true if u and v are in the same set +// - size(u) : size of the set containing u. // -// Union Find data structure +// The weighted version additionally maintains the values for the +// elements and supports the following operations: +// - add(u, a) : value[u] += a +// - addSet(u, a): value[v] += a for v in set(u) +// - get(u) : return value[u] +// - getSet(u) : return sum(value[v] for v in set(u)) // +// Complexity: +// Amortized O(a(n)) for all operations. +// Here, a(n) is the inverse Ackermann function, which is +// less than five for a realistic size input. +// +// Verified: +// AOJ1330 http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1330 +// and other many problems. +// + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) -struct union_find { - vector p; - union_find(int n) : p(n, -1) { }; +struct UnionFind { + vector parent; // parent[root] is the negative of the size. + UnionFind(int n) : parent(n, -1) { }; bool unite(int u, int v) { - if ((u = root(u)) == (v = root(v))) return false; - if (p[u] > p[v]) swap(u, v); - p[u] += p[v]; p[v] = u; + u = root(u); v = root(v); + if (u == v) return false; + if (parent[u] > parent[v]) swap(u, v); + parent[u] += parent[v]; parent[v] = u; return true; } bool find(int u, int v) { return root(u) == root(v); } - int root(int u) { return p[u] < 0 ? u : p[u] = root(p[u]); } - int size(int u) { return -p[root(u)]; } + int root(int u) { return parent[u] < 0 ? u : parent[u] = root(parent[u]); } + int size(int u) { return -parent[root(u)]; } }; + +template +struct WeightedUnionFind { + struct Data { + int parent = -1; + T value = 0, delta = 0, total = 0; + }; + vector data; + WeightedUnionFind(int n) : data(n) { } + + void add(int u, T a) { + data[u].value += a; + data[root(u)].total += a; + } + void addSet(int u, T a) { + data[root(u)].delta += a; + data[root(u)].total -= data[root(u)].parent * a; + } + T get(int u) { + return data[u].value + root_(u).snd; + } + T getSet(int u) { + return data[root(u)].total; + } + bool unite(int u, int v) { + u = root(u); v = root(v); + if (u == v) return false; + if (data[u].parent > data[v].parent) swap(u, v); + data[u].parent += data[v].parent; + data[v].parent = u; + data[v].delta -= data[u].delta; + data[u].total += data[v].total; + return true; + } + pair root_(int u) { + if (data[u].parent < 0) return {u, data[u].delta}; + auto p = root_(data[u].parent); + p.snd += data[u].delta; + data[u].parent = p.fst; + data[u].delta = p.snd - data[p.fst].delta; + return p; + } + int root(int u) { return root_(u).fst; } + bool find(int u, int v) { + return root(u) == root(v); + } + int size(int u) { + return -data[root(u)].parent; + } +}; + +int test() { + int n = 5; + WeightedUnionFind uf(n); + for (int i = 0; i < n; ++i) { + uf.add(i, i); + } + uf.unite(2, 4); + for (int i = 0; i < n; ++i) { + cout << uf.get(i) << " " << uf.getSet(i) << endl; + } + cout << endl; + uf.unite(3, 4); + for (int i = 0; i < n; ++i) { + cout << uf.get(i) << " " << uf.getSet(i) << endl; + } + cout << endl; + uf.add(3,10); + for (int i = 0; i < n; ++i) { + cout << uf.get(i) << " " << uf.getSet(i) << endl; + } + cout << endl; + uf.addSet(4,5); + for (int i = 0; i < n; ++i) { + cout << uf.get(i) << " " << uf.getSet(i) << endl; + } +} + +void AOJ1330() { + for (int n, m; cin >> n >> m && n; ) { + WeightedUnionFind uf(n); + for (int i = 0; i < m; ++i) { + char c[2]; + int a, b; + scanf("%s %d %d", c, &a, &b); + --a; --b; + if (c[0] == '!') { + long long x; + scanf("%Ld", &x); + uf.addSet(b, uf.get(a)-uf.get(b)-x); + uf.unite(a, b); + } else { + if (uf.find(a, b)) { + printf("%Ld\n", uf.get(a)-uf.get(b)); + } else { + printf("UNKNOWN\n"); + } + } + } + } +} +int main() { AOJ1330(); } diff --git a/data_structure/union_find_undo.cc b/data_structure/union_find_undo.cc new file mode 100644 index 0000000..208ff82 --- /dev/null +++ b/data_structure/union_find_undo.cc @@ -0,0 +1,127 @@ +// +// Undoable Union Find +// +// It can undo each unite operation. +// +// Naming: +// Data structures with undo operation is weaker than +// partially-persistence (accessible all older vers) and +// slightly stronger than semi-persistence (backtrackable). +// +#include +#include +#include +#include +#include +#include + +using namespace std; +#define fst first +#define snd second +#define all(c) begin(c), end(c) + + +struct UndoableUnionFind { + vector parent; + vector> history; + UndoableUnionFind(int n) : parent(n, -1) { }; + bool unite(int u, int v) { + u = root(u); v = root(v); + if (u == v) { + history.push_back(make_tuple(-1,-1,-1)); + return false; + } else { + if (parent[u] > parent[v]) swap(u, v); + history.push_back(make_tuple(u, v, parent[v])); + parent[u] += parent[v]; parent[v] = u; + return true; + } + } + void undo() { + int u, v, w; + tie(u, v, w) = history.back(); + history.pop_back(); + if (u == -1) return; + parent[v] = w; + parent[u] -= parent[v]; + } + bool find(int u, int v) { return root(u) == root(v); } + int root(int u) { while (parent[u] >= 0) u = parent[u]; return u; } + int size(int u) { return -parent[root(u)]; } +}; + +struct OfflineDynamicConnectivity { + int n; + UndoableUnionFind uf; + OfflineDynamicConnectivity(int n) : n(n), uf(n) { } + + typedef pair Edge; + vector query; + vector ans; + map>> appear; + + void addEdge(int u, int v) { + if (u > v) swap(u, v); + appear[{u,v}].push_back({query.size(), 1<<30}); + } + void eraseEdge(int u, int v) { + if (u > v) swap(u, v); + appear[{u,v}].back().snd = query.size(); + } + int isConnected(int u, int v) { + query.push_back({u,v}); + return query.size()-1; + } + vector> edges; + void insert(int l, int r, int k, int s, int t, Edge e) { + s = max(s, l); t = min(r, t); + if (s >= t) return; + if (s == l && t == r) { + edges[k].insert(e); + } else { + insert(l, (l+r)/2, 2*k+1, s, t, e); + insert((l+r)/2, r, 2*k+2, s, t, e); + if (edges[2*k+1].count(e) && edges[2*k+2].count(e)) { + edges[2*k+1].erase(e); + edges[2*k+2].erase(e); + edges[k].insert(e); + } + } + } + void rec(int l, int r, int k) { + if (l >= r) return; + for (Edge e: edges[k]) uf.unite(e.fst, e.snd); + if (l+1 == r) { + ans[l] = uf.find(query[l].fst, query[l].snd); + } else { + rec(l, (l+r)/2, 2*k+1); + rec((l+r)/2, r, 2*k+2); + } + for (Edge e: edges[k]) uf.undo(); + } + void solve() { + int q = query.size(); + edges.resize(4*q); + for (auto a: appear) + for (auto b: a.snd) + insert(0, q, 0, b.fst, b.snd, a.fst); + ans.assign(q, 0); + rec(0, q, 0); + } +}; + +int main() { + OfflineDynamicConnectivity solver(3); + solver.isConnected(0,1); + solver.addEdge(0,1); + solver.isConnected(0,1); + solver.isConnected(1,2); + solver.addEdge(1,2); + solver.isConnected(0,2); + solver.eraseEdge(0,1); + solver.isConnected(0,2); + solver.solve(); + for (int i = 0; i < solver.query.size(); ++i) { + cout << solver.query[i].fst << " " << solver.query[i].snd << " " << solver.ans[i] << endl; + } +} diff --git a/dynamic_programming/bounded_knapsack.cc b/dynamic_programming/bounded_knapsack.cc new file mode 100644 index 0000000..0bff66f --- /dev/null +++ b/dynamic_programming/bounded_knapsack.cc @@ -0,0 +1,110 @@ +// +// Bounded Knapsack Problem +// +// Description: +// +// There are n kinds of items of profit pi, weight bi, and +// amount mi (i in {0...n-1}). For a given W, we want to select items +// to maximize the total profit subject to the total weight +// is at most W and the number of each item is at most mi. +// +// This problem can be solved by the following DP. +// E[j][w] = max {E[j-1][w], E[j-1][w-bj]+pj, E[j-1][w-2bj]+2pj. ...} +// A naive implementation requires O(nmW) time. However, we can reduce +// this to O(nW) as follows. +// +// We compute E[j][s], E[j][s+bj]. E[s+2bj] ... for each s in [0,bj). +// For simplicity, we consider s = 0. Then, we have +// E[j][w+bj] = max {E[j-1][w+bj], E[j-1][w]+pj, E[j-1][w-bj]+2pj. ...} +// By comparing this with the original formula, +// - E[j][w+bj] contains E[j-1][w+bj] term +// - E[j][w+bj] does not contain E[j-1][w-mjbj] term +// - The all terms have been added pj +// Thus, by using a data structure that supports these operations, +// we can perform the DP efficiently. The data structure is implemented +// by a maximum queue with one accumulation parameter. +// +// Complexity: +// +// O(n W) +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +int boundedKnapsackDP(vector ps, + vector ws, + vector ms, + int W) { + int n = ps.size(); + vector> dp(n+1, vector(W+1)); + for (int i = 0; i < n; ++i) { + for (int s = 0; s < ws[i]; ++s) { + int alpha = 0; + queue que; + deque peek; + for (int w = s; w <= W; w += ws[i]) { + alpha += ps[i]; + int a = dp[i][w]-alpha; + que.push(a); + while (!peek.empty() && peek.back() < a) peek.pop_back(); + peek.push_back(a); + while (que.size() > ms[i]+1) { + if (que.front() == peek.front()) peek.pop_front(); + que.pop(); + } + dp[i+1][w] = peek.front()+alpha; + } + } + } + int ans = 0; + for (int w = 0; w <= W; ++w) + ans = max(ans, dp[n][w]); + return ans; +} + +int boundedKnapsackDPNaive(vector ps, + vector ws, + vector ms, + int W) { + int n = ps.size(); + vector> dp(n+1, vector(W+1)); + for (int i = 0; i < n; ++i) { + for (int w = 0; w <= W; ++w) { + dp[i+1][w] = dp[i][w]; + for (int j = 1; j <= ms[i]; ++j) { + if (w - j*ws[i] < 0) break; + dp[i+1][w] = max(dp[i+1][w], dp[i][w-j*ws[i]]+j*ps[i]); + } + } + } + int ans = 0; + for (int w = 0; w <= W; ++w) + ans = max(ans, dp[n][w]); + return ans; +} + +int main() { + int seed; + seed = 20; + //cin >> seed; + seed = time(0); + srand(seed); + int n = 100; + int W = 10000; + vector ps(n), ws(n), ms(n); + for (int i = 0; i < n; ++i) { + ps[i] = rand() % n + 1; + ws[i] = rand() % n + 1; + ms[i] = rand() % n + 1; + //cout << ps[i] << " " << ws[i] << " " << ms[i] << endl; + } + + cout << boundedKnapsackDP(ps, ws, ms, W) << endl; + cout << boundedKnapsackDPNaive(ps, ws, ms, W) << endl; +} diff --git a/dynamic_programming/digit_dp.cc b/dynamic_programming/digit_dp.cc new file mode 100644 index 0000000..ec003ed --- /dev/null +++ b/dynamic_programming/digit_dp.cc @@ -0,0 +1,280 @@ +// +// Digit DP +// +// Description: +// +// Digit DP is a framework to solve problems of counting +// the numbers less than equal to a given number and +// whose digits satisfy some constraint. +// +// More generally, it can compute the sum-product +// sum { prod(x) : 0 <= x <= z } +// where +// prod(x) = (((e * x[0]) * x[1])...) * x[n-1]. +// +// The sum operator + is required to be commutative, and +// right-distributive with respect to * as +// (u + v) * d = (u * d + v * d) +// +// The constraint of digits should be represented by a +// finite automaton that reads digits from left to right. +// The DP has the table +// dp[digit][tight][status] +// with the following DP +// +// dp[0][1][M.init] = e +// for (int i = 0; i < n; ++i) { +// for (int tight = 0; tight <= 1; ++tight) { +// for (int state = 0; state < M.size(); ++state) { +// int lim = tight ? 'z'-0 : 9; +// for (int d = 0; d <= lim; ++d) { +// oplusTo(dp[i+1][tight&&d==lim][next(state,d)], +// otimes(dp[i][tight][state], d)); +// } +// } +// } +// } +// for (int tight = 0; tight <= 1; ++tight) +// for (int state = 0; state < M.size(); ++state) +// if (M.accept(state)) oplusTo(ans, dp[n][tight][state]; +// return ans; +// +// Here, tight means the left digits are tight so that the current +// digit cannot run over 0 to 9, and state means the state of the +// automaton, which compresses the 10^len states to |Automaton| states. +// +// Verified: +// SPOJ_CPCRC1C +// AOJ_ZIGZAG +// ABC_007D + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + + +// struct Value { +// Value &operator+(Value y) +// Value &operator*(int d) +// }; +// struct Automaton { +// int init +// int size() +// int next(int state, int d) +// bool accept(int state) +// }; +template +Value digitDP(string z, Value e, Automaton M, bool eq = 1) { + struct Maybe { + Value value; + bool undefined = true; + }; + auto oplusTo = [&](Maybe &x, Maybe y) { + if (x.undefined) x = y; + else if (!y.undefined) x.value += y.value; + }; + auto otimes = [&](Maybe x, int d) { + x.value *= d; + return x; + }; + int n = z.size(); + vector> curr(2, vector(M.size())); + curr[1][M.init] = {e, false}; + for (int i = 0; i < n; ++i) { + vector> next(2, vector(M.size())); + for (int tight = 0; tight <= 1; ++tight) { + for (int state = 0; state < M.size(); ++state) { + if (curr[tight][state].undefined) continue; + int lim = (tight ? z[i] - '0' : 9); + for (int d = 0; d <= lim; ++d) { + int tight_ = tight && d == lim; + int state_ = M.next(state, d); + oplusTo(next[tight_][state_], otimes(curr[tight][state], d)); + } + } + } + curr = next; + } + Maybe ans; + for (int tight = 0; tight <= eq; ++tight) + for (int state = 0; state < M.size(); ++state) + if (M.accept(state)) oplusTo(ans, curr[tight][state]); + return ans.value; +} + +template +string toString(T x) { + stringstream ss; + ss << x; + return ss.str(); +} + +// +// Sum of digits. +// Since sum is not distributive, (u + v) + d != (u + d + v + d), +// we need to augment the number to contain the number of numbers. +// Let + and * be defined by +// (u,a) + (v,b) = (u+v,a+b), +// (u,a) * d = (u+a*d,a). +// Then, they are right-distributive as +// ((u,a) + (v,b)) * c = (u+v,a+b) * c = (u+v+ac+bc,a+b), +// (u,a) * c + (v,b) * c = (u+ac,a) + (v+bc,b) = (u+v+ac+bc,a+b). +// +using Int = long long; +Int sumOfDigits(string z, bool eq = true) { + struct Value { + Int count, sum; + Value &operator+=(Value y) { count+=y.count; sum+=y.sum; return *this; } + Value &operator*=(int d) { sum+=count*d; return *this; } + }; + struct Automaton { + int init = 0; + int size() { return 1; } + int next(int s, int d) { return 0; } + int accept(int s) { return true; } + }; + return digitDP(z, (Value){1,0}, Automaton(), eq).sum; +} +void SPOJ_CPCRC1C() { + for (long long a, b; cin >> a >> b; ) { + if (a < 0 && b < 0) break; + cout << sumOfDigits(toString(b), true) + - sumOfDigits(toString(a), false) << endl; + } +} + +struct Automaton { + vector> trans; + vector is_accept; + int init = 0; + int next(int state, int a) { return trans[state][a]; } + bool accept(int state) { return is_accept[state]; } + int size() { return trans.size(); } +}; +template +Automaton intersectionAutomaton(Automaton1 A, Automaton2 B) { + Automaton M; + vector> table(A.size(), vector(B.size(), -1)); + vector x = {A.init}, y = {B.init}; + table[x[0]][y[0]] = 0; + for (int i = 0; i < x.size(); ++i) { + M.trans.push_back(vector(10, -1)); + M.is_accept.push_back(A.accept(x[i]) && B.accept(y[i])); + for (int a = 0; a <= 9; ++a) { + int u = A.next(x[i], a), v = B.next(y[i], a); + if (table[u][v] == -1) { + table[u][v] = x.size(); + x.push_back(u); + y.push_back(v); + } + M.trans[i][a] = table[u][v]; + } + } + return M; +} + +// +// Count the zigzag numbers that is a multiple of M. +// Here, a number is zigzag if its digits are alternatively +// increasing and decreasing, like 14283415... +// Since there are multiple conditions, we use automaton +// composition to simplify the approach. +// +void AOJ_ZIGZAG() { + char A[1000], B[1000]; + int M; + scanf("%s %s %d", A, B, &M); + + struct Value { + int value = 0; + Value &operator+=(Value x) { + if ((value += x.value) >= 10000) value -= 10000; + return *this; + } + Value &operator*=(int d) { + return *this; + } + } e = (Value){1}; + + // state = 0 : empty + // 1 : fail + // 2 ... 10 : singleton and last number is state-1 + // 11 ... 19 : increased and last number is state-10 + // 20 ... 28 : decreased and last number is state-20 + struct ZigZagAutomaton { + int init = 0; + int size() { return 29; } + int next(int state, int a) { + if (state == 0) return a == 0 ? 0 : a + 1; + if (state == 1) return 1; + if (state <= 10) { + int last = state - 1; + if (a > last) return a + 10; + else if (a < last) return a + 20; + } else if (state <= 19) { + int last = state - 10; + if (a < last) return a + 20; + } else if (state <= 28) { + int last = state - 20; + if (a > last) return a + 10; + } + return 1; + } + bool accept(int state) { return state != 1; } + } zigzag; + + // state = x : x == n % mod + struct ModuloAutomaton { + int mod; + ModuloAutomaton(int mod) : mod(mod) { } + int init = 0; + int size() { return mod; } + int next(int state, int a) { return (10 * state + a) % mod; } + bool accept(int state) { return state == 0; } + } modulo(M); + + auto IM = intersectionAutomaton(zigzag, modulo); + int a = digitDP(A, e, IM, 0).value; + int b = digitDP(B, e, IM, 1).value; + cout << (b + (10000 - a)) % 10000 << endl; +} + +// +// Count the numbers that does not contain 4 and 7 in each digit. +// +void ABC007D() { + string a, b; + cin >> a >> b; + + struct ForbiddenNumber { + int init = 0; + int size() { return 2; } + int next(int state, int a) { + if (state == 1) return 1; + if (a == 4 || a == 9) return 1; + return 0; + } + bool accept(int state) { return state == 1; } + }; + struct Counter { + long long value = 0; + Counter &operator+=(Counter x) { + value += x.value; + return *this; + } + Counter &operator*=(int d) { + return *this; + } + }; + cout << digitDP(b, (Counter){1}, ForbiddenNumber(), true).value + - digitDP(a, (Counter){1}, ForbiddenNumber(), false).value << endl; +} + +int main() { + ABC007D(); + //SPOJ_CPCRC1C(); + //AOJ_ZIGZAG(); +} diff --git a/dynamic_programming/longest_zigzag_subsequence.cc b/dynamic_programming/longest_zigzag_subsequence.cc new file mode 100644 index 0000000..0f31ad9 --- /dev/null +++ b/dynamic_programming/longest_zigzag_subsequence.cc @@ -0,0 +1,64 @@ +// +// Longest ZigZag Subsequence +// +// Description: +// +// A sequence xs is zigzag if x[i] < x[i+1], x[i+1] > x[i+2], for all i +// (initial direction can be arbitrary). The maximum length zigzag +// subsequence is computed in O(n) time by a greedy method. +// +// First, we contract contiguous same numbers. Then, the number of +// peaks corresponds to the longest zig-zag subsequence. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +template +int longestZigZagSubsequence(vector xs) { + int n = xs.size(), len = 1, prev = -1; + for (int i = 0, j; i < n; i = j) { + for (j = i+1; j < n && xs[i] == xs[j]; ++j); + if (j < n) { + int sign = (xs[i] < xs[j]); + if (prev != sign) ++len; + prev = sign; + } + } + return len; +} + +// DP for verification +template +int longestZigZagSubsequenceN(vector A) { + int n = A.size(); + vector> Z(n, vector(2)); + Z[0][0] = 1; + Z[0][1] = 1; + int best = 1; + for(int i = 1; i < n; i++){ + for(int j = i-1; j>= 0; j--){ + if(A[j] < A[i]) Z[i][0] = max(Z[j][1]+1, Z[i][0]); + if(A[j] > A[i]) Z[i][1] = max(Z[j][0]+1, Z[i][1]); + } + best = max(best, max(Z[i][0],Z[i][1])); + } + return best; +} + +int main() { + for (int seed = 0; seed < 10000; ++seed) { + srand(seed); + int n = 100; + vector a(n); + for (int i = 0; i < n; ++i) { + a[i] = rand() % n; + } + assert(longestZigZagSubsequence(a) == longestZigZagSubsequenceN(a)); + } +} diff --git a/geometry/_geom.cc b/geometry/_geom.cc new file mode 100644 index 0000000..9b4a7a4 --- /dev/null +++ b/geometry/_geom.cc @@ -0,0 +1,3624 @@ +// +// +// http://cs.smith.edu/classwiki/images/c/c8/Mitchell.MinPerim.pdf +// https://www.ics.uci.edu/~eppstein/pubs/EppOveRot-DCG-92.pdf +// https://en.wikipedia.org/wiki/Well-separated_pair_decomposition +// http://www.algorithmic-solutions.info/leda_manual/geo_alg.html +// +// future work: +// boolean operations (polygonal region overlay; 人間には実装無理では) +// ham sandwitch cut https://www.ti.inf.ethz.ch/ew/lehre/CG09/materials/v11.pdf + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(x,a) { auto y=(x); if (sign(y-a)) { cout << "line " << __LINE__ << #x << " = " << y << " != " << a << endl; exit(-1); } } +double urand() { return rand() / (1.0 + RAND_MAX); } + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +template +ostream &operator<<(ostream &os, const vector &v) { + os << "["; + for (int i = 0; i < v.size(); os << v[i++]) + if (i > 0) os << " "; + os << "]"; + return os; +} +template +ostream &operator<<(ostream &os, const vector> &v) { + os << "["; + for (int i = 0; i < v.size(); os << v[i++]) + if (i > 0) os << endl << " "; + os << "]"; + return os; +} + +const double PI = acos(-1.0); + +// implementation note: use EPS only in this function +// usage note: check sign(x) < 0, sign(x) > 0, or sign(x) == 0 +const double EPS = 1e-8; +int sign(double x) { + if (x < -EPS) return -1; + if (x > +EPS) return +1; + return 0; +} + +using real = long double; +struct point { + real x, y; + point &operator+=(point p) { x += p.x; y += p.y; return *this; } + point &operator-=(point p) { x -= p.x; y -= p.y; return *this; } + point &operator*=(real a) { x *= a; y *= a; return *this; } + point &operator/=(real a) { return *this *= (1.0/a); } + point operator-() const { return {-x, -y}; } + bool operator<(point p) const { + int s = sign(x - p.x); + return s ? s < 0 : sign(y - p.y) < 0; + } +}; +bool operator==(point p, point q) { return !(p < q) && !(q < p); } +bool operator!=(point p, point q) { return p < q || q < p; } +bool operator<=(point p, point q) { return !(q < p); } +point operator+(point p, point q) { return p += q; } +point operator-(point p, point q) { return p -= q; } +point operator*(real a, point p) { return p *= a; } +point operator*(point p, real a) { return p *= a; } +point operator/(point p, real a) { return p /= a; } +real dot(point p, point q) { return p.x*q.x+p.y*q.y; } +real cross(point p, point q) { return p.x*q.y-p.y*q.x; } // left turn > 0 +real norm2(point p) { return dot(p,p); } +point orth(point p) { return {-p.y, p.x}; } +real norm(point p) { return sqrt(dot(p,p)); } +real arg(point p) { return atan2(p.y, p.x); } +real arg(point p, point q){ return atan2(cross(p,q), dot(p,q)); } + +istream &operator>>(istream &is, point &p) { is>>p.x>>p.y;return is; } +ostream &operator<<(ostream &os, const point &p) { os<<"("< 0 && p.y >= 0) return i; + return 0; + } + bool operator()(point p, point q) const { + p = p - o; q = q - o; + if (quad(p) != quad(q)) return s*quad(p) < s*quad(q); + if (cross(p, q)) return s*cross(p, q) > 0; + return norm2(p) < norm2(q); // closer first + } +}; + +struct line { point p, q; }; +bool operator==(line l, line m) { + return !sign(cross(l.p-l.q,m.p-m.q)) && !sign(cross(l.p-l.q,m.p-l.p)); +} + +struct segment { point p, q; }; +bool operator==(segment l, line m) { + return (l.p==m.p && l.q==m.q) || (l.p==m.q && l.q==m.p); // do not consider the direction +} +struct circle { point p; real r; }; +bool operator==(circle c, circle d) { return c.p == d.p && !sign(c.r - d.r); } + +// inner tangent polygon. +// sometimes, circle problem can be reduced to discretized problem +vector discretize(circle c, int n = 50) { + vector ps; + for (int i = 0; i < n; ++i) { + double x = cos(2*PI*i/n), y = sqrt(1 - x*x); + ps.push_back(c.p + c.r * point({x,y})); + } + return ps; +} + +typedef vector polygon; + + +//----------------------------------------------------------------------------- +// visualizer +//----------------------------------------------------------------------------- +struct visualizer { + real minx, maxx, miny, maxy, scale; + ofstream ofs; + visualizer(string s = "data.js") : ofs(s) { + minx = miny = 1.0/0.0; + maxx = maxy = -1.0/0.0; + } + void update(point p) { + minx = min(minx, p.x); miny = min(miny, p.y); + maxx = max(maxx, p.x); maxy = max(maxy, p.y); + scale = 480/(max(maxx-minx, max(maxy-miny,1.0l))); + } + double X(point p) { return scale * (p.x-minx) + 10; } + double Y(point p) { return 490 - scale * (p.y-miny); } + vector ps; + vector ss; + vector cs; + visualizer &operator<<(circle c) { + cs.push_back(c); + update(c.p + point({ c.r, c.r})); + update(c.p + point({-c.r,-c.r})); + return *this; + } + visualizer &operator<<(point p) { + ps.push_back(p); + update(p); + return *this; + } + visualizer &operator<<(segment s) { + ss.push_back(s); + update(s.p); + update(s.q); + return *this; + } + ~visualizer() { + for (point p: ps) + ofs << "circle(" << X(p) << "," << Y(p) << ",3.0)" << endl; + for (segment s: ss) + ofs << "line(" << X(s.p) << "," << Y(s.p) << "," + << X(s.q) << "," << Y(s.q) << ")" << endl; + for (circle c: cs) + ofs << "circle(" << X(c.p) << "," << Y(c.p) << "," << scale*c.r << ")" << endl; + } +}; + + +//----------------------------------------------------------------------------- +// point p is on line l +//----------------------------------------------------------------------------- +vector intersect(line l, point p) { + if (sign(cross(l.p-p, l.q-p)) != 0) return {}; + return {p}; +} +vector intersect(point p, line l) { + return intersect(l, p); +} + +//----------------------------------------------------------------------------- +// point p is on segment s +//----------------------------------------------------------------------------- +vector intersect(segment s, point p) { + if (sign(cross(s.p-p, s.q-p)) != 0) return {}; + if (sign( dot(s.p-p, s.q-p)) > 0) return {}; // > for strict intersect + return {p}; // >= for weak intersect +} +vector intersect(point p, segment s) { + return intersect(s, p); +} + +//----------------------------------------------------------------------------- +// intersection of two lines +// +// Derivation: The crosspoint equation is +// l.p + (l.q - l.p) t == m.p + (m.q - m.p) s ... (CP.1) +// Taking a cross product with (m.q - m.p), we have +// (m.q - m.p) x (l.q - l.p) t == (m.q - m.p) x (m.p - l.p) +// ~~~~~~~~~~~~a~~~~~~~~~~~~ ~~~~~~~~~~~~b~~~~~~~~~~~~ +// +// If a != 0, these two lines have a proper crosspoint. +// If a == 0 and b == 0, these two lines are the same line. +// Otherwise, these two lines are parallel. +//----------------------------------------------------------------------------- +vector intersect(line l, line m) { + auto a = cross(m.q - m.p, l.q - l.p); + auto b = cross(l.p - m.p, l.q - l.p); + if ( sign(a)) return {m.p + b/a*(m.q - m.p)}; // properly crossing + if (!sign(b)) return {m.p, m.q}; // same line + return {}; // disjoint parallel +} + +//----------------------------------------------------------------------------- +// intersection of line and segment +// +// In CP.1, t must be in [0, 1]. Thus 0 <= b/a <= 1 is required. +// By assuming a > 0, it is equivalent to b >= 0 and b-a <= 0 +//----------------------------------------------------------------------------- +vector intersect(line l, segment s) { + auto a = cross(s.q - s.p, l.q - l.p); + auto b = cross(l.p - s.p, l.q - l.p); + if (a < 0) { a *= -1; b *= -1; } + if (sign(b) < 0 || sign(a-b) < 0) return {}; // no intersect + if (sign(a) != 0) return {s.p + b/a*(s.q - s.p)}; // properly crossing + if (sign(b) == 0) return {s.p, s.q}; // same line + return {}; // disjoint parallel +} + +//----------------------------------------------------------------------------- +// intersection of two segments +// +// Solve two CP.1s simultaneously. +// If two segments are overlapping, it is bit difficult. +//----------------------------------------------------------------------------- +vector intersect(segment s, segment t) { + auto a = cross(s.q - s.p, t.q - t.p); + auto b = cross(t.p - s.p, t.q - t.p); + auto c = cross(s.q - s.p, s.p - t.p); + if (a < 0) { a = -a; b = -b; c = -c; } + if (sign(b) < 0 || sign(a-b) < 0 || + sign(c) < 0 || sign(a-c) < 0) return {}; // disjoint + if (sign(a) != 0) return {s.p + b/a*(s.q - s.p)}; // properly crossing + vector ps; // same line + auto insert_if_possible = [&](point p) { + for (auto q: ps) if (sign(dot(p-q, p-q)) == 0) return; + ps.push_back(p); + }; + if (sign(dot(s.p-t.p, s.q-t.p)) <= 0) insert_if_possible(t.p); + if (sign(dot(s.p-t.q, s.q-t.q)) <= 0) insert_if_possible(t.q); + if (sign(dot(t.p-s.p, t.q-s.p)) <= 0) insert_if_possible(s.p); + if (sign(dot(t.p-s.q, t.q-s.q)) <= 0) insert_if_possible(s.q); + return ps; +} + +//----------------------------------------------------------------------------- +// reflected point with respect to l +//----------------------------------------------------------------------------- +point reflection(point p, line l) { + auto a = dot(l.p-l.q, l.p-l.q); + auto b = dot(l.p-p, l.p-l.q); + return 2 * (l.p + a/b*(l.q - l.p)) - p; +} + +//----------------------------------------------------------------------------- +// closest point on l +//----------------------------------------------------------------------------- +point projection(point p, line l) { + auto a = dot(l.p-l.q, l.p-l.q); + auto b = dot(l.p-p, l.p-l.q); + return l.p + a/b*(l.q - l.p); +} + +//----------------------------------------------------------------------------- +// closest point on s +//----------------------------------------------------------------------------- +point projection(point p, segment s) { + auto a = dot(s.p-s.q, s.p-s.q); + auto b = dot(s.p - p, s.p-s.q); + if (sign(b) < 0) return s.p; + if (sign(a-b) < 0) return s.q; + return s.p + b/a*(s.q - s.p); +} + +//----------------------------------------------------------------------------- +// closest point on c +//----------------------------------------------------------------------------- +point projection(point p, circle c) { + point v = p - c.p; + return c.p + c.r * v / norm(v); +} +//----------------------------------------------------------------------------- +// distances +//----------------------------------------------------------------------------- +real dist(point p, point q) { + return norm(p-q); +} +real dist(point p, line l) { + return dist(p, projection(p, l)); +} +real dist(line l, point p) { + return dist(p, l); +} +real dist(line l, line m) { + if (sign(cross(l.p-l.q,m.p-m.q))) return 0; // cross + return dist(l.p, m); +} +real dist(point p, segment s) { + return dist(p, projection(p, s)); +} +real dist(line l, segment s) { + if (intersect(l, s).size()) return 0; + return min(dist(l, s.p), dist(l, s.q)); +} +real dist(segment s, line l) { + return dist(l, s); +} +real dist(segment s, segment T) { + if (intersect(s, T).size()) return 0; + return min({dist(s.p,T), dist(s.q,T), dist(T.p,s), dist(T.q,s)}); +} + + +//----------------------------------------------------------------------------- +// intersection points of two circles +//----------------------------------------------------------------------------- +vector intersect(circle c, circle d) { + if (c.r < d.r) swap(c, d); + auto pow2 = [](real a) { return a*a; }; + auto g = dot(c.p-d.p, c.p-d.p); + if (sign(g) == 0) { + if (sign(c.r-d.r) != 0) return {}; + return {{c.p.x+c.r, c.p.y}, {c.p.x, c.p.y+c.r}, {c.p.x-c.r, c.p.y}}; + } + int inner = sign(g-pow2(c.r-d.r)); + int outer = sign(g-pow2(c.r+d.r)); + if (inner < 0 || outer > 0) return {}; + if (inner == 0) return {(c.r*d.p-d.r*c.p)/(c.r-d.r)}; + if (outer == 0) return {(c.r*d.p+d.r*c.p)/(c.r+d.r)}; + auto eta = (pow2(c.r) - pow2(d.r) + g)/(2*g); + auto mu = sqrt(pow2(c.r)/g - pow2(eta)); + point q = c.p + eta*(d.p-c.p), v = mu*orth(d.p - c.p); + return {q + v, q - v}; +} + +//----------------------------------------------------------------------------- +// intersection of line and circle +//----------------------------------------------------------------------------- +vector intersect(line l, circle c) { + point u = l.q - l.p, v = l.p - c.p; + auto a = dot(u,u), b = dot(u,v)/a, t = (dot(v,v) - c.r*c.r)/a; + auto det = b*b - t; + if (sign(det) < 0) return {}; // no solution + if (sign(det) == 0) return {l.p - b*u}; // touch inner/outer + return {l.p - (b + sqrt(det))*u, // properly intersect + l.p - (b - sqrt(det))*u}; +} +vector intersect(circle c, line l) { + return intersect(l, c); +} + +//----------------------------------------------------------------------------- +// intersection of segment and circle +// number of points: +// 0 ==> no intersect +// 1 ==> touch +// 2 ==> contained +// 3 ==> penetrating single side +// 4 ==> penetrating both sides +// sorted from s.p to s.q; usually, one would use ans[0] and ans.back(). +//----------------------------------------------------------------------------- +vector intersect(circle c, segment s) { + point u = s.q - s.p, v = s.p - c.p; + auto a = dot(u,u), b = dot(u,v)/a, t = (dot(v,v) - c.r*c.r)/a; + auto det = b*b - t; + if (sign(det) < 0) return {}; // no solution + + auto t1 = -b - sqrt(det), t2 = -b + sqrt(det); + vector ps; + auto insert_if_possible = [&](point p) { + for (auto q: ps) if (sign(dot(p-q, p-q)) == 0) return; + ps.push_back(p); + }; + if (sign(c.r - norm(s.p-c.p)) >= 0) insert_if_possible(s.p); + if (sign(t1) >= 0 && sign(1-t1) >= 0) insert_if_possible(s.p+t1*u); + if (sign(t2) >= 0 && sign(1-t2) >= 0) insert_if_possible(s.p+t2*u); + if (sign(c.r - norm(s.q-c.p)) >= 0) insert_if_possible(s.q); + return ps; +} +vector intersect(segment s, circle c) { + return intersect(c, s); +} +bool contains(circle c, point p) { + return sign(dot(c.p-p, c.p-p) - c.r * c.r) <= 0; +} + + +//----------------------------------------------------------------------------- +// polygon contains a point +// half-line crossing method +//----------------------------------------------------------------------------- +int contains(polygon ps, point p) { + bool in = false; + for (int i = 0; i < ps.size(); ++i) { + int j = (i+1 == ps.size() ? 0 : i+1); + point a = ps[i] - p, b = ps[j] - p; + if (a.y > b.y) swap(a, b); + if (a.y <= 0 && 0 < b.y && cross(a, b) < 0) in = !in; + if (!sign(cross(a, b)) && sign(dot(a, b)) <= 0) + return 1; // point on the edge + } + return in ? 2 : 0; // point in:out the polygon +} + +//----------------------------------------------------------------------------- +// convex hull with the given points +// +// Andrew's monotone chain +// +// [verified] +// +// A. M. Andrew (1979): +// Another efficient algorithm for convex hulls in two dimensions. +// Information Processing Letters 9 (5): 216-219. +//----------------------------------------------------------------------------- +polygon convex_hull(vector ps) { + int n = ps.size(), k = 0; + sort(all(ps)); + vector ch(2*n); + auto cond = [&](point p, point q, point o) { + int a = sign(cross(p-o, q-o)); // return a < 0 if no three points on line + return a ? a < 0 : sign(dot(p-o, q-o)) >= 0; + }; + for (int i = 0; i < n; ch[k++] = ps[i++]) // lower-hull + for (; k >= 2 && cond(ch[k-2], ch[k-1], ps[i]); --k); + for (int i = n-2, t = k+1; i >= 0; ch[k++] = ps[i--]) // upper-hull + for (; k >= t && cond(ch[k-2], ch[k-1], ps[i]); --k); + ch.resize(k-1); + return ch; +} + + +//----------------------------------------------------------------------------- +// farthest pair of points +// +// is located on the convex hull. perform rotating caliper. +// +// [verified ACAC002] +//----------------------------------------------------------------------------- +pair farthest_pair(vector ps) { + vector ch = convex_hull(ps); + int n = ch.size(); + int u = 0, v = 1; + real best = -1; + for (int i = 0, j = 1; i < n; ++i) { + while (1) { + int k = (j+1 < n ? j+1 : 0); + real len = norm2(ch[j] - ch[i]); + if (sign(len - norm2(ch[k] - ch[i])) <= 0) j = k; + else { + if (best < len) { best = len; u = i; v = j; } + break; + } + } + } + return make_pair(ch[u], ch[v]); +} + + +//----------------------------------------------------------------------------- +// signed area of arbitrary polygon +// +// [verified] +//----------------------------------------------------------------------------- +real area(polygon ps) { + if (ps.size() <= 2) return 0; + auto a = cross(ps.back(), ps[0]); + for (int i = 0; i+1 < ps.size(); ++i) + a += cross(ps[i], ps[i+1]); + return a/2; +} + +//----------------------------------------------------------------------------- +// left side of a convex polygon with respect to a line +// +// [verified] +//----------------------------------------------------------------------------- +polygon convex_cut(polygon ps, line l) { + vector qs; + for (int i = 0; i < ps.size(); ++i) { + int j = (i+1 == ps.size() ? 0 : i+1); + if (sign(cross(l.p - ps[i], l.q - ps[i])) >= 0) qs.push_back(ps[i]); + if (sign(cross(l.p - ps[i], l.q - ps[i])) * + sign(cross(l.p - ps[j], l.q - ps[j])) < 0) { + auto a = cross(ps[j] - ps[i], l.q - l.p); + auto b = cross(l.p - ps[i], l.q - l.p); + qs.push_back(ps[i] + b/a*(ps[j] - ps[i])); + } + } + return qs; +} + +//----------------------------------------------------------------------------- +// the circle through three points +//----------------------------------------------------------------------------- +circle three_point_circle(point p, point q, point r) { + point u = orth(q - p), v = r - p; + point o = (p+q + u*dot(r-q,v)/dot(u,v))/2; + return {o, norm(p-o)}; +} +//----------------------------------------------------------------------------- +// area of quadrilateral; +// not verified +//----------------------------------------------------------------------------- +real quadrilateral_area(real a, real b, real c, real d) { + real s = a+b+c+d; + return sqrt((s-a)*(s-b)*(s-c)*(s-d))/4; +} +real triangle_area(real a, real b, real c) { + return quadrilateral_area(a, b, c, 0); +} +real excircle_radius(real a, real b, real c) { + return a*b*c/4/triangle_area(a, b, c); +} +real incircle_radius(real a, real b, real c) { + return 2*triangle_area(a,b,c)/(a+b+c); +} + +//----------------------------------------------------------------------------- +// tangent line of a circle at the nearest point from p +// +// Let q be a tangent point. +// The angle between q -- p -- c.p is +// sin(t) = r/|p - c.p|. +// and the solution is +// p + (c.p - p) * exp(\pm it). +// +// [verified] +//----------------------------------------------------------------------------- +vector tangent(point p, circle c) { + point u = p - c.p, v = orth(u); + auto g = dot(u,u) - c.r*c.r; + if (sign(g) < 0) return {}; + if (sign(g) == 0) return {{p, p + v}}; + u = u * (c.r*c.r/dot(u,u)); + v = v * (c.r*sqrt(g)/dot(v,v)); + return {{p, c.p + u - v}, {p, c.p + u + v}}; +} +vector tangent(circle c, point p) { + return tangent(p, c); +} + +//----------------------------------------------------------------------------- +// common tangents of two circles +// +// [verified] +//----------------------------------------------------------------------------- +vector tangent(circle c, circle d) { + if (c.r < d.r) swap(c, d); + auto g = dot(c.p-d.p, c.p-d.p); + if (sign(g) == 0) return {}; // same origin + point u = (d.p-c.p)/sqrt(g), v = orth(u); // coordinate systems + vector ls; + for (int s = +1; s >= -1; s -= 2) { + auto h = (c.r+s*d.r)/sqrt(g); // = cos(theta) + if (sign(1 - h*h) == 0) { // touch inner/outer + ls.push_back({c.p+c.r*u, c.p+c.r*(u+v)}); + } else if (sign(1 - h*h) > 0) { // properly intersect + point uu = h*u, vv = sqrt(1-h*h)*v; + ls.push_back({c.p+c.r*(uu+vv), d.p-d.r*(uu+vv)*s}); + ls.push_back({c.p+c.r*(uu-vv), d.p-d.r*(uu-vv)*s}); + } + } + return ls; +} + +//----------------------------------------------------------------------------- +// common tangent circles of two lines of radius r +// +// o|o +// --+-- +// o|o +// +// number of solutions: +// 0: parallel and distance < r +// 1: parallel and distance = r +// 4: non-parallel +// +// [non-verified] +//----------------------------------------------------------------------------- +vector tangent_circles(line l, line m, real r) { + vector cs; + real a = cross(l.p-m.p, l.q-l.p), b = cross(m.q-m.p, l.q-l.p); + if (!sign(b)) { // parallel case + if (l.q < l.p) swap(l.p, l.q); + if (m.q < m.p) swap(m.p, m.q); + if (sign(cross(m.p-l.p, m.q-l.p)) >= 0) swap(l, m); // l is lower + point v = orth(m.q - m.p); v /= norm(v); + real d = a / cross(l.q - l.p, v); + if (sign(d - 2*r) == 0) cs.push_back({l.p + r * v, r}); + } else { + point o = m.p + a/b * (m.q - m.p), u = l.q - l.p, v = m.q - m.p; + u /= norm(u); v /= norm(v); + for (int i = 0; i < 4; ++i) { + point w = u + v; w /= norm(w); + real t = r / sqrt(1 - dot(v,w)*dot(v,w)); + cs.push_back({o + t * w, r}); + u *= -1; swap(u, v); + } + } + return cs; +} + +//----------------------------------------------------------------------------- +// find a line that passes the maximum number of points +// +// [non-verified] +//----------------------------------------------------------------------------- +int maximum_points_line(vector ps) { + sort(all(ps)); // assume dx >= 0; if dx == 0 then dy >= 0 + int max_count = 0; + for (int i = 0; i < ps.size(); ++i) { + vector qs; + int base = 1; + for (int j = 0; j < i; ++j) + if (ps[j] == ps[i]) ++base; + else qs.push_back(ps[j] - ps[i]); + sort(all(qs), polar_angle()); + for (int j = 0, k; j < qs.size(); j += k) { + for (k = 1; j+k < qs.size() && sign(cross(qs[j], qs[j+k])) == 0; ++k); + max_count = max(max_count, base + k); + } + } + return max_count; +} + +// for comparison +int maximum_points_line_n(vector ps) { + sort(all(ps)); + int ans = 0; + for (int i = 0; i < ps.size(); ++i) { + for (int j = i+1; j < ps.size(); ++j) { + if (ps[i] == ps[j]) continue; + int count = 0; + for (int k = 0; k < ps.size(); ++k) { + if (intersect((line){ps[i], ps[j]}, ps[k]).size() > 0) ++count; + } + ans = max(ans, count); + } + } + return ans; +} +void verify_maximum_points_line() { + int n = 100; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i].x = rand() % 20; + ps[i].y = rand() % 20; + } + cout << maximum_points_line(ps) << endl; + cout << maximum_points_line_n(ps) << endl; +} + + +//----------------------------------------------------------------------------- +// triangulate simple polygon in O(n) time. +// +// [non-verified]; future work for polygonal overlay +//----------------------------------------------------------------------------- +real triangulate(vector ps) { + int n = ps.size(); + vector next(n); + for (int i = 0; i < n-1; ++i) next[i] = i+1; + auto is_ear = [&](int i, int j, int k) { + if (sign(cross(ps[j]-ps[i], ps[k]-ps[i])) <= 0) return false; + for (int l = next[k]; l != i; l = next[l]) + if (sign(cross(ps[i]-ps[l], ps[j]-ps[l])) >= 0 + && sign(cross(ps[j]-ps[l], ps[k]-ps[l])) >= 0 + && sign(cross(ps[k]-ps[l], ps[i]-ps[l])) >= 0) return false; + return true; + }; + real area = 0; + for (int i = 0; next[next[i]] != i; ) { + if (is_ear(i, next[i], next[next[i]])) { + area += abs(cross(ps[next[i]]-ps[i], ps[next[next[i]]] - ps[i])) / 2; + next[i] = next[next[i]]; + } else i = next[i]; + } + return area; +} + +//----------------------------------------------------------------------------- +// area of intersection of two circles +// [verified] +//----------------------------------------------------------------------------- +real intersection_area(circle c, circle d) { + if (c.r < d.r) swap(c, d); + auto A = [&](real r, real h) { + return r*r*acos(h/r)-h*sqrt(r*r-h*h); + }; + auto l = norm(c.p - d.p), a = (l*l + c.r*c.r - d.r*d.r)/(2*l); + if (sign(l - c.r - d.r) >= 0) return 0; // far away + if (sign(l - c.r + d.r) <= 0) return PI*d.r*d.r; + if (sign(l - c.r) >= 0) return A(c.r, a) + A(d.r, l-a); + else return A(c.r, a) + PI*d.r*d.r - A(d.r, a-l); +} +//----------------------------------------------------------------------------- +// circle-polygon intersection area +// [verified] +//----------------------------------------------------------------------------- +real intersection_area(vector ps, circle c) { + auto tri = [&](point p, point q){ + point d = q - p; + auto a = dot(d,p)/dot(d,d), b = (dot(p,p)-c.r*c.r)/dot(d,d); + auto det = a*a - b; + if (det <= 0) return arg(p,q) * c.r*c.r / 2; + auto s = max(0.l, -a-sqrt(det)), t = min(1.l, -a+sqrt(det)); + if (t < 0 || 1 <= s) return c.r*c.r*arg(p,q)/2; + point u = p + s*d, v = p + t*d; + return arg(p,u)*c.r*c.r/2 + cross(u,v)/2 + arg(v,q)*c.r*c.r/2; + }; + auto sum = 0.0; + for (int i = 0; i < ps.size(); ++i) + sum += tri(ps[i] - c.p, ps[(i+1)%ps.size()] - c.p); + return sum; +} +real intersection_area(circle c, vector ps) { + return intersection_area(ps, c); +} + +//----------------------------------------------------------------------------- +// find the closest pair of points by sweepline +// [verified] +//----------------------------------------------------------------------------- +pair closest_pair(vector ps) { + sort(all(ps), [](point p, point q) { return p.y < q.y; }); + auto u = ps[0], v = ps[1]; + auto best = dot(u-v, u-v); + auto update = [&](point p, point q) { + auto dist = dot(p-q, p-q); + if (best > dist) { best = dist; u = p; v = q; } + }; + set S; S.insert(u); S.insert(v); + for (int l = 0, r = 2; r < ps.size(); ++r) { + if (S.count(ps[r])) return {ps[r], ps[r]}; + if ((ps[l].y-ps[r].y)*(ps[l].y-ps[r].y) > best) S.erase(ps[l++]); + auto i = S.insert(ps[r]).fst; + for (auto j = i; ; ++j) { + if (j == S.end() || (i->x-j->x)*(i->x-j->x) > best) break; + if (i != j) update(*i, *j); + } + for (auto j = i; ; --j) { + if (i != j) update(*i, *j); + if (j == S.begin() || (i->x-j->x)*(i->x-j->x) > best) break; + } + } + return {u, v}; +} +//----------------------------------------------------------------------------- +// find the closest pair of points by divide and conquer +// (slower than the sweepline) +//----------------------------------------------------------------------------- +pair closest_pair2(vector ps) { + sort(all(ps), [](point p, point q) { return p.y < q.y; }); + auto u = ps[0], v = ps[1]; + auto best = dot(u-v, u-v); + auto update = [&](point p, point q) { + auto dist = dot(p-q, p-q); + if (best > dist) { best = dist; u = p; v = q; } + }; + function rec = [&](int l, int r) { + if (r - l <= 1) { + for (int i = l; i < r; ++i) + for (int j = i+1; j < r; ++j) + update(ps[i], ps[j]); + stable_sort(&ps[l], &ps[r]); + } else { + int m = (l + r) / 2; + auto y = ps[m].y; + rec(l, m); rec(m, r); + inplace_merge(&ps[l], &ps[m], &ps[r]); + vector qs; + for (int i = l; i < r; ++i) { + if ((ps[i].y-y)*(ps[i].y-y) >= best) continue; + for (int j = (int)qs.size()-1; j >= 0; --j) { + if ((qs[j].x-ps[i].x)*(qs[j].x-ps[i].x) >= best) break; + update(qs[j], ps[i]); + } + qs.push_back(ps[i]); + } + } + }; + rec(0, ps.size()); + return {u, v}; +} + + +//----------------------------------------------------------------------------- +// half-plane intersection in O(n log n) +// [un-verified; buggy?] +//----------------------------------------------------------------------------- +vector half_plane_intersection(vector ls) { + int n = ls.size(); + sort(all(ls), [&](line l, line m) { return arg(l.p-l.q) < arg(m.p-m.q); }); + int L = 0, R = 0; + vector bd(2*n); + vector ps(2*n); + bd[R] = ls[0]; + auto left = [&](point p, line l) { return sign(cross(l.p-p, l.q-p)) >= 0; }; + for (int i = 1; i < n; ++i) { + if (!sign(cross(bd[R].p-bd[R].q, ls[i].p-ls[i].q))) { + if (left(ls[i].p, bd[R])) bd[R] = ls[i]; + } else { + while (L < R && !left(ps[R-1], ls[i])) --R; + while (L < R && !left(ps[L] , ls[i])) ++L; + bd[++R] = ls[i]; + } + if (R > L) ps[R-1] = intersect(bd[R-1], bd[R])[0]; + } + while (L < R && !left(ps[R-1], bd[L])) --R; + if (R - L <= 1) return {}; + if (R > L) ps[R] = intersect(bd[L], bd[R])[0]; + vector ch = {ps[L]}; + for (int i = L+1; i <= R; ++i) + if (!(ch.back() == ps[i])) ch.push_back(ps[i]); + if (ch.size() > 1 && ch.back() == ch[0]) ch.pop_back(); + return ch; +} + + + +//----------------------------------------------------------------------------- +// geometric median, i.e., p in argmin sum |ps[i] - p|_2 +// +// Weiszfield's iterative reweighted method least squares +// with avoiding equal points +// [verified: LA5102] +//----------------------------------------------------------------------------- +point geometric_median(vector ps) { + point g = {0,0}; + real eta = 1000.0; + for (int iter = 0; iter < 1000000; ++iter, eta /= 2) { + real w = 0; + point h = {0,0}; + for (point p: ps) { + real a = eta + norm(p - g); + h = h + p/a; w = w + 1/a; + } + h = h / w; swap(g, h); + if (norm(g - h) < EPS) break; + } + return g; +} + + +//----------------------------------------------------------------------------- +// find a circle of radius r that contains many points as possible +// +// quad-tree search (this is faster than the next sweepline solution) +// [verified: AOJ 1132] +//----------------------------------------------------------------------------- +int maximum_circle_cover(vector ps, double r) { + const double dx[] = {1,-1,-1,1}, dy[] = {1,1,-1,-1}; + point best_p; + int best = 0; + function)> + rec = [&](point p, double w, vector ps) { + w /= 2; + point qs[4]; + vector pss[4]; + for (int i = 0; i < 4; ++i) { + qs[i] = p + w * point({dx[i], dy[i]}); + int lo = 0; + for (point q: ps) { + auto d = dist(qs[i], q); + if (sign(d - r) <= 0) ++lo; + if (sign(d - w*sqrt(2) - r) <= 0) pss[i].push_back(q); + } + if (lo > best) { best = lo; best_p = qs[i]; } + } + for (int i = 0, j; i < 4; ++i) { + for (int j = i+1; j < 4; ++j) + if (pss[i].size() < pss[j].size()) + swap(pss[i], pss[j]), swap(qs[i], qs[j]); + if (pss[i].size() <= best) break; + rec(qs[i], w, pss[i]); + } + }; + real w = 0; + for (point p: ps) w = max(w, max(abs(p.x), abs(p.y))); + rec({0,0}, w, ps); + return best; //best_p; +} + +//----------------------------------------------------------------------------- +// find a circle of radius r that contains many points as possible +// +// sweepline O(n^2 log n). +// [verified: AOJ 1132] +//----------------------------------------------------------------------------- +int maximum_circle_cover2(vector ps, double r) { + int best = 0; + for (point p: ps) { + int count = 0; + vector> aux; + for (point q: ps) { + auto d = dist(p, q); + if (sign(d) == 0) ++count; + else if (sign(d - 2*r) <= 0) { + auto theta = arg(q-p); + auto phi = acos(min(1.l, d/(2*r))); + aux.push_back({theta-phi, -1}); + aux.push_back({theta+phi, +1}); + } + } + sort(all(aux)); + best = max(best, count); + for (auto a: aux) + best = max(best, count -= a.snd); + } + return best; +} + +//----------------------------------------------------------------------------- +// area of union of rectangles +// Bentley's sweepline with segment tree. +// +// [accepted, LightOJ 1120 Rectangle Union] +//----------------------------------------------------------------------------- +struct rectangle { point p, q; }; // lower-left and upper-right +real rectangle_union(vector rs) { + vector ys; // plane sweep with coordinate compression + struct event { + real x, ymin, ymax; + int add; + bool operator<(event e) const { return x < e.x; } + }; + vector es; + for (auto r: rs) { + ys.push_back(r.p.y); + ys.push_back(r.q.y); + es.push_back({r.p.x, r.p.y, r.q.y, +1}); + es.push_back({r.q.x, r.p.y, r.q.y, -1}); + } + sort(all(es)); + sort(all(ys)); + ys.erase(unique(all(ys)), ys.end()); + + vector len(4 * ys.size()); // segment tree on sweepline + vector sum(4 * ys.size()); + function update + = [&](real ymin, real ymax, int add, int i, int j, int k) { + ymin = max(ymin, ys[i]); ymax = min(ymax, ys[j]); + if (ymin >= ymax) return; + if (ys[i] == ymin && ys[j] == ymax) sum[k] += add; + else { + update(ymin, ymax, add, i, (i+j)/2, 2*k+1); + update(ymin, ymax, add, (i+j)/2, j, 2*k+2); + } + if (sum[k]) len[k] = ys[j] - ys[i]; + else len[k] = len[2*k+1] + len[2*k+2]; + }; + real area = 0; + for (int i = 0; i+1 < es.size(); ++i) { + update(es[i].ymin, es[i].ymax, es[i].add, 0, ys.size()-1, 0); + area += len[0] * (es[i+1].x - es[i].x); + } + return area; +} + +//----------------------------------------------------------------------------- +// number of points below ps[i]--ps[j] +// +// TODO: めっちゃバグる・バグってるなう +// +// [non-verified] +//----------------------------------------------------------------------------- +struct points_counter { + int n; + vector ps; + vector> low; // low[i][j] is the number of points below (ps[i], ps[j]) + points_counter(vector ps_) : n(ps_.size()), ps(ps_), low(n, vector(n)) { + double sint = 1e-1, cost = sqrt(1 - sint*sint); // perturbation + for (point &p: ps) p = {p.x*cost - p.y*sint, p.x*sint + p.y*cost}; + + vector is(n); iota(all(is), 0); + sort(all(is), [&](int i, int j) { return ps[i] < ps[j]; }); + + vector left; + vector> iss(n); // iss[i] = points smaller than i, sorted by the polar angle + for (int o: is) { + sort(all(left), [&](int j, int k) { // sort in clock-wise order + point u = ps[j] - ps[o], v = ps[k] - ps[o]; + int s = sign(cross(u, v)); + return s ? s < 0 : dot(u,u) > dot(v,v); + }); + iss[o] = left; + left.push_back(o); + } + for (int o: is) { + cout << "processing " << ps[o] << endl; + cout << iss[o].size() << endl; + for (int i = 0; i+1 < iss[o].size(); ++i) { + int a = iss[o][i], b = iss[o][i+1]; + cout << " comparing " << ps[a] << " " << ps[b] << endl; + if (ps[b] < ps[a]) low[b][o] = low[a][o] + low[a][b] + 1; + else low[b][o] = low[a][o] - low[a][b]; + low[o][b] = low[b][o]; + } + } + cout << low << endl; + + + vector> low2(n, vector(n)); + for (int i = 0; i < n; ++i) { + for (int j = i+1; j < n; ++j) { + for (int k = 0; k < n; ++k) { + if (k == i || k == j) continue; + point p = ps[i], q = ps[j], r = ps[k]; + if (q < p) swap(p, q); // assume p < q + if (r.x < p.x || r.x >= q.x) continue; + if (sign(cross(q-r, p-r)) > 0) low2[i][j]++; + } + low2[j][i] = low2[i][j]; + } + } + cout << low2 << endl; + } + int count(int a, int b, int o) { // i -> j -> k ccw order + if (ps[b] < ps[a]) swap(a, b); + if (ps[o] < ps[b]) swap(b, o); + if (ps[b] < ps[a]) swap(a, b); + if (ps[b].y < ps[a].y) swap(a, b); + cout << "comparing " << ps[a] << " " << ps[b] << " " << ps[o] << endl; + cout << "values " << low[o][a] << " " << low[a][b] << " " << low[o][b] << endl; + return low[o][a] + low[a][b] - low[o][b] + (ps[a].x > ps[b].x); + } +}; + + +//----------------------------------------------------------------------------- +// segment arrangement +// +// graph whose vertices are the points and edges are the segments. +// complexity is O(m^2 log m). +// +// [accepted: AOJ 1226] +// [accepted: AOJ 2068] +// [accepted: AOJ 0273] +//----------------------------------------------------------------------------- +namespace arrangement_slow { +struct arrangement { + struct edge { + int src, dst; + real weight; + size_t id, rev; + }; + int n; + vector ps; + map id; + vector> adj; + + arrangement(vector ss) : n(0) { + vector>> group(ss.size()); + auto append = [&](int i, point p) { + if (!id.count(p)) { id[p] = n++; ps.push_back(p); } + group[i].push_back({norm(ss[i].p - p), id[p]}); + }; + for (int i = 0; i < ss.size(); ++i) { + append(i, ss[i].p); append(i, ss[i].q); + for (int j = 0; j < i; ++j) { + for (point p: intersect(ss[i], ss[j])) { + append(i, p); append(j, p); + } + } + } + adj.resize(n); + for (auto &vs: group) { + sort(all(vs)); + for (int i = 0; i+1 < vs.size(); ++i) { + auto u = vs[i].snd, v = vs[i+1].snd; + if (u == v) continue; + auto len = vs[i+1].fst - vs[i].fst; + adj[u].push_back({u, v, len}); + adj[v].push_back({v, u, len}); + } + } + // remove duplicates and orient edges + vector> idx(n); + for (int u = 0; u < n; ++u) { + auto eq = [&](edge e, edge f) { return e.dst == f.dst; }; + auto lt = [&](edge e, edge f) { return e.dst < f.dst; }; + sort(all(adj[u]), lt); + adj[u].erase(unique(all(adj[u]), eq), adj[u].end()); + sort(all(adj[u]), [&](edge e, edge f) { + return arg(ps[e.dst] - ps[e.src]) > arg(ps[f.dst] - ps[f.src]); + }); + for (int i = 0; i < adj[u].size(); ++i) { + adj[u][i].id = i; + int v = adj[u][i].dst; + idx[u][v] = i; + if (idx[v].count(u)) { + int j = idx[v][u]; + adj[u][i].rev = j; + adj[v][j].rev = i; + } + } + } + } + // traverse utilities for DCEL (planar graph) + // traversing edges surrounding the left face + edge twin(edge e) const { return adj[e.dst][e.rev]; } + edge next(edge e) const { + int j = adj[e.dst][e.rev].id + 1; + if (j >= adj[e.dst].size()) j = 0; + return adj[e.dst][j]; + } + edge outer() const { + int s = 0; // leftmost, outerface edge + for (int i = 1; i < n; ++i) if (ps[i] < ps[s]) s = i; + for (int i = 0; i < adj[s].size(); ++i) { + edge e1 = adj[s][i], e2 = adj[s][(i+1)%adj[s].size()]; + if (cross(ps[e1.dst]-ps[s], ps[e2.dst]-ps[s]) <= 0) return e1; + } + } + + // [accepted: AOJ 2068 Hide-and-Seek] + void shortest_path(point sp) { + int s = id[sp]; + vector dist(n, 1.0/0.0); + vector prev(n, -1); + typedef pair node; + priority_queue, greater> Q; + Q.push(node(dist[s] = 0, s)); + while (!Q.empty()) { + node z = Q.top(); Q.pop(); + if (dist[z.snd] <= z.fst) { + for (auto e: adj[z.snd]) { + if (dist[e.dst] > dist[e.src] + e.weight) { + dist[e.dst] = dist[e.src] + e.weight; + prev[e.dst] = e.src; + Q.push({dist[e.dst], e.dst}); + } + } + } + } + real ans = 0; + for (int u = 0; u < n; ++u) { + for (edge e: adj[u]) { + real s = (dist[e.dst] - dist[e.src] + e.weight)/2; + ans = max(ans, dist[e.src] + s); + } + } + printf("%.12lf\n", ans); + } + + // [accepted: AOJ 1226 Fishnet] + template + void traverse(edge e, F func) { + edge s = e; + do { + func(e); + e = next(e); + } while (e.src != s.src || e.dst != s.dst); + } + void traverse_all_faces() { + vector> visited(n); + real ans = 0; + for (int u = 0; u < n; ++u) { + for (edge e: adj[u]) { + if (!visited[e.src].count(e.dst)) { + real area = 0; + traverse(e, [&](edge e) { + visited[e.src].insert(e.dst); + area += cross(ps[e.src], ps[e.dst]); + }); + ans = max(ans, area); + } + } + } + printf("%.6f\n", ans/2); + } + void traverse_all_faces2() { + vector> visited(n); + real ans = 0; + for (int u = 0; u < n; ++u) { + for (edge e: adj[u]) { + if (!visited[e.src].count(e.dst)) { + real area = 0; + traverse(e, [&](edge e) { + visited[e.src].insert(e.dst); + area += cross(ps[e.src], ps[e.dst]); + }); + if (area > 0) ans += area; + } + } + } + printf("%.12f\n", ans/2); + } + edge contains() { + vector> visited(n); + auto contains = [&](edge e, point p) { + edge s = e; + bool in = false; + do { + point a = ps[e.src] - p, b = ps[e.dst] - p; + if (a.y > b.y) swap(a, b); + if (a.y <= 0 && 0 < b.y && cross(a, b) < 0) in = !in; + if (!sign(cross(a, b)) && sign(dot(a, b)) <= 0) + return 1; // point on the edge + visited[e.src].count(e.dst); + e = next(e); + } while (e.src != s.src || e.dst != s.dst); + return in ? 2 : 0; // point in:out the polygon + }; + for (int u = 0; u < n; ++u) + for (edge e: adj[u]) + if (!visited[e.src].count(e.dst)) + if (contains(e, (point){0,0})) return e; + return {-1}; + } +}; + +void AOJ0273() { + for (int c, w; ~scanf("%d %d", &c, &w) && c; ) { + vector ps(c); + for (int i = 0; i < c; ++i) { + scanf("%lf %lf", &ps[i].x, &ps[i].y); + } + vector ss; + for (int i = 0; i < w; ++i) { + int u, v; scanf("%d %d", &u, &v); + ss.push_back({ps[u-1], ps[v-1]}); + } + arrangement arr(ss); + typedef arrangement::edge edge; + edge e = arr.outer(); // outer-face edge + + vector> step(arr.n); + queue que; + auto proceed = [&](edge s, int value) { + if (step[s.src].count(s.dst)) return; + edge e = s; + do { + step[e.src][e.dst] = value; + que.push(arr.twin(e)); + e = arr.next(e); + } while (e.src != s.src || e.dst != s.dst); + }; + proceed(e, 0); + int ans = 0; + while (!que.empty()) { + edge e = que.front(); que.pop(); + ans = step[e.dst][e.src]; + proceed(e, ans + 1); + } + printf("%d\n", ans); + } +} + + + +void AOJ1226() { + for (int n; ~scanf("%d", &n) && n; ) { + vector> a(4, vector(n)); + for (int k = 0; k < 4; ++k) + for (int i = 0; i < n; ++i) + scanf("%lf", &a[k][i]); + + vector ss = { + {{0,0},{0,1}}, + {{0,1},{1,1}}, + {{1,1},{1,0}}, + {{1,0},{0,0}} + }; + for (int i = 0; i < n; ++i) { + ss.push_back({{a[0][i],0},{a[1][i],1}}); + ss.push_back({{0,a[2][i]},{1,a[3][i]}}); + } + arrangement arr(ss); + arr.traverse_all_faces(); + } +} + +void AOJ2448() { + int n; scanf("%d", &n); + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + vector ss; + for (int i = 0; i+1 < n; ++i) + ss.push_back({ps[i], ps[i+1]}); + arrangement arr(ss); + arr.traverse_all_faces2(); +} + +void AOJ1247() { + for (int n; ~scanf("%d", &n) && n; ) { + vector ss; + for (int i = 0; i < n; ++i) { + double x1, y1, x2, y2; + scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2); + ss.push_back({{x1,y1},{x2,y2}}); + } + arrangement arr(ss); + if (arr.contains().src >= 0) printf("yes\n"); + else printf("no\n"); + } +} +} +// --------------------------------------------------------------------------- +// segment arrangement (Bentley-Ottman's plane sweep) +// +// graph whose vertices are the points and edges are the segments. +// complexity is O((n + k) log n); where k is the number of intersections. +// +// Verified: AOJ1226, AOJ2448 +// --------------------------------------------------------------------------- +struct arrangement { + struct Vertex; struct Edge; // Doubly Connected Edge List + struct Vertex { + point p; // + Edge *edge; // any edge incident to this vertex + }; + struct Edge { + Vertex *vertex; // origin vertex of the edge + Edge *twin; // reverse edge of e + Edge *prev, *next; // surrounding edges of face (CCW) + }; + map> adj; + vector vertices; + vector edges; + + vector segs; + + struct node { // Sweep-Line Structure (RBST) + int index; + int size = 1; + node *left = 0, *right = 0; + } *root = 0; + vector ns; + + node *update(node *x) { + if (x) { + x->size = 1; + if (x->left) x->size += x->left->size; + if (x->right) x->size += x->right->size; + } + return x; + } + node *merge(node *x, node *y) { + if (!x) return y; + if (!y) return x; + if (rand() % (x->size + y->size) < x->size) { + x->right = merge(x->right, y); + return update(x); + } else { + y->left = merge(x, y->left); + return update(y); + } + } + template // 3-way split: cond(x) < 0, cond(x) == 0, cond(x) > 0 + tuple split(node *x, C cond) { + if (!x) return make_tuple(x,x,x); + if (cond(x) == 0) { + auto a = split(x->left, cond); + auto b = split(x->right, cond); + x->left = x->right = 0; update(x); + get<1>(a) = merge(merge(get<1>(a), x), get<1>(b)); + get<2>(a) = get<2>(b); + return a; + } + if (cond(x) < 0) { + auto a = split(x->right, cond); + x->right = 0; update(x); + get<0>(a) = merge(x, get<0>(a)); + return a; + } + if (cond(x) > 0) { + auto a = split(x->left, cond); + x->left = 0; update(x); + get<2>(a) = merge(get<2>(a), x); + return a; + } + } + node *leftmost(node *x) { while (x && x->left) x = x->left; return x; } + node *rightmost(node *x) { while (x && x->right) x = x->right; return x; } + template + void process(node *x, F func) { + if (!x) return; + process(x->left, func); + func(x); + process(x->right, func); + } + + arrangement(vector segs_) : segs(segs_) { + ns.resize(segs.size()); + + set events; + map> L, R; + for (int i = 0; i < segs.size(); ++i) { + if (segs[i].q < segs[i].p) swap(segs[i].p, segs[i].q); + events.insert(segs[i].p); + events.insert(segs[i].q); + L[segs[i].p].insert(i); + R[segs[i].q].insert(i); + ns[i].index = i; + } + vector last(segs.size()); + + while (!events.empty()) { + const point p = *events.begin(); + events.erase(events.begin()); + + Vertex *u = new Vertex({p}); + vertices.push_back(u); + + auto cond = [&](node *x) { + const segment &s = segs[x->index]; + if (sign(s.q.x - s.p.x) == 0) { + if (sign(p.y - s.p.y) < 0) return -1; + if (sign(s.q.y - p.y) < 0) return +1; + return 0; + } + return -sign(cross(s.p - p, s.q - p)); + }; + auto z = split(root, cond); + vector inserter; + process(get<1>(z), [&](node *x) { + Vertex *v = last[x->index]; + if (!adj[u][v]) { + adj[u][v] = new Edge({u}); + adj[v][u] = new Edge({v}); + adj[u][v]->twin = adj[v][u]; + adj[v][u]->twin = adj[u][v]; + edges.push_back(adj[u][v]); + edges.push_back(adj[v][u]); + } + if (!R[p].count(x->index)) + inserter.push_back(x); + }); + for (int i: L[p]) + if (!R[p].count(i)) + inserter.push_back(&ns[i]); + + sort(all(inserter), [&](node *x, node *y) { + const segment &s = segs[x->index], &t = segs[y->index]; + return sign(cross(s.q - s.p, t.q - t.p)) >= 0; + }); + auto add_event = [&](node *x, node *y) { + if (!x || !y) return; + vector ps = intersect(segs[x->index], segs[y->index]); + for (point q: ps) + if (p < q) events.insert(q); + }; + if (inserter.empty()) { + add_event(rightmost(get<0>(z)), leftmost(get<2>(z))); + } else { + add_event(rightmost(get<0>(z)), inserter[0]); + add_event(leftmost(get<2>(z)), inserter.back()); + } + root = 0; + for (int i = 0; i < inserter.size(); ++i) { + last[inserter[i]->index] = u; + inserter[i]->left = inserter[i]->right = 0; + root = merge(root, update(inserter[i])); + } + root = merge(merge(get<0>(z), root), get<2>(z)); + } + for (auto &pp: adj) { + Vertex *u = pp.fst; + vector es; + for (auto z: pp.snd) es.push_back(z.snd); + sort(all(es), [&](Edge *e, Edge *f) { + auto quad = [](point p) { + for (int i = 1; i <= 4; ++i, swap(p.x = -p.x, p.y)) + if (p.x > 0 && p.y >= 0) return i; + return 0; + }; + const point p = e->twin->vertex->p - e->vertex->p; + const point q = f->twin->vertex->p - f->vertex->p; + if (quad(p) != quad(q)) return quad(p) < quad(q); + return sign(cross(p, q)) > 0; + }); + u->edge = es.back(); + for (Edge *e: es) { + u->edge->next = e; + u->edge->next->prev = u->edge; + u->edge = u->edge->next; + } + } + } +}; +void AOJ1226() { + for (int n; ~scanf("%d", &n) && n; ) { + //cout << n << endl; + vector> a(4, vector(n)); + for (int k = 0; k < 4; ++k) + for (int i = 0; i < n; ++i) + scanf("%lf", &a[k][i]); + + vector ss = { + {{0,0},{0,1}}, + {{0,1},{1,1}}, + {{1,1},{1,0}}, + {{1,0},{0,0}} + }; + for (int i = 0; i < n; ++i) { + ss.push_back({{a[0][i],0},{a[1][i],1}}); + ss.push_back({{0,a[2][i]},{1,a[3][i]}}); + } + arrangement arr(ss); + + double result = 0; + set seen; + for (auto *e: arr.edges) { + if (seen.count(e)) continue; + auto *f = e; + double area = 0; + do { + seen.insert(f); + area += cross(f->vertex->p, f->twin->vertex->p); + f = f->twin->prev; + } while (f != e); + result = max(result, area); + } + printf("%.6f\n", result/2); + } +} +void AOJ2448() { + int n; scanf("%d", &n); + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + vector ss; + for (int i = 0; i+1 < n; ++i) + ss.push_back({ps[i], ps[i+1]}); + arrangement arr(ss); + + double result = 0; + set seen; + for (auto *e: arr.edges) { + if (seen.count(e)) continue; + auto *f = e; + double area = 0; + do { + seen.insert(f); + area += cross(f->vertex->p, f->twin->vertex->p); + f = f->twin->prev; + } while (f != e); + if (area > 0) result += area; + } + printf("%.12f\n", result/2); +} + + +//----------------------------------------------------------------------------- +// visibility graph in O(|points|^2 |obstacles|) +// +// Here, the visibility of p and q is: +// 1. p, q in [a,b] ==> visible +// 2. a in (p,q) ==> invisible +// 3. (p,q) intersects (a,b) ==> invisible +// 4. m=(p+q)/2 in int(obs) ==> invisible +// +// [non-verified]; +//----------------------------------------------------------------------------- +struct visibility_graph { + struct edge { + int src, dst; + real weight; + }; + int n; + vector ps; + vector> adj; + visibility_graph(vector ps, vector os) : + n(ps.size()), ps(ps), adj(n) { + auto blocked = [&](point s, point t, polygon &obs) { + bool in = false, on = false; + point m = (s + t) / 2; + for (int i = 0; i < obs.size(); ++i) { + int j = (i+1 == obs.size() ? 0 : i+1); + point a = obs[i], b = obs[j]; + if (!sign(cross(a-s,b-s)) && sign(dot(a-s,b-s)) <= 0 && // s is on [a,b] and t is on [a,b] + !sign(cross(a-t,b-t)) && sign(dot(a-t,b-t)) <= 0) return false; + if (!sign(cross(s-a,t-a)) && sign(dot(s-a,t-a)) < 0) return false; // (s,t) contains a + if (sign(cross(a-s,b-s))*sign(cross(a-t,b-t)) < 0 && // (s,t) intersects (a,b) + sign(cross(s-a,t-a))*sign(cross(s-b,t-b)) < 0) return true; + if (b.y < a.y) swap(a, b); // a is lower + if (a.y <= m.y && m.y < b.y) + if (sign(cross(a-m, b-m)) < 0) in = !in; + } + return in; // midpoint is on obs + }; + for (int i = 0; i < ps.size(); ++i) { + for (int j = i+1, k; j < ps.size(); ++j) { + for (k = 0; k < os.size(); ++k) + if (blocked(ps[i], ps[j], os[k])) break; + if (k == os.size()) { + auto len = norm(ps[i] - ps[j]); + adj[i].push_back({i, j, len}); + adj[j].push_back({j, i, len}); + } + } + } + } +}; +// +// weighted geometric shortest path +// +// find a shortest path on 2D plane, +// where each obstacle is assigned a weight (inverse velocity). +// if weight = INF, it reduced to the standard geometric shortest path problem. +// +// basic algorithm: A* search on implicit visibility graph. +// It performs O(n^2) A* search with dist(u,t) as a heuristics. +// +// on a weighted problem, divide edges to approximate solutions. +// +// reference: +// L. Aleksandrov, A. Maheshwari, and J. -R. Sack (1998): +// Determining approximate shortest paths on weighted polyhedral surfaces. +// +// see aso: http://arxiv.org/pdf/0904.2550.pdf +// +struct geometric_shortest_path { + vector ps; + vector prev, next; + vector> region; + vector weight; + void add_region(vector poly, real w = 1.0/0.0) { + int n = ps.size(), k = poly.size(); + vector obj; + for (int i = 0; i < k; ++i) { + ps.push_back(poly[i]); + obj.push_back(n+i); + next.push_back(n+i+1); + prev.push_back(n+i-1); + } + next[n+k-1] = n; + prev[n] = n+k-1; + region.push_back(obj); + weight.push_back(w); + } + void refine(int v) { + auto divide = [&](int u, int w) { + int v = ps.size(); + ps.push_back((ps[u] + ps[w])/2); + prev.push_back(u); + next.push_back(w); + prev[next[v]] = v; + next[prev[v]] = v; + }; + divide(prev[v], v); + divide(v, next[v]); + } + enum { INTERSECT, CONTAINED, ONLINE, VISIBLE }; + int visibility(point s, point t, vector ®) { + bool in = false; + point m = (s + t) / 2; + for (int i = 0; i < reg.size(); ++i) { + point a = ps[reg[i]], b = ps[reg[(i+1)%reg.size()]]; + if (!sign(cross(a-s,b-s)) && sign(dot(a-s,b-s)) <= 0 && // s is on [a,b] and t is on [a,b] + !sign(cross(a-t,b-t)) && sign(dot(a-t,b-t)) <= 0) return ONLINE; + if (sign(cross(a-s,b-s))*sign(cross(a-t,b-t)) < 0 && // (s,t) intersects (a,b) + sign(cross(s-a,t-a))*sign(cross(s-b,t-b)) < 0) return INTERSECT; + if (b.y < a.y) swap(a, b); + if (a.y <= m.y && m.y < b.y && sign(cross(a-m, b-m)) < 0) in = !in; + } + return in ? CONTAINED : VISIBLE; + } + real length(int u, int v) { + point s = ps[u], t = ps[v]; + auto len = norm(s - t); + for (int i = 0; i < region.size(); ++i) { + int a = visibility(s, t, region[i]); + if (a == ONLINE) return len; + if (a == CONTAINED) return weight[i] * len; + if (a == INTERSECT) return 1.0 / 0.0; + } + return len; + } + pair> shortest_path(point p, point q) { + ps.push_back(p); ps.push_back(q); + int n = ps.size(), s = n-2, t = n-1; + vector dist(n, 1.0/0.0), h(n); dist[s] = 0; + for (int u = 0; u < n; ++u) h[u] = norm(ps[u]-ps[t]); // modify here if weight < 1.0 + vector last(n, ~s); // negative -> unfixed + while (last[t] < 0) { + int u = t; + for (int v = 0; v < n; ++v) + if (last[v] < 0 && dist[v] + h[v] < dist[u] + h[u]) u = v; + last[u] = ~last[u]; + for (int v = 0; v < n; ++v) { + if (last[v] >= 0) continue; + auto len = dist[u] + length(u, v); + if (sign(dist[v] - len) > 0) { + dist[v] = len; + last[v] = ~u; + } + } + } + auto cost = dist[t]; + vector path; + if (cost < 1.0 / 0.0) { + while (t != s) { + path.push_back(t); + t = last[t]; + } + path.push_back(s); + } + ps.pop_back(); ps.pop_back(); + return {cost, path}; + } +}; + +//----------------------------------------------------------------------------- +// merge segments in O(n log n) +// [non-verified] +//----------------------------------------------------------------------------- +vector merge_segments(vector ss) { + auto compare = [&](segment s, segment t) { + int a = sign(cross(s.q-s.p, t.p-t.q)); + return a ? a < 0 : sign(cross(t.p-s.p, t.q-s.p)) < 0; + }; + for (segment &s: ss) if (s.q < s.p) swap(s.p, s.q); + sort(all(ss), compare); + vector res; + for (int i = 0, j; i < ss.size(); i = j) { + for (j = i+1; j < ss.size(); ++j) + if (compare(ss[i], ss[j])) break; + point o = ss[i].p, v = ss[i].q - ss[i].p; + sort(ss.begin()+i, ss.begin()+j, [&](segment s, segment &t) { + auto a = dot(s.p - t.p, v); + if (a) return a < 0; + return dot(s.q - t.q, v) < 0; + }); + for (int a = i, b; a < j; a = b) { + for (b = a+1; b < j; ++b) { + if (sign(dot(ss[a].q - ss[b].p, v)) < 0) break; + if (dot(ss[a].q - ss[b].q, v) < 0) ss[a].q = ss[b].q; + } + res.push_back(ss[a]); + } + } + return res; +} + +//----------------------------------------------------------------------------- +// relative neighborhood graph +// there is an edge between p and q iff +// d(p,q) < d(p,r), and d(p,q) < d(q,r) +// for all other point r. +// +// it contains euclidean mst. +// +// O(n^2) by Katajainen and Nevalainen +// +// [non-verified] +//----------------------------------------------------------------------------- +struct relative_neighborhood_graph { + struct edge { + int src, dst; + real len; + }; + int n; + vector ps; + vector> adj; + relative_neighborhood_graph(vector ps) : + n(ps.size()), ps(ps), adj(n) { + + auto quadrant = [&](point p) { + for (int i = 0; i < 8; ++i) { + if (p.x >= 0 && p.y >= 0 && p.y < p.x) return i; + p = (point){p.x + p.y, -p.x + p.y}; + } + return -1; + }; + for (int i = 0; i < n; ++i) { + vector> cand(8); + vector dist(8, 1.0/0.0); + for (int j = 0; j < n; ++j) { + if (i == j) continue; + int k = quadrant(ps[j] - ps[i]); + real d = norm2(ps[j] - ps[i]); + if (sign(d - dist[k]) < 0) cand[k] = {j}, dist[k] = d; + else if (sign(d - dist[k]) == 0) cand[k].push_back(j); + } + for (int k = 0, l; k < 8; ++k) { + //cout << dist[k] << endl; + for (int j: cand[k]) { + if (j >= i) continue; + for (l = 0; l < n; ++l) { + if (l == i || l == j) continue; + if (sign(dist[k] - norm2(ps[l] - ps[i])) > 0) break; + } + if (l == n) { + adj[i].push_back({i, j, sqrt(dist[k])}); + adj[j].push_back({j, i, sqrt(dist[k])}); + } + } + } + } + } +}; + + +// --------------------------------------------------------------------------- +// maximum area of empty convex k-gon +// +// David P. Dovkin, Harbert Edelsbrunner, and Mark H. Overmars (1990): +// Searching for Empty Convex Polygons. +// Algorithmica, vol.5, no.1, pp.561--571. +// +// Complexity: O(n^3) +// +// [non-verified] +// --------------------------------------------------------------------------- +real maximum_area_empty_convex_polygon(vector ps) { + int n = ps.size(); + real ans = 0; + for (int o = 0; o < n; ++o) { + vector vs; + for (point p: ps) + if (p < ps[o]) vs.push_back(p - ps[o]); + int m = vs.size(); + sort(all(vs), [&](point p, point q) { + int s = sign(cross(p, q)); + return s ? s > 0 : sign(dot(q,q) - dot(p,p)) > 0; + }); + vector> dp(m, vector(m)); + for (int k = 1; k < m; ++k) { + int i = k-1; + while (i >= 0 && !sign(cross(vs[i], vs[k]))) --i; + vector seq; + for (int j; i > 0; i = j) { + seq.push_back(i); + for (j = i-1; j > 0 && sign(cross(vs[i]-vs[k], vs[j]-vs[k])) > 0; --j); + auto v = cross(vs[i], vs[k]); + if (j >= 0) v += dp[i][j]; + dp[k][i] = v; + ans = max(ans, v); + } + for (int i = (int)seq.size()-2; i >= 0; --i) + dp[k][seq[i]] = max(dp[k][seq[i]], dp[k][seq[i+1]]); + } + } + return ans; +} + +//----------------------------------------------------------------------------- +// delaunay triangulation +// O(n^2) in the worst case, O(n log n) -- O(n sqrt(n)) in pratice. +// +// [verified: RUPC 2013 F] +//----------------------------------------------------------------------------- +struct delaunay { + struct edge { + int src, dst; + }; + int n; + vector ps; + vector> adj; // optional + vector inner; + int incircle(int a, int b, int c, int p) { + point u = ps[a]-ps[p], v = ps[b]-ps[p], w = ps[c]-ps[p]; + return sign(norm2(u)*cross(v,w) + +norm2(v)*cross(w,u) + +norm2(w)*cross(u,v)) > 0; + } + bool orient(int a, int b, int p) { + point u = ps[a]-ps[b], v = ps[p]-ps[b]; + int s = sign(cross(u, v)); + return s ? s > 0 : sign(dot(u, v)) > 0; + } + delaunay(vector ps) : n(ps.size()), ps(ps), adj(n), inner(n) { + if (n <= 1) return; + vector> ccw(n); // ccw[u][v] is the third pt for (u,v) + auto make_triangle = [&](int a, int b, int c) { + ccw[a][b] = c; ccw[b][c] = a; ccw[c][a] = b; + }; + vector is(n); iota(all(is), 0); + sort(all(is), [&](int i, int j) { return ps[i] < ps[j]; }); + // delaunay flips + function rec = [&](int a, int b) { + if (!ccw[a].count(b) || !ccw[b].count(a)) return; + int c = ccw[a][b], d = ccw[b][a]; + if (incircle(a, b, c, d) > 0) { + ccw[a].erase(b); ccw[b].erase(a); + make_triangle(d, c, a); + make_triangle(c, d, b); + rec(a, d); rec(d, b); rec(b, c); rec(c, a); + } + }; + // lexicographic triangulation + vector next(n,-1), prev(n,-1); + next[is[0]] = prev[is[0]] = is[1]; + next[is[1]] = prev[is[1]] = is[0]; + for (int i = 2; i < n; ++i) { + int h = is[i], u = is[i-1], v = u; + while ( orient(u, next[u], h)) u = next[u]; + while (!orient(v, prev[v], h)) v = prev[v]; + for (int w = v; w != u; w = next[w]) + if (sign(cross(ps[next[w]]-ps[h], ps[w]-ps[h])) > 0) + make_triangle(w, h, next[w]); + next[h] = u; prev[u] = h; + prev[h] = v; next[v] = h; + } + for (int u: is) { + auto nbh = ccw[u]; // hardcopy + for (auto z: nbh) rec(z.fst, z.snd); // flip + } + // complete graph structure + for (int u: is) { + int v = ccw[u].begin()->fst, s = v; + while (ccw[s].count(u)) { + s = ccw[s][u]; + if (s == v) break; + } // v != s means that u is on the outer face + if (v != s) { inner[u] = false; v = s; } + do { + adj[u].push_back({u, v}); + if (!ccw[u].count(v)) break; + v = ccw[u][v]; + } while (v != s); + } + } +}; +//----------------------------------------------------------------------------- +// voronoi diagram (from delaunay triangulation) +// O(sum deg^2) = O(n^2) in worst case, O(n) for random input. +// +// [verified: RUPC 2013 F] +//----------------------------------------------------------------------------- +struct voronoi { + struct edge { + int src, dst; + real len; + }; + int n, m; + vector ps, qs; // qs is the voronoi vertices + map id; + vector> cell; + vector> adj; + void add_edge(int u, int v) { + auto len = norm(qs[u] - qs[v]); + adj[u].push_back({u, v, len}); + adj[v].push_back({v, u, len}); + } + int node(point p) { + if (!id.count(p)) { id[p] = m++; qs.push_back(p); adj.push_back({}); } + return id[p]; + } + voronoi(delaunay DT, vector domain) : + n(DT.n), m(0), ps(DT.ps), cell(n) { + for (int u = 0; u < n; ++u) { + vector region = domain; + for (auto e: DT.adj[u]) { + point s = (ps[e.src]+ps[e.dst])/2, d = orth(ps[e.dst]-ps[e.src]); + region = convex_cut(region, {s, s+d}); + } + for (int i = 0; i < region.size(); ++i) { + add_edge(node(region[i]), node(region[(i+1)%region.size()])); + cell[u].push_back(node(region[i])); + } + } + } + voronoi(vector ps, vector domain) : + voronoi(delaunay(ps), domain) { } +}; + +/* +DCEL にしたい + +struct Delaunay { + struct Vertex; struct Edge; + struct Vertex { + point p; + Edge *edge; // any adjacent edge + }; + struct Edge { + Vertex *vertex; // origin + Edge *twin; + Edge *prev, *next; + }; + int incircle(Vertex *a, Vertex *b, Vertex *c, Vertex *p) { + point u = a->p - p->p, v = b->p - p->p, w = c->p - p->p; + return sign(norm2(u)*cross(v,w) + +norm2(v)*cross(w,u) + +norm2(w)*cross(u,v)) > 0; + } + bool orient(Vertex *a, Vertex *b, Vertex *p) { + point u = a->p - b->p, v = p->p - b->p; + int s = sign(cross(u, v)); + return s ? s > 0 : sign(dot(u, v)) > 0; + } + Delaunay(vector ps) { + + } + z d w d + / \ / | \ + 枝 a -e-> b ==> a | b + \ / \ v / + y c x c + + を逆転させる手続き + if incircle: + r = e->twin + x = e->next y = e->prev + z = r->next w = r->prev + x->vertex->edge = x + z->vertex->edge = z + w->next = x x->next = r r->next = w + w->prev = r x->prev = w r->prev = x + y->next = z z->next = e e->next = y + y->prev = e z->prev = y e->prev = z + e->vertex = w->vertex + r->vertex = y->vertex + rec(x); rec(y); rec(z); rec(w); + + Vertex *u :: rightmost + Edge *e = u->edge + while orient: e = e->prev + + span(e->next) + e->twin->next で CH を traverse できる + + while !orient: + r = new Edge, s = new Edge, t = new Edge + r->next = s s->next = t t->next = r + r->prev = b + + + + p ---- v + \ / + q / + + auto make_triangle = [&](int a, int b, int c) { + ccw[a][b] = c; ccw[b][c] = a; ccw[c][a] = b; + }; + vector is(n); iota(all(is), 0); + sort(all(is), [&](int i, int j) { return ps[i] < ps[j]; }); + // delaunay flips + function rec = [&](int a, int b) { + if (!ccw[a].count(b) || !ccw[b].count(a)) return; + int c = ccw[a][b], d = ccw[b][a]; + if (incircle(a, b, c, d) > 0) { + ccw[a].erase(b); ccw[b].erase(a); + make_triangle(d, c, a); + make_triangle(c, d, b); + rec(a, d); rec(d, b); rec(b, c); rec(c, a); + } + }; + +}; +*/ + + +//----------------------------------------------------------------------------- +// [non-verified] +//----------------------------------------------------------------------------- +bool is_congruence(polygon ps, polygon qs) { + if (ps.size() != qs.size()) return false; + int n = ps.size(); + vector as, bs; + for (int i = 0; i < n; ++i) { + int j = (i+1 < n ? i+1 : 0), k = (j+1 < n ? j+1 : 0); + as.push_back({dot(ps[i]-ps[j], ps[k]-ps[j]), + cross(ps[i]-ps[j], ps[k]-ps[j])}); + bs.push_back({dot(qs[i]-qs[j], qs[k]-qs[j]), + cross(qs[i]-qs[j], qs[k]-qs[j])}); + } + vector fail(n+1, -1); // knuth morris pratt + for (int i = 1, j = -1; i <= n; ++i) { + while (j >= 0 && !(as[j] == as[i-1])) j = fail[j]; + fail[i] = ++j; + } + for (int i = 0, k = 0; i < 2*n; ++i) { + while (k >= 0 && !(bs[i%n] == as[k])) k = fail[k]; + if (++k == n) return true; // ps[0,n) == qs[i-n+1, *) + } + return false; +} +//----------------------------------------------------------------------------- +// [non-verified] +//----------------------------------------------------------------------------- +bool is_similar(polygon ps, polygon qs) { + if (ps.size() != qs.size()) return false; + int n = ps.size(); + vector as, bs; + for (int i = 0; i < n; ++i) { + int j = (i+1 < n ? i+1 : 0), k = (j+1 < n ? j+1 : 0); + as.push_back({dot(ps[i]-ps[j], ps[k]-ps[j]), + cross(ps[i]-ps[j], ps[k]-ps[j])}); + bs.push_back({dot(qs[i]-qs[j], qs[k]-qs[j]), + cross(qs[i]-qs[j], qs[k]-qs[j])}); + } + real maxa = as[0].x, maxb = bs[0].y; + for (int i = 1; i < n; ++i) + maxa = max(maxa, as[i].x), maxb = max(maxb, bs[i].x); + vector fail(n+1, -1); // knuth morris pratt + for (int i = 1, j = -1; i <= n; ++i) { + while (j >= 0 && !(as[j] == as[i-1])) j = fail[j]; + fail[i] = ++j; + } + for (int i = 0, k = 0; i < 2*n; ++i) { + while (k >= 0 && !(maxa*bs[i%n] == maxb*as[k])) k = fail[k]; + if (++k == n) return true; // maxb * ps[0,n) == maxa * qs[i-n+1, *) + } + return false; +} +//----------------------------------------------------------------------------- +// [non-verified] +//----------------------------------------------------------------------------- +polygon simplify(polygon ps) { + int n = ps.size(); + polygon qs; + for (int i = 0; i < n; ++i) { + int j = (i+1 < n ? i+1 : 0), k = (j+1 < n ? j+1 : 0); + if (sign(dot(ps[j]-ps[i], ps[k]-ps[i])) < 0 || + sign(cross(ps[j]-ps[i], ps[k]-ps[i]))) + qs.push_back(ps[j]); + } + return qs; +} + + +//----------------------------------------------------------------------------- +// VP tree (metric tree) +// +// [non-verified] +//----------------------------------------------------------------------------- +struct vantage_point_tree { + int n; + vector ps; + vector> aux; + vantage_point_tree(vector ps) : n(ps.size()), ps(ps), aux(n) { + for (int i = 0; i < n; ++i) aux[i].snd = i; + function rec = [&](int l, int r) { + if (l == r) return; + swap(aux[l], aux[l+rand()%(r-l)]); + for (int i = l+1; i < r; ++i) + aux[i].fst = norm(ps[aux[i].snd] - ps[aux[l].snd]); + int m = (l+1 + r) / 2; + nth_element(aux.begin()+l+1, aux.begin()+m, aux.begin()+r); + aux[l].fst = aux[m].fst; + rec(l+1, m); rec(m, r); + }; + rec(0, n); + } + vector closest(point p, int k = 1) { + priority_queue> topk; + function rec = [&](int l, int r) { + int m = (l+1 + r) / 2; + if (l == r) return; + auto d = norm(p - ps[aux[l].snd]); + if (topk.size() < k) topk.push({d, aux[l].snd}); + else if (topk.top().fst > d) { + topk.pop(); + topk.push({d, aux[l].snd}); + } + if (d <= aux[l].fst) { + rec(l+1, m); + if (aux[l].fst - d < topk.top().fst) rec(m, r); + } else { + rec(m, r); + if (d - aux[l].fst < topk.top().fst) rec(l+1, m); + } + }; + rec(0, n); + vector ans; + for (; !topk.empty(); topk.pop()) ans.push_back(topk.top().snd); + reverse(all(ans)); + return ans; + } +}; + +//----------------------------------------------------------------------------- +// random ball over +// O(n f(n)) construction, O(n/f(n)) query +// If there are T queries, set f(n) = O(sqrt(T)). +// +// [non-verified] +//----------------------------------------------------------------------------- +struct random_ball_cover { + int n, m; + vector ps, cs; + vector>> vs; + random_ball_cover(vector ps) : n(ps.size()), ps(ps), cs(ps) { + for (int k = m = 1; m < n && k < n; k *= 2, ++m); // m = O(log(n)) + cs.resize(m); vs.resize(m); + for (int u = 0; u < n; ++u) { + int j = 0; + real best = norm(cs[j] - ps[u]); + for (int k = 1; k < m; ++k) { + real len = norm(cs[k] - ps[u]); + if (best > len) { best = len; j = k; } + } + vs[j].push_back({best, u}); + } + for (int j = 0; j < m; ++j) { + sort(all(vs[j])); reverse(all(vs[j])); + } + } + vector closest(point p, int k = 1) { + vector> order(m); + for (int j = 0; j < m; ++j) + order[j] = {norm(cs[j] - p), j}; + sort(all(order)); + priority_queue> topk; + for (auto ord: order) { + real rad = ord.fst; + for (auto z: vs[ord.snd]) { + if (topk.size() < k || topk.top().fst > ord.fst - z.fst) { + topk.push({norm(ps[z.snd] - p), z.snd}); + if (topk.size() > k) topk.pop(); + } else break; + } + } + vector ans; + for (; !topk.empty(); topk.pop()) ans.push_back(topk.top().snd); + reverse(all(ans)); + return ans; + } +}; + + +//----------------------------------------------------------------------------- +// Dynamic Convex Hull (Overmars-Leeuwen) +// +// Memoise divide-and-conquer procedure in segment tree. +// Each tree nodes stores convex hulls by binary search tree. +// +// [verified] CODECHEF MGCHGEOM, ACM/ICPC 2017-D +//----------------------------------------------------------------------------- + +template +struct half_hull { + struct node { + point p; + node *child[2], *parent; + node *next[2]; + + real area; + double perimeter; + }; + node *update(node *t) { + if (t) { + t->area = 0; + if (t->child[0]) t->area += t->child[0]->area + cross(t->p, t->next[0]->p); + if (t->child[1]) t->area += t->child[1]->area - cross(t->p, t->next[1]->p); + + t->perimeter = 0; + if (t->child[0]) t->perimeter += t->child[0]->perimeter + norm(t->p - t->next[0]->p); + if (t->child[1]) t->perimeter += t->child[1]->perimeter + norm(t->p - t->next[1]->p); + } + return t; + } + int dir(node *x, node *y) { return x && x->child[0] == y ? 0 : 1; } + void link(node *x, node *y, int d) { + if (x) x->child[d] = y; + if (y) y->parent = x; + } + void rot(node *x, int d) { + node *y = x->child[d], *z = x->parent; + link(x, y->child[!d], d); + link(y, x, !d); + link(z, y, dir(z, x)); + update(x); update(y); + } + void splay(node *x) { + if (!x) return; + while (x->parent) { + node *y = x->parent, *z = y->parent; + int dy = dir(y, x), dz = dir(z, y); + if (!z) { rot(y, dy); } + else if (dy == dz) { rot(z, dz), rot(y, dy); } + else { rot(y, dy), rot(z, dz); } + } + } + int n; + vector vs; + vector ch, sh; + vector ps; + half_hull(vector ps_) : ps(ps_) { + sort(all(ps)); + ps.erase(unique(all(ps)), ps.end()); + n = ps.size(); + vs.resize(n); + for (int i = 0; i < n; ++i) vs[i] = {ps[i]}; + ch.resize(4*n); sh.resize(4*n); + } + pair bridge(node *lch, node *rch) { + if (lch && rch) { + while (1) { + int it = 0; + for (splay(rch); ; ++it) { + if (rch->next[0] && turn*sign(cross(rch->next[0]->p - lch->p, rch->p - lch->p)) <= 0) { + rch = rch->child[0]; + } else if (rch->next[1] && turn*sign(cross(rch->p - lch->p, rch->next[1]->p - lch->p)) > 0) { + rch = rch->child[1]; + } else break; + } + for (splay(lch); ; ++it) { + if (lch->next[1] && turn*sign(cross(lch->p - rch->p, lch->next[1]->p - rch->p)) <= 0) { + lch = lch->child[1]; + } else if (lch->next[0] && turn*sign(cross(lch->next[0]->p - rch->p, lch->p - rch->p)) > 0) { + lch = lch->child[0]; + } else break; + } + if (it == 0) break; + } + } else if (lch) { + for (splay(lch); lch->child[1]; lch = lch->child[1]); + } else if (rch) { + for (splay(rch); rch->child[0]; rch = rch->child[0]); + } + return {lch, rch}; + } + node *apart(node *x, int d) { + if (!x) return 0; + node *y = x->child[d]; + if (!y) return 0; + y->parent = x->child[d] = 0; + for (; y->child[!d]; y = y->child[!d]); + splay(y); + x->next[d] = y->next[!d] = 0; + update(x); + return y; + } + node *join(node *x, node *y) { + if (!x) return y; + if (!y) return x; + x->child[1] = x->next[1] = y; + y->parent = y->next[0] = x; + update(x); + return x; + } + template + void build(int l, int r, int k, int i) { + if (l+1 == r) { ch[k] = I ? &vs[i] : 0; return; } + splay(ch[2*k+1]); + apart(ch[2*k+1], 1); + ch[2*k+1] = join(ch[2*k+1], sh[2*k+1]); + splay(ch[2*k+2]); + ch[2*k+2] = join(sh[2*k+2], ch[2*k+2]); + if (i < (l+r)/2) build(l, (l+r)/2, 2*k+1, i); + else build((l+r)/2, r, 2*k+2, i); + tie(ch[2*k+1], ch[2*k+2]) = bridge(ch[2*k+1], ch[2*k+2]); + splay(ch[2*k+1]); + splay(ch[2*k+2]); + sh[2*k+1] = apart(ch[2*k+1], 1); + sh[2*k+2] = apart(ch[2*k+2], 0); + ch[k] = join(ch[2*k+1], ch[2*k+2]); + } + int index(point p) const { return lower_bound(all(ps), p) - ps.begin(); } + void insert(point p) { build<1>(0, n, 0, index(p)); } + void erase(point p) { build<0>(0, n, 0, index(p)); } + + node *find(point p) { + node *t = ch[0]; + while (t && t->p != p) + t = t->child[t->p < p]; + return t; + } +}; +struct dynamic_convex_hull { + half_hull<+1> upper; + half_hull<-1> lower; + + dynamic_convex_hull(vector ps) : upper(ps), lower(ps) { } + void insert(point p) { upper.insert(p); lower.insert(p); } + void erase(point p) { upper.erase(p); lower.erase(p); } + + real area() { + real area = 0; + if (upper.ch[0]) area += upper.ch[0]->area; + if (lower.ch[0]) area -= lower.ch[0]->area; + return area; + } + double perimeter() { + double perimeter = 0; + if (upper.ch[0]) perimeter += upper.ch[0]->perimeter; + if (lower.ch[0]) perimeter += lower.ch[0]->perimeter; + return perimeter; + } + + struct hull_iterator { + half_hull<+1>::node *upper_ptr; + half_hull<-1>::node *lower_ptr; + hull_iterator(half_hull<+1>::node *upper_ptr, half_hull<-1>::node *lower_ptr) : + upper_ptr(upper_ptr), lower_ptr(lower_ptr) { } + + bool operator==(hull_iterator it) { + auto is_end = [&](hull_iterator it) { return !it.upper_ptr && !it.lower_ptr; }; + if (is_end(*this) && is_end(it)) return true; + if (is_end(*this) || is_end(it)) return false; + return *(*this) == *it; + } + bool operator!=(hull_iterator it) { return !operator==(it); } + void operator++() { + if (upper_ptr) upper_ptr = upper_ptr->next[1]; + if (!upper_ptr) { + lower_ptr = lower_ptr->next[0]; + if (lower_ptr && !lower_ptr->next[0]) lower_ptr = 0; + } + } + point operator*() { + return upper_ptr ? upper_ptr->p : lower_ptr->p; + } + }; + hull_iterator begin() { + if (!upper.ch[0]) return hull_iterator(0, 0); + auto upper_ptr = upper.ch[0]; + for (; upper_ptr->child[0]; upper_ptr = upper_ptr->child[0]); + auto lower_ptr = lower.ch[0]; + for (; lower_ptr->child[1]; lower_ptr = lower_ptr->child[1]); + return hull_iterator(upper_ptr, lower_ptr); + } + hull_iterator end() { return hull_iterator(0, 0); } + hull_iterator find(point p) { + hull_iterator it = begin(); + it.upper_ptr = upper.find(p); + if (!it.upper_ptr) it.lower_ptr = lower.find(p); + return it; + } + hull_iterator next(hull_iterator it) { + ++it; + if (it == end()) it = begin(); + return it; + } +}; + +int ACMICPC_JP_2017D() { + int n; + scanf("%d", &n); + vector ps; + for (int i = 0; i < n; ++i) { + double x, y; + scanf("%lf %lf", &x, &y); + ps.push_back({x, y}); + } + dynamic_convex_hull hull(ps); + for (int i = 0; i < n; ++i) + hull.insert(ps[i]); + + double per = hull.perimeter(); + double best1 = 0; + { // best non-adjacent + vector> top; + for (auto it = hull.begin(); it != hull.end(); ++it) { + hull.erase(*it); + top.push_back({per - hull.perimeter(), *it}); + hull.insert(*it); + } + sort(all(top)); reverse(all(top)); + for (int i = 0; i < min(4, (int)top.size()); ++i) { + point p = top[i].snd; + for (int j = i+1; j < min(4, (int)top.size()); ++j) { + point q = top[j].snd; + auto it = hull.next(hull.find(p)); + if (*it == q) continue; + it = hull.next(hull.find(q)); + if (*it == p) continue; + best1 = max(best1, top[i].fst + top[j].fst); + } + } + } + double best2 = 0; + { // best consecurive two + for (auto it = hull.begin(); it != hull.end(); ++it) { + auto jt = hull.next(it); + hull.erase(*it); + hull.erase(*jt); + best2 = max(best2, per - hull.perimeter()); + hull.insert(*it); + hull.insert(*jt); + } + } + double best3 = 0; + { // best successive two + for (auto it = hull.begin(); it != hull.end(); ++it) { + auto jt = hull.next(it), kt = hull.next(jt); + hull.erase(*jt); + for (auto lt = it; lt != kt; lt = hull.next(lt)) { + hull.erase(*lt); + best3 = max(best3, per - hull.perimeter()); + hull.insert(*lt); + } + hull.insert(*jt); + } + } + printf("%.5f\n", max({best1, best2, best3})); +} + +//----------------------------------------------------------------------------- +// kd-tree with distance biseparator. +// +// if we construct naively, it tooks O(n^2). +// using candle burning method (by Bentley), it can construct in O(n log n). +// The following implementation is lazy so O(n log^2 n). +//----------------------------------------------------------------------------- +struct split_tree { + struct node { + node *l, *r; + int d; + point h; + int id; + } *root; + int n; + vector ps; + pair ref(pair p) { + return {{p.fst.y, p.fst.x}, p.snd}; + } + split_tree(vector ps) : n(ps.size()), ps(ps) { + set> s[2]; + for (int i = 0; i < n; ++i) { + pair z = {ps[i], i}; + s[0].insert(z); + s[1].insert(ref(z)); + } + function>*)> rec = [&](set> s[]) { + if (s[0].empty()) return (node*)0; + if (s[0].size() == 1) { + int id = s[0].begin()->snd; + return new node({0, 0, -1, ps[id], id}); + } + int d = 0; + if (prev(s[0].end())->fst - s[0].begin()->fst < + prev(s[1].end())->fst - s[1].begin()->fst) d = 1; + auto it = s[d].begin(), jt = prev(s[d].end()); + point h = (jt->fst + it->fst) / 2; // left if smaller than h + while (1) { + if (it == jt || h <= it->fst) break; ++it; + if (it == jt || jt->fst < h) break; --jt; + } + node *l, *r; + set> ss[2]; + if (it->fst < h) { // violate jt side + ++jt; + do { + ss[!d].insert(ref(*jt)); + s[!d].erase(ref(*jt)); + ss[d].insert(*jt); + jt = s[d].erase(jt); + } while (jt != s[d].end()); + r = rec(ss); + l = rec(s); + } else { // violate it side + do { + --it; + ss[!d].insert(ref(*it)); + s[!d].erase(ref(*it)); + ss[d].insert(*it); + it = s[d].erase(it); + } while (it != s[d].begin()); + l = rec(ss); + r = rec(s); + } + return new node({l, r, d, h, -1}); + }; + root = rec(s); + } + + int depth(node *u) { + if (!u) return 0; + return 1+max(depth(u->l), depth(u->r)); + } + void disp(node *u, int tab = 0) { + if (!u) return; + if (u->d < 0) { + cout << string(tab, ' ') << u->h << endl; + return; + } else { + cout << string(tab, ' ') << "split at " << (u->h) << " (" << u->d << ")" << endl; + disp(u->l, tab+2); + disp(u->r, tab+2); + } + } +}; + +// naive. O(n^2) in worst case. or O(n log(largest gap/smallest gap)) +struct split_tree_n { + struct node { + node *l, *r; + int d; + point h; + int id; + } *root; + + int n; + vector ps; + pair ref(pair p) { + return {{p.fst.y, p.fst.x}, p.snd}; + } + split_tree_n(vector ps) : n(ps.size()), ps(ps) { + function)> rec = [&](vector id) { + if (id.size() == 0) return (node*)0; + if (id.size() == 1) { + return new node({0, 0, -1, ps[id[0]], id[0]}); + } + vector xs, ys; + for (int i: id) { + xs.push_back(ps[i].x); + ys.push_back(ps[i].y); + } + sort(all(xs)); + sort(all(ys)); + if (xs.back() - xs[0] > ys.back() - ys[0]) { + real d = (xs.back()+xs[0])/2; + vector ls, rs; + for (int i: id) { + if (ps[i].x < d) ls.push_back(i); + else rs.push_back(i); + } + return new node({rec(ls), rec(rs), 0, {d,0}, -1}); + } else { + real d = (ys.back()+ys[0])/2; + vector ls, rs; + for (int i: id) { + if (ps[i].y < d) ls.push_back(i); + else rs.push_back(i); + } + return new node({rec(ls), rec(rs), 1, {0,d}, -1}); + } + }; + vector id(n); iota(all(id), 0); + root = rec(id); + } + + int depth(node *u) { + if (!u) return 0; + return 1+max(depth(u->l), depth(u->r)); + } + void disp(node *u, int tab = 0) { + if (!u) return; + if (u->d < 0) { + cout << string(tab, ' ') << u->h << endl; + return; + } else { + cout << string(tab, ' ') << "split at " << (u->h) << " (" << u->d << ")" << endl; + disp(u->l, tab+2); + disp(u->r, tab+2); + } + } +}; + +// TODO +// https://graphics.stanford.edu/courses/cs468-06-fall/Papers/02%20vladlen%20notes.pdf +// epsilon net +// Let (X, F) be a set system. N \subset X is called epsilon net if +// N cat S \neq empty for all S in F with u(S) > epsilon. +// (if S in F has area greater than epsilon, S intersect with N). +// +// Theorem. there exists e-net of size O(d (1/e) log(1/e)) +// + + + +// vor(i) is the polygon such that for all p in vor(i) +// ps[i] is the farthest point from p. +// +// clearly: vor(i) is non-empty if ps[i] is on the convex hull. +// +// TODO +struct farthest_voronoi { + int n; + vector ps, qs; + map id; + /* + int node(point p) { + if (!id.count(p)) { id[p] = m++; qs.push_back(p); adj.push_back({}); } + return id[p]; + } + */ + vector> vor; + + farthest_voronoi(vector ps, vector domain) : + n(ps.size()), ps(ps) { + vector id(n); iota(all(id), 0); + sort(all(id), [&](int i, int j) { return ps[i] < ps[j]; }); + + vector ch(2*n); + auto cond = [&](int i, int j, int k) { + return sign(cross(ps[i]-ps[k], ps[j]-ps[k])) < 0; + }; + int k = 0; + for (int i = 0; i < n; ch[k++] = i++) + for (; k >= 2 && cond(ch[k-2], ch[k-1], i); --k); + for (int i = n-2, t = k+1; i >= 0; ch[k++] = i--) + for (; k >= t && cond(ch[k-2], ch[k-1], i); --k); + ch.resize(k-1); + + cout << ch << endl; + + vector prev(n, -1), next(n, -1); + for (int i = 0; i < ch.size(); ++i) { + int j = i + 1; if (j >= ch.size()) j = 0; + next[ch[i]] = ch[j]; + prev[ch[j]] = ch[i]; + } + + auto disp = [&](int s) { + int u = s; + do { + cout << u << " "; + u = next[u]; + } while (u != s); + cout << endl; + }; + shuffle(all(ch), mt19937()); + vor.resize(n); + for (int i = (int)ch.size()-1; i >= 1; --i) { + disp(ch[0]); + next[prev[ch[i]]] = next[ch[i]]; + prev[next[ch[i]]] = prev[ch[i]]; + } + // つらい + // 基本 DCEL がらみはしんどい + vor[ch[0]] = domain; + cout << "---" << endl; + for (int i = 1; i < ch.size(); ++i) { + next[prev[ch[i]]] = ch[i]; + prev[next[ch[i]]] = ch[i]; + disp(ch[0]); + // ch[i] と next[ch[i]] の bisector で切る + // 領域を hyperplane で管理するのが良いのか + /* + for (int j = 0; j < i; ++j) { + point s = (ps[e.src]+ps[e.dst])/2, d = orth(ps[e.dst]-ps[e.src]); + region = convex_cut(region, {s, s+d}); + } + */ + } + + // ランダムに挿入しながら構築する. + // 点 i を挿入するとき.next[i] の voronoi region を i, next[i] の bisector で切る + // bisector があたる領域を j の voronoi region として i, j の bisector で切る + // これを繰り返す + // + // データ構造処理がデス辛い + // + // 必要な演算 + // voronoi region の辺集合 + + } + +}; + +/* +struct doubly_connected_edge_list { + struct Vertex; + struct Edge; + struct Face; + struct vertex { + Edge *edge; // any incident edge + point p; // + }; + struct Edge { + Vertex *vertex; // origin + Edge *prev, *next; // surrounding edges of face + Edge *twin; // reverse edge of e + Face *face; // left face + }; + struct Face { + Edge *edge; // Any incident edge + }; + + // process edges incident to v in CCW order + void incident(Vertex *v) { + Edge *e = vertex->edge; + do { + // process e + e = e->prev->twin; + } while (e != v->edge) + v->edge; + } + // process vertices incident to e in SRC-DST order + void incident(Edge *e) { + // process e->vertex; + // process e->twin->vertex; + } + // process edges incident to f in CCW order + void incident(Face *f) { + Edge *e = f->edge; + do { + // process e + e = e->next; + } while (e != f->edge); + } +}; +*/ + +// +// Polyhedral Region Overlay +// +struct DCEL { + struct Vertex; + struct Edge; + struct Vertex { + point p; + Edge *edge; + }; + struct Edge { + Vertex *vertex; + Edge *twin; + Edge *prev, *next; + // Face *face; + }; + + DCEL copy() { + + } +}; +void overlay(DCEL *a, DCEL *b) { + // + // a と b で segment intersection をとく + // 各 intersection について新しい点をおいて edge を分割 + // その後,face を assign する + // +}; + + +// Convex Hull of circles; めっちゃバグってる +// +// divide and conquer?? +// +// 2つの凸包から,それらの union の凸包を作ればいい +// +// 最も右端にある円を選び,真上への接直線を引く +// dominant なほうを追加する +// +// TODO +// http://ac.els-cdn.com/092577219290015K/1-s2.0-092577219290015K-main.pdf?_tid=f2321600-62e3-11e6-aa7a-00000aacb35e&acdnat=1471264364_f7d8c0796b081532ec0e84e22028f111 +// +// [non-verified; in progress] +vector convex_hull(vector cs) { + int n = cs.size(); + typedef vector hull; + function merge = [&](hull P, hull Q) { + cout << "---" << endl; + cout << "merge "; + for (auto i: P) cout << "[" << cs[i].p << "," << cs[i].r << "] "; + cout << "and"; + for (auto j: Q) cout << " [" << cs[j].p << "," << cs[j].r << "]"; + cout << endl; + hull S; + unordered_set elem; + auto add = [&](int k) { + if (elem.count(k)) return; + cout << "add [" << cs[k].p << "," << cs[k].r << "]" << endl; + S.push_back(k); + elem.insert(k); + }; + auto supp = [&](int k, point v) { + circle c = cs[k]; + return c.p - c.r * orth(v); + }; + auto dom = [&](int i, int j, point v) { + point p = supp(P[i], v), q = supp(Q[j], v); + cout << "p = " << p << ", q = " << q << endl; + int s = sign(cross(p - q, v)); + cout << "s = " << s << endl; + return s ? s > 0 : sign(dot(q - p, v)) > 0; + }; + auto tangent = [&](int k, int l) { + if (k == l) return point({0,0}); + auto u = cs[l].p - cs[k].p; + auto b = cs[k].r - cs[l].r, g = norm(u); + u /= g; + auto h = b / g; + cout << h << endl; + if (sign(1 - h*h) < 0) return point({0,0}); + return orth(u*h - orth(u)*sqrt(max(0.0l, 1 - h*h))); + }; + auto compare = [&](point a, point b, point v) { + cout << "compare " << a << " " << b << " " << v << endl; + if (sign(dot(a,a)) == 0) return false; + if (sign(dot(b,b)) == 0) return true; + // TODO: v と a, b は同じ方向ではいけない(大丈夫?) + // a はゼロかもしれない + int s = sign(cross(v, a)), t = sign(cross(v, b)); + cout << "s = " << s << ", t = " << t << endl; + if (s == 0 && dot(v, a) > 0) return true; + if (t == 0 && dot(v, b) > 0) return false; + return s != t ? s > t : sign(cross(a, b)) > 0; + }; + auto advance = [&](int &i, int &j, point &v) { + int I = (i+1) % P.size(), J = (j+1) % Q.size(); + point a = tangent(P[i], Q[j]), b = tangent(P[i], P[I]), + c = tangent(Q[j], Q[J]), d = tangent(Q[j], P[i]); + cout << a << " " << b << " " << c << " " << d << endl; + if (compare(a, b, v) && compare(a, c, v)) { cout << a << " is the first turn" << endl; add(Q[j]); } + if (compare(d, b, v) && compare(d, c, v)) { cout << d << " is the first turn" << endl; add(P[i]); } + if (compare(b, c, v)) { v = b; i = I; } + else { v = c; j = J; } + }; + int i = 0, j = 0; + point v = {1, 0}; + for (int iter = 0; iter < 3+P.size()+Q.size(); ++iter) { + if (sign(norm(v)) == 0) break; + cout << "currently " << cs[P[i]].p << " and " << cs[Q[j]].p << endl; + if (dom(i, j, v)) { + cout << cs[P[i]].p << " is the lowermost" << endl; + add(P[i]); + } else { + cout << cs[Q[j]].p << " is the lowermost" << endl; + add(Q[j]); + } + advance(i, j, v); + } + cout << "==> "; + for (auto i: S) cout << "[" << cs[i].p << "," << cs[i].r << "] "; + cout << endl; + return S; + }; + function rec = [&](int l, int r) { + if (l+1 == r) return (hull){l}; + auto P = rec(l, (l+r)/2), Q = rec((l+r)/2, r); + return merge(P, Q); + }; + auto ch = rec(0, n); + vector res; + for (int i: ch) res.push_back(cs[i]); + return res; +} + +void verify_convex_hull_discs() { + int n = 20; + vector cs; + for (int i = 0; i < n; ++i) + cs.push_back({ {urand(), urand()}, urand()/3 }); + auto ch = convex_hull(cs); + + visualizer vis; + for (auto c: cs) vis << c; + point shift = point({vis.maxx+1, 0}); + for (auto c: ch) vis << circle({c.p + shift, c.r}); +} + +void verify_farthest_voronoi() { + + vector ps = { + {0,0}, + {2,0}, + {1,1}, + {2,2}, + {0,2}, + }; + vector region = { + {-10,-10}, + { 10,-10}, + { 10, 10}, + {-10, 10} + }; + farthest_voronoi V(ps, region); +} + + +// verify +// +void verify_delaunay() { + { + vector ps = { + //{0,0}, {1,0}, {1,1}, + /* + {0,0}, {0,1}, {0,2}, + {1,0}, {1,1}, + */ + /* + {0,0}, {1,0}, {2,0}, + {0,1}, {1,1}, {2,1}, + {0,2}, {1,2}, {2,2}, + */ + }; + } + int n = 100000; + vector ps(n); + for (int i = 0; i < n; ++i) + ps[i].x = urand(), ps[i].y = urand(); + tick(); + delaunay DT(ps); + cout << tick() << endl; + + visualizer vis; + for (point p: ps) vis << p; + for (int u = 0; u < DT.n; ++u) { + for (auto e: DT.adj[u]) + vis << segment({ps[e.src], ps[e.dst]}); + } + /* + for (int n = 5; n < 7; n *= 1.5) { + vector ps(n); + for (int i = 0; i < n; ++i) + ps[i].x = 100 * urand(), ps[i].y = 100 * urand(); + delaunay DT(ps); + } + */ +} +void verify_voronoi() { + /* + vector ps = { + {0,0}, {1,0}, {0,1} + }; + */ + for (int n = 5; n < 100000; n *= 1.5) { + vector ps(n); + for (int i = 0; i < n; ++i) + ps[i].x = urand(), ps[i].y = urand(); + + vector region = { + {-0.1,-0.1}, + { 1.1,-0.1}, + { 1.1, 1.1}, + {-0.1, 1.1} + }; + cout << "n = " << n << " "; + voronoi Vor(ps, region); + + visualizer vis; + for (point p: ps) vis << p; + for (int u = 0; u < Vor.m; ++u) { + //vis << Vor.qs[u]; + for (auto e: Vor.adj[u]) + vis << segment({Vor.qs[e.src], Vor.qs[e.dst]}); + } + } +} + +void POJ2235() { + for (int n; ~scanf("%d", &n); ) { + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + delaunay DT(ps); + } +} +void AOJ1514() { + for (int n, m; scanf("%d %d", &n, &m); ) { + if (n == 0) break; + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + delaunay DT(ps); + vector score(n); + double ans = 0.0; + for (int j = 0; j < m; ++j) { + point c, d; + double s; + scanf("%lf %lf %lf %lf %lf", &c.x, &c.y, &d.x, &d.y, &s); + vector domain = { + c + point({-d.x, -d.y}), + c + point({+d.x, -d.y}), + c + point({+d.x, +d.y}), + c + point({-d.x, +d.y}), + }; + voronoi V(DT, domain); + visualizer vis; + for (point p: ps) vis << p; + for (int u = 0; u < V.m; ++u) { + for (auto e: V.adj[u]) + vis << segment({V.qs[e.src], V.qs[e.dst]}); + } + vector &qs = V.qs; + for (int i = 0; i < n; ++i) { + real area = 0; + int K = V.cell[i].size(); + for (int k = 0; k < K; ++k) + area += cross(qs[k], qs[(k+1)%K]); + score[i] += s * area / 2 / (4 * d.x * d.y); + ans = max(ans, score[i]); + } + } + printf("%.12lf\n", ans); + } +} + +void verify_rectangle_union() { + vector rs = { + { {0,0},{2,2} }, + { {1,1},{4,2} }, + { {3,0},{5,2} }, + }; + cout << rectangle_union(rs) << endl; +} + +void verify_relative_neighborhood_graph() { + vector ps = { + {0,0}, + {1,0}, + {0,1}, + {1,1} + }; + relative_neighborhood_graph rng(ps); + for (int u = 0; u < rng.n; ++u) { + for (auto e: rng.adj[u]) { + cout << ps[e.src] << " " << ps[e.dst] << endl; + } + } +} + + +void verify_nearest_neighbor_structure() { + int n = 1000000, m = 100, k = 10; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i].x = urand(); + ps[i].y = urand(); + } + tick(); + vantage_point_tree VPT(ps); + cout << "vantage point tree: " << tick() << endl; + random_ball_cover RBC(ps); + cout << "random ball cover: " << tick() << endl; + + double t1 = 0, t2 = 0; + for (int i = 0; i < m; ++i) { + point p; + p.x = urand(); + p.y = urand(); + + cout << "---" << endl; + tick(); + cout << VPT.closest(p, k) << endl; + t1 += tick(); + cout << RBC.closest(p, k) << endl; + t2 += tick(); + } + cout << "vantage point tree: " << t1 << endl; + cout << "random ball over: " << t2 << endl; +} + + + +void verify_points_counter() { + vector ps = { + {0,1}, + {1,0}, + {1,1}, + {2,1}, + }; + points_counter T(ps); +} + + + + + + + + + +void verify_intersectCC() { + auto th = 3.141592653589*rand()/(1.0+RAND_MAX); + auto dx = 1 - 2*rand()/(1.0+RAND_MAX); + auto dy = 1 - 2*rand()/(1.0+RAND_MAX); + auto S = [&](point p) { + real c = cos(th), s = sin(th); + p.x -= dx; p.y -= dy; + return (point){c * p.x + s * p.y, -s * p.x + c*p.y}; + }; + auto T = [&](circle C) { + return (circle){ S(C.p), C.r }; + }; + { + circle C = { {0,0}, 1 }; + circle D = { {2,0}, 1 }; + TEST(intersect(T(C), T(D)).size(), 1); // touch outer + } + { + circle C = { {0,0}, 1 }; + circle D = { {1,0}, 1 }; + TEST(intersect(T(C), T(D)).size(), 2); // properly intersect inner + } + { + circle C = { {0,0}, 2 }; + circle D = { {1,0}, 1 }; + TEST(intersect(T(C), T(D)).size(), 1); // intersect inner + } + { + circle C = { {0,0}, 2 }; + circle D = { {3,0}, 2 }; + TEST(intersect(T(C), T(D)).size(), 2); // properly intersect outer + } + { + circle C = { {0,0}, 3 }; + circle D = { {1,0}, 1 }; + TEST(intersect(T(C), T(D)).size(), 0); // too close + } + { + circle C = { {0,0}, 1 }; + circle D = { {3,0}, 1 }; + TEST(intersect(T(C), T(D)).size(), 0); // too far + } +} + +void verify_three_point_circle() { + for (int iter = 0; iter < 100; ++iter) { + point p = {urand(), urand()}; + point q = {urand(), urand()}; + point r = {urand(), urand()}; + circle c = three_point_circle(p, q, r); + TEST(dot(c.p - p, c.p - p), dot(c.p - q, c.p - q)); + TEST(dot(c.p - p, c.p - p), dot(c.p - r, c.p - r)); + } +} + +void verify_triangulate() { + vector ps; + ps.push_back({0, 0}); + ps.push_back({2, 0}); + ps.push_back({2, 2}); + ps.push_back({1, 1}); + ps.push_back({0, 2}); + TEST(triangulate(ps), area(ps)); +} + +void verify_convex_cut() { + int n; + scanf("%d", &n); + vector ps(n); + for (int i = 0; i < n; ++i) { + scanf("%lf %lf", &ps[i].x, &ps[i].y); + } + int m; + scanf("%d", &m); + for (int i = 0; i < m; ++i) { + line L; + scanf("%lf %lf %lf %lf", &L.p.x, &L.p.y, &L.q.x, &L.q.y); + vector qs = convex_cut(ps, L); + printf("%f\n", area(qs)); + } +} +void verify_convex_cut2() { + vector ps = { + {0.,0.}, + {1.,0.}, + {2.,0.}, + {2.,1.}, + {2.,2.}, + {1.,2.}, + {0.,2.}, + {0.,1.} + }; + line L = {{1,0},{1.5,0}}; + vector qs = convex_cut(ps, L); + for (auto q: qs) cout << q << " "; cout << endl; +} +void verify_tangent() { + point p; + circle c; + scanf("%lf %lf", &p.x, &p.y); + scanf("%lf %lf %lf", &c.p.x, &c.p.y, &c.r); + vector ps; + for (auto L: tangent(c, p)) { + if (L.p == p) ps.push_back(L.q); + else ps.push_back(L.p); + } + sort(all(ps)); + for (auto p: ps) + printf("%.12f %.12f\n", p.x + EPS, p.y + EPS); +} +void verify_tangentCC() { + TEST(tangent({{-2.0, 0.0}, 2.0}, {{-2.0, 0.0}, 1.0}).size(), 0); + TEST(tangent({{-2.0, 0.0}, 2.0}, {{-1.0, 0.0}, 1.0}).size(), 1); + TEST(tangent({{-2.0, 0.0}, 2.0}, {{-0.5, 0.0}, 1.0}).size(), 2); + TEST(tangent({{-2.0, 0.0}, 2.0}, {{+1.0, 0.0}, 1.0}).size(), 3); + TEST(tangent({{-2.0, 0.0}, 2.0}, {{+2.0, 0.0}, 1.0}).size(), 4); + TEST(tangent({{+2.0, 0.0}, 2.0}, {{+2.0, 0.0}, 1.0}).size(), 0); + TEST(tangent({{+2.0, 0.0}, 2.0}, {{+1.0, 0.0}, 1.0}).size(), 1); + TEST(tangent({{+2.0, 0.0}, 2.0}, {{+0.5, 0.0}, 1.0}).size(), 2); + TEST(tangent({{+2.0, 0.0}, 2.0}, {{-1.0, 0.0}, 1.0}).size(), 3); + TEST(tangent({{+2.0, 0.0}, 2.0}, {{-2.0, 0.0}, 1.0}).size(), 4); + + for (int iter = 0; iter < 100; ++iter) { + circle c = {{urand(), urand()}, urand()}; + circle d = {{urand(), urand()}, urand()}; + for (line l: tangent(c, d)) { + TEST(intersect(l, c).size(), 1); + TEST(intersect(l, d).size(), 1); + } + } +} +void verify_tangentCC2() { + circle c, d; + cin >> c.p.x >> c.p.y >> c.r; + cin >> d.p.x >> d.p.y >> d.r; + vector ls = tangent(c, d); + vector ps; + for (line l: ls) { + ps.push_back(intersect(l, c)[0]); + } + sort(all(ps)); + for (point p: ps) { + double x = p.x; if (sign(x) == 0) x = 0; + double y = p.y; if (sign(y) == 0) y = 0; + printf("%.12f %.12f\n", x, y); + } +} +void verify_intersect_area() { + vector ps = { + {0.,0.}, + {3.,0.}, + {0.,3.}, + }; + circle c = {{0.0,0.0},2.8}; + cout << intersection_area(ps, c) << endl; +} + +void verify_closest_pair() { + double t1 = 0, t2 = 0; + for (int seed = 3; seed < 100; ++seed) { + srand(seed); + int n = 20000; + vector ps; + for (int i = 0; i < n; ++i) { + ps.push_back({urand(), urand()}); + } + tick(); + auto uv = closest_pair(ps); + t1 += tick(); + auto wx = closest_pair2(ps); + t2 += tick(); + auto d1 = dist(uv.fst, uv.snd); + auto d2 = dist(wx.fst, wx.snd); + cout << uv.fst << " " << uv.snd << " " << dist(uv.fst, uv.snd) << endl; + cout << wx.fst << " " << wx.snd << " " << dist(wx.fst, wx.snd) << endl; + cout << endl; + if (sign(d1 - d2) != 0) { + cout << seed << endl; + break; + } + } + cout << t1 << " " << t2 << endl; +} + +vector half_plane_intersection_n(vector ls) { + real s = 99999999; + vector ps = {{-s,-s},{s,-s},{s,s},{-s,s}}; + for (int i = 0; i < ls.size(); ++i) + ps = convex_cut(ps, ls[i]); + return ps; +} +void verify_half_plane_intersection() { + for (int seed = 0; seed < 1000; ++seed) { + srand(seed); + int n = 3 + rand() % 100; + vector ls; + for (int i = 0; i < n; ++i) { + double th1 = 2 * PI * i / n; + double th2 = 2 * PI * (i+1) / n; + double r1 = 10 + 100 * urand(); + double r2 = 10 + 100 * urand(); + ls.push_back({{r1*cos(th1), r1*sin(th1)}, + {r2*cos(th2), r2*sin(th2)}}); + } + auto a1 = area(half_plane_intersection(ls)); + auto a2 = area(half_plane_intersection_n(ls)); + if (sign(1 - a2/a1)) { cout << a1 << " " << a2 << " " << 1 - a2/a1 << " " << sign(1-a2/a1) << seed << endl; exit(-1); } + } +} + +// TEST +void angular_sort_n(vector &ps) { + vector> qs; + for (point p: ps) { + qs.push_back(make_tuple(arg(p), norm2(p), p)); + if (get<0>(qs.back()) < 0) get<0>(qs.back()) += 2 * PI; + } + sort(all(qs)); + for (int i = 0; i < ps.size(); ++i) + ps[i] = get<2>(qs[i]); +} +void verify_polar_angle() { + double t1 = 0, t2 = 0; + int n = 1000000; + vector ps; + for (int i = 0; i < n; ++i) + ps.push_back({(double)(rand()%2001)-1000, (double)(rand()%2001)-1000}); + vector qs = ps; + tick(); + sort(all(ps), polar_angle()); + t1 += tick(); + angular_sort_n(qs); + t2 += tick(); + for (int i = 0; i < ps.size(); ++i) { + if (!(ps[i] == qs[i])) { cout << "*"; } + //cout << ps[i] << " " << qs[i] << endl; + } + cout << t1 << " " << t2 << endl; +} + +void verify_maximum_circle_cover() { + int n = 10000; + vector ps; + for (int i = 0; i < n; ++i) { + double x = rand() % 1000, y = rand() % 1000; + ps.push_back({x, y}); + } + tick(); + cout << maximum_circle_cover(ps, 20) << endl; + cout << tick() << endl; + cout << maximum_circle_cover2(ps, 20) << endl; + cout << tick() << endl; +} +void verify_maximum_circle_cover2() { + for (int n; scanf("%d", &n) && n; ) { + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + printf("%d\n", maximum_circle_cover2(ps, 1.0)); + } +} + + +void verify_circle_intersection_area() { + circle c = {{0,0}, 2}; + circle d = {{2.8,0}, 1}; + cout << intersection_area(c, d) << endl; + + // Monte-Carlo integration + real w = 10.0, vol = w*w; // w times w box centered at (0,0) + int count = 0, maxcount = 100000000; + for (int i = 0; i < maxcount; ++i) { + point p = {w*urand() - w/2, w*urand() - w/2}; + if (contains(c, p) && contains(d, p)) ++count; + } + real r = 1.0*count/maxcount; + real mu = vol * r, sigma = vol*sqrt((r-r*r)/maxcount); + cout << "95\% confidence: [" << mu-3*sigma << ", " << mu+3*sigma << "]" << endl; +} + +void verify_geometric_median() { + int n = 10; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i].x = urand(); + ps[i].y = urand(); + } + cout << geometric_median(ps) << endl; +} +void verify_geometric_median2() { + while (1) { + vector ps(4); + for (int i = 0; i < 4; ++i) + cin >> ps[i].x >> ps[i].y; + if (ps[0].x < 0) break; + point g = geometric_median(ps); + //cout << g << endl; + double w = 0; + for (int i = 0; i < 4; ++i) + w += norm(ps[i] - g); + printf("%.4f\n", w); + } +} +void verify_tangent_circles() { + line l = { {0,0},{1,0} }; + line m = { {0,2},{1,2} }; + for (circle c: tangent_circles(l, m, 1.0)) { + cout << c.p << " " << c.r << endl; + cout << " "; for (point p: intersect(c, l)) { cout << p << " "; } cout << endl; + cout << " "; for (point p: intersect(c, m)) { cout << p << " "; } cout << endl; + } +} + + +void verify_arrangement() { + vector ss = { + {{0,0},{2,0}}, + {{3,0},{5,0}}, + {{1,0},{4,0}} + }; + arrangement arr(ss); +} + +void verify_is_congruence() { + int n = 10; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i] = {urand(), urand()}; + } + double r = urand(); + point u = {urand(), urand()}; + double c = urand(), s = sqrt(1 - c*c); + vector qs; + for (int i = 0; i < ps.size(); ++i) { + qs.push_back(r * (point){c*ps[i].x+s*ps[i].y, -s*ps[i].x+c*ps[i].y} + u); + } + int k = rand() % qs.size(); + rotate(qs.begin(), qs.begin()+k, qs.end()); + cout << is_congruence(ps, qs) << endl; + cout << is_similar(ps, qs) << endl; +} + + +void verify_merge_segment() { + vector ss = { + {{0,0},{2,0}}, + {{0,0},{0,2}}, + {{4,0},{7,0}}, + {{5,0},{6,0}}, + }; + merge_segments(ss); +} +void verify_farthest_pair() { + int n = 30; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i].x = rand() % 10; + ps[i].y = rand() % 10; + } + auto ans = farthest_pair(ps); + + real best = -1; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + best = max(best, norm(ps[i]-ps[j])); + } + } + + cout << norm(ans.fst-ans.snd) << " " << best << endl; +} + +void ACAC002() { + int n; cin >> n; + vector ps(n); + for (int i = 0; i < n; ++i) + cin >> ps[i]; + auto ans = farthest_pair(ps); + printf("%.12f\n", norm(ans.snd-ans.fst)); +} + +void verify_split_tree() { + for (int n = 1; n < 1000000; n *= 2) { + vector ps; + double x = 1, y = 0; + for (int i = 0; i < n; ++i) { + x *= 1.001; + y = 0; //rand() / (RAND_MAX +1.0); + ps.push_back({x,y}); + } + sort(all(ps)); ps.erase(unique(all(ps)), ps.end()); + tick(); + split_tree T(ps); + cout << T.depth(T.root) << endl; + cout << n << " " << tick() << endl; + } +} + + +int main() { + //verify_intersectCC(); + //verify_three_point_circle(); + //verify_triangulate(); + //verify_convex_cut2(); + //verify_tangent(); + //verify_tangentCC(); + //verify_tangentCC2(); + //verify_intersect_area(); + //verify_closest_pair(); + //verify_half_plane_intersection(); + //verify_polar_angle(); + //verify_maximum_circle_cover(); + //verify_maximum_circle_cover2(); + //verify_rectangle_union(); + //verify_points_counter(); + //verify_circle_intersection_area(); + //verify_geometric_median(); + //verify_tangent_circles(); + //verify_maximum_points_line(); + //verify_arrangement(); + //verify_merge_segment(); + //AOJ1226(); + //AOJ2448(); + //AOJ1247(); + //verify_relative_neighborhood_graph(); + //verify_nearest_neighbor_structure(); + //verify_delaunay(); + //POJ2235(); + // verify_voronoi(); + //verify_is_congruence(); + //AOJ1514(); + //AOJ0273(); + //verify_farthest_pair(); + //ACAC002(); + //verify_compressed_quad_tree(); + //verify_split_tree(); + //verify_farthest_voronoi(); + //verify_convex_hull_discs(); +} diff --git a/geometry/coordinate_domination.cc b/geometry/coordinate_domination.cc new file mode 100644 index 0000000..6bbb728 --- /dev/null +++ b/geometry/coordinate_domination.cc @@ -0,0 +1,88 @@ +// +// 3D Coordinate-Wise Domination +// +// Description: +// +// Point (x,y,z) dominates (x',y',z') if +// x < x', y < y', and z < z' +// holds. Kung-Luccio-Preparata proposed an algorithm to compute +// the all set of dominating points in O(n log n) time. +// +// It maintains a data structure to check the domination in (y,z) plane, +// and proceed the points in the decreasing order of x. +// By the processing order, the new point is never dominated by the latter +// points and is dominated by the previous points if its (y,z) coordinate +// is dominated by them. +// +// Complexity: +// +// O(n log n). By using this method recursively, +// we can solve d-dimensional domination in O(n log^{d-2} n). +// +// Reference: +// +// Hsiang-Tsung Kung, Fabrizio Luccio, Franco P. Preparata (1975): +// "On finding the maxima of a set of vectors." Journal of the ACM, +// vol.22, no.4, pp.469-476. +// + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +using Real = int; +struct Point { + Real x, y, z; + bool operator < (Point p) const { + if (x != p.x) return x < p.x; + if (y != p.y) return y < p.y; + return z < p.z; + } +}; +int domination(vector xs) { + multiset frontier; + auto bad = [&](multiset::iterator it) { + auto jt = next(it); + if (jt == frontier.end()) return false; + return it->y < jt->y && it->z < jt->z; + }; + int n = xs.size(); + sort(all(xs)); + int count = 0; + for (int i = n-1; i >= 0; --i) { + auto proc = [&] { + if (i < n-1 && xs[i].x == xs[i+1].x) return true; + Point p(xs[i]); p.x = 0; + auto it = frontier.insert(p); + if (bad(it)) { + frontier.erase(it); + return false; + } else { + while (it != frontier.begin() && bad(prev(it))) + frontier.erase(prev(it)); + return true; + } + }; + if (proc()) ++count; + } + return count; +} + + +int main() { + int ncase; scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + int n; scanf("%d", &n); + vector ps(n); + for (int i = 0; i < n; ++i) { + scanf("%d %d %d", &ps[i].x, &ps[i].y, &ps[i].z); + ps[i].x = -ps[i].x; + ps[i].y = -ps[i].y; + ps[i].z = -ps[i].z; + } + printf("%d\n", domination(ps)); + } +} diff --git a/geometry/kd_tree.cc b/geometry/kd_tree.cc new file mode 100644 index 0000000..48f2df2 --- /dev/null +++ b/geometry/kd_tree.cc @@ -0,0 +1,180 @@ +// +// Kd-Tree +// +// Description: +// +// Kd-Tree is a spatial partitioning tree defined as follows[1]. +// Each node has a point, called a pivot, and its left +// and right childs store the points that are lefter and righter +// on the pivot. Here, "left" and "right" are defined by the +// coordinate that switches cyclically over the depth. +// +// The Kd-Tree has the depth O(log n), and if the input is random, +// the searching has complexity O(log n) in expectation. +// However, in an adversarial input, the worst case complexity +// becomes O(n^{1-1/d}), which tends to a naive bound as d to infty[2]. +// +// Note: Computing NNs for n points requires O(n^{2-1/d}) time. +// Basically, it is practical and has advantage over the naive search +// if n = 10^5. +// +// Complexity: +// +// Construction: O(n log n) +// Nearest Neighbor: O(n^{1-1/d}) in worst case, +// O(log n) in random case. +// +// References: +// +// [1] Jon Louis Bentley (1975): +// "Multidimensional binary search trees used for associative searching." +// Communications of the ACM, vol. 18, no. 9, pp. 509--517. +// +// [2] Der-Tsai Lee and C. K. Wong (1977): +// "Worst-case analysis for region and partial region searches in +// multidimensional binary search trees and balanced quad trees." +// Acta Informatica, vol.9, no.1, pp. 23--29. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +using Real = long double; +const Real PI = acos(-1.0); +const Real EPS = 1e-8; +int sign(Real x) { return (x > EPS) - (x < -EPS); } +struct Point { + Real x, y; + Point &operator+=(Point p) { x += p.x; y += p.y; return *this; } + Point &operator*=(Real a) { x *= a; y *= a; return *this; } + Point operator+() const { return {+x, +y}; } + Point operator-() const { return {-x, -y}; } + + Point &operator-=(Point p) { return *this += -p; } + Point &operator/=(Real a) { return *this *= 1/a; } +}; +Point operator+(Point p, Point q) { return p += q; } +Point operator-(Point p, Point q) { return p -= q; } +Point operator*(Real a, Point p) { return p *= a; } +Point operator*(Point p, Real a) { return p *= a; } +Point operator/(Point p, Real a) { return p /= a; } + +int compare(Point p, Point q) { + int s = sign(p.x - q.x); + return s ? s : sign(p.y - q.y); +} +bool operator==(Point p, Point q) { return compare(p,q)==0; } +bool operator!=(Point p, Point q) { return compare(p,q)!=0; } +bool operator<=(Point p, Point q) { return compare(p,q)<=0; } +bool operator>=(Point p, Point q) { return compare(p,q)>=0; } +bool operator<(Point p, Point q) { return compare(p,q)<0; } +bool operator>(Point p, Point q) { return compare(p,q)>0; } + +Real dot(Point p, Point q) { return p.x*q.x+p.y*q.y; } +Real cross(Point p, Point q) { return p.x*q.y-p.y*q.x; } // left turn > 0 +Real norm2(Point p) { return dot(p,p); } +Point orth(Point p) { return {-p.y, p.x}; } +Real norm(Point p) { return sqrt(dot(p,p)); } +Real arg(Point p) { return atan2(p.y, p.x); } +Real arg(Point p, Point q){ return atan2(cross(p,q), dot(p,q)); } + +istream &operator>>(istream &is, Point &p) { is>>p.x>>p.y;return is; } +ostream &operator<<(ostream &os, const Point &p) { os<<"("< ps; + KdTree(vector ps) : ps(ps) { + int idx[ps.size()]; + iota(idx, idx+ps.size(), 0); + root = build<0>(idx, idx+ps.size()); + } + template + Node *build(int *l, int *r) { + if (l - r >= 0) return 0; + auto comp = [&](int i, int j) { + if (d == 0) return ps[i].x < ps[j].x; + if (d == 1) return ps[i].y < ps[j].y; + }; + int *m = l + (r-l)/2; + nth_element(l, m, r, comp); + return new Node({*m, build(l,m), build(m+1,r)}); + } + template + void nearestNeighborSearchRec(Node *x, Point p, pair &ub) { + if (!x) return; + Point q = p - ps[x->id]; + Real r = norm(q), w; + if (r < ub.fst) ub = {r, x->id}; + if (d == 0) w = q.x; + else w = q.y; + Node *fst = x->left, *snd = x->right; + if (w > 0) swap(fst, snd); + nearestNeighborSearchRec(fst, p, ub); + if (ub.fst > abs(w)) nearestNeighborSearchRec(snd, p, ub); + } + int nearestNeighbor(Point p) { + pair ub(1.0/0.0, -1); + nearestNeighborSearchRec<0>(root, p, ub); + return ub.snd; + } + + + // for verification + int nearestNeighborNaive(Point p) { + int id = 0; + for (int i = 1; i < ps.size(); ++i) + if (norm(ps[i] - p) < norm(ps[id] - p)) id = i; + return id; + } + void display(Node *x, int tab=0) { + if (!x) return; + display(x->left, tab+2); + cout << string(tab, ' ') << x->id << ": " << ps[x->id] << endl; + display(x->right,tab+2); + } +}; +int main() { + int n = 10000; + vector ps(n); + for (int i = 0; i < n; ++i) { + ps[i].x = rand() % n; + ps[i].y = rand() % n; + } + KdTree T(ps); + //T.display(T.root); + + double t1 = 0, t2 = 0; + for (int k = 0; k < n; ++k) { + Point p = {rand() % n, rand() % n}; + tick(); + Point q = ps[T.nearestNeighbor(p)]; + t1 += tick(); + Point r = ps[T.nearestNeighborNaive(p)]; + t2 += tick(); + TEST(sign(norm(q-p) - norm(r-p)) == 0); + //cout << p << " " << norm(q - p) << " " << norm(r - p) << endl; + } + cout << t1 << " [s] by Kd search" << endl << + t2 << " [s] by naive search" << endl; +} diff --git a/geometry/random_ball_cover.cc b/geometry/random_ball_cover.cc new file mode 100644 index 0000000..f2266b2 --- /dev/null +++ b/geometry/random_ball_cover.cc @@ -0,0 +1,225 @@ +// +// Random Ball Cover +// +// Description: +// +// Random ball cover is a data structure for metric nearest neighbor +// search. It is useful if the only distance function is available, +// and/or dimension is moderately large (10 to 1000). +// +// It first select O(sqrt{n})-size random sample from the points as +// representatives. Then, it assigns other points to the nearest +// representatives. The search procedure uses the triangle inequality +// to prune unnecessary searching. +// +// +// Complexity: +// +// Construction: O(n log n). +// Search: O(sqrt(n)) in a random distribution. +// +// +// Reference: +// +// Lawrence Cayton (2012): +// "Accelerating nearest neighbor search on manycore systems." +// Parallel & Distributed Processing Symposium (IPDPS), +// in IPDPS, pp.402-413. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + + +using Real = long double; +const Real PI = acos(-1.0); +const Real EPS = 1e-8; +int sign(Real x) { return (x > EPS) - (x < -EPS); } +struct Point { + Real x, y; + Point &operator+=(Point p) { x += p.x; y += p.y; return *this; } + Point &operator*=(Real a) { x *= a; y *= a; return *this; } + Point operator+() const { return {+x, +y}; } + Point operator-() const { return {-x, -y}; } + + Point &operator-=(Point p) { return *this += -p; } + Point &operator/=(Real a) { return *this *= 1/a; } +}; +Point operator+(Point p, Point q) { return p += q; } +Point operator-(Point p, Point q) { return p -= q; } +Point operator*(Real a, Point p) { return p *= a; } +Point operator*(Point p, Real a) { return p *= a; } +Point operator/(Point p, Real a) { return p /= a; } + +int compare(Point p, Point q) { + int s = sign(p.x - q.x); + return s ? s : sign(p.y - q.y); +} +bool operator==(Point p, Point q) { return compare(p,q)==0; } +bool operator!=(Point p, Point q) { return compare(p,q)!=0; } +bool operator<=(Point p, Point q) { return compare(p,q)<=0; } +bool operator>=(Point p, Point q) { return compare(p,q)>=0; } +bool operator<(Point p, Point q) { return compare(p,q)<0; } +bool operator>(Point p, Point q) { return compare(p,q)>0; } + +Real dot(Point p, Point q) { return p.x*q.x+p.y*q.y; } +Real cross(Point p, Point q) { return p.x*q.y-p.y*q.x; } // left turn > 0 +Real norm2(Point p) { return dot(p,p); } +Point orth(Point p) { return {-p.y, p.x}; } +Real norm(Point p) { return sqrt(dot(p,p)); } +Real arg(Point p) { return atan2(p.y, p.x); } +Real arg(Point p, Point q){ return atan2(cross(p,q), dot(p,q)); } + +istream &operator>>(istream &is, Point &p) { is>>p.x>>p.y;return is; } +ostream &operator<<(ostream &os, const Point &p) { os<<"("< ps; + vector>> list; + RandomBallCover(vector ps) : ps(ps) { + int n = ps.size(), sqrtn = sqrt(n + 0.5); + vector idx(n); + iota(all(idx), 0); + random_shuffle(all(idx)); + for (int i = 0; i < sqrtn; ++i) + list.push_back({make_pair(0.0, idx[i])}); + for (int i = sqrtn; i < n; ++i) { + Real nearest = 1.0/0.0; + int id; + for (int j = 0; j < sqrtn; ++j) { + Real d = dist(ps[list[j][0].snd], ps[idx[i]]); + if (nearest > d) { + nearest = d; + id = j; + } + } + list[id].push_back({nearest, idx[i]}); + } + for (int i = 0; i < list.size(); ++i) + sort(all(list[i])); + } + int nearestNeighbor(Point p) { + vector dis(list.size()), rem(list.size()); + vector cand(list.size()); + Real best = 1.0/0.0; + int id; + for (int i = 0; i < list.size(); ++i) { + dis[i] = dist(p, ps[list[i][0].snd]); + if (dis[i] < best) { + best = dis[i]; + id = list[i][0].snd; + } + cand[i] = i; + } + sort(all(cand), [&](int i, int j) { return dis[i] < dis[j]; }); + for (int i: cand) { + for (int k = list[i].size()-1; k >= 0; --k) { + if (best <= dis[i] - list[i][k].fst) break; + int j = list[i][k].snd; + Real d = dist(p, ps[j]); + if (d < best) { + best = d; + id = j; + } + } + } + return id; + } + int nearestNeighborNaive(Point p) { + int id = 0; + for (int i = 0; i < ps.size(); ++i) + if (dist(p, ps[id]) > dist(p, ps[i])) id = i; + return id; + } +}; + + +// for comparison +// Kd-Tree for k = 2 +struct KdTree { + struct Node { + int id; + Node *left, *right; + } *root = 0; + vector ps; + KdTree(vector ps) : ps(ps) { + int idx[ps.size()]; + iota(idx, idx+ps.size(), 0); + root = build<0>(idx, idx+ps.size()); + } + template + Node *build(int *l, int *r) { + if (l - r >= 0) return 0; + auto comp = [&](int i, int j) { + if (d == 0) return ps[i].x < ps[j].x; + if (d == 1) return ps[i].y < ps[j].y; + }; + int *m = l + (r-l)/2; + nth_element(l, m, r, comp); + return new Node({*m, build(l,m), build(m+1,r)}); + } + template + void nearestNeighborSearchRec(Node *x, Point p, pair &ub) { + if (!x) return; + Point q = p - ps[x->id]; + Real r = norm(q), w; + if (r < ub.fst) ub = {r, x->id}; + if (d == 0) w = q.x; + else w = q.y; + Node *fst = x->left, *snd = x->right; + if (w > 0) swap(fst, snd); + nearestNeighborSearchRec(fst, p, ub); + if (ub.fst > abs(w)) nearestNeighborSearchRec(snd, p, ub); + } + int nearestNeighbor(Point p) { + pair ub(1.0/0.0, -1); + nearestNeighborSearchRec<0>(root, p, ub); + return ub.snd; + } +}; + +int main() { + int n = 10000; + vector ps; + for (int i = 0; i < n; ++i) { + Real x = rand() % n; + Real y = rand() % n; + ps.push_back({x, y}); + } + RandomBallCover X(ps); + KdTree T(ps); + double t1 = 0, t2 = 0; + for (int i = 0; i < n; ++i) { + Real x = rand() % n; + Real y = rand() % n; + Point p = {x, y}; + tick(); + int j = X.nearestNeighbor(p); + t1 += tick(); + int k = T.nearestNeighbor(p); + t2 += tick(); + assert(sign(norm(p - ps[j]) - norm(p - ps[k])) == 0); + } + cout << t1 << " " << t2 << endl; +} diff --git a/geometry/segment_arrangement.cc b/geometry/segment_arrangement.cc new file mode 100644 index 0000000..ebdd923 --- /dev/null +++ b/geometry/segment_arrangement.cc @@ -0,0 +1,361 @@ +// +// Segment Arrangement (Bentley-Ottman's Plane-Sweep) +// +// Description: +// Given a set of segments, it finds the all intersections of the +// segments and construct the graph structure. By the plane-sweep +// with the balanced binary search tree, it runs in O(k log n) +// time, where k is the size of output. +// +// Complexity: +// O(k log n), where k is the size of output. +// +// Verified: +// AOJ 1226 +// AOJ 2448 +// +// References: +// CGAA +// + +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +using Real = double; +const Real EPS = 1e-8; +int sign(Real x) { return (x > EPS) - (x < -EPS); } +struct Point { + Real x, y; + Point &operator+=(Point p) { x += p.x; y += p.y; return *this; } + Point &operator*=(Real a) { x *= a; y *= a; return *this; } + Point operator+() const { return {+x, +y}; } + Point operator-() const { return {-x, -y}; } + + Point &operator-=(Point p) { return *this += -p; } + Point &operator/=(Real a) { return *this *= 1/a; } +}; +Point operator+(Point p, Point q) { return p += q; } +Point operator-(Point p, Point q) { return p -= q; } +Point operator*(Real a, Point p) { return p *= a; } +Point operator*(Point p, Real a) { return p *= a; } +Point operator/(Point p, Real a) { return p /= a; } + +int compare(Point p, Point q) { + int s = sign(p.x - q.x); + return s ? s : sign(p.y - q.y); +} +bool operator==(Point p, Point q) { return compare(p,q)==0; } +bool operator!=(Point p, Point q) { return compare(p,q)!=0; } +bool operator<=(Point p, Point q) { return compare(p,q)<=0; } +bool operator>=(Point p, Point q) { return compare(p,q)>=0; } +bool operator<(Point p, Point q) { return compare(p,q)<0; } +bool operator>(Point p, Point q) { return compare(p,q)>0; } + +Real dot(Point p, Point q) { return p.x*q.x+p.y*q.y; } +Real cross(Point p, Point q) { return p.x*q.y-p.y*q.x; } // left turn > 0 +Real norm2(Point p) { return dot(p,p); } +Point orth(Point p) { return {-p.y, p.x}; } +Real norm(Point p) { return sqrt(dot(p,p)); } +Real arg(Point p) { return atan2(p.y, p.x); } +Real arg(Point p, Point q){ return atan2(cross(p,q), dot(p,q)); } + +istream &operator>>(istream &is, Point &p) { is>>p.x>>p.y;return is; } +ostream &operator<<(ostream &os, const Point &p) { os<<"("< intersect(Segment s, Segment t) { + auto a = cross(s.q - s.p, t.q - t.p); + auto b = cross(t.p - s.p, t.q - t.p); + auto c = cross(s.q - s.p, s.p - t.p); + if (a < 0) { a = -a; b = -b; c = -c; } + if (sign(b) < 0 || sign(a-b) < 0 || + sign(c) < 0 || sign(a-c) < 0) return {}; // disjoint + if (sign(a) != 0) return {s.p + b/a*(s.q - s.p)}; // properly crossing + vector ps; // same line + auto insert_if_possible = [&](Point p) { + for (auto q: ps) if (sign(dot(p-q, p-q)) == 0) return; + ps.push_back(p); + }; + if (sign(dot(s.p-t.p, s.q-t.p)) <= 0) insert_if_possible(t.p); + if (sign(dot(s.p-t.q, s.q-t.q)) <= 0) insert_if_possible(t.q); + if (sign(dot(t.p-s.p, t.q-s.p)) <= 0) insert_if_possible(s.p); + if (sign(dot(t.p-s.q, t.q-s.q)) <= 0) insert_if_possible(s.q); + return ps; +} + + +// +// each vertex has one incident edge +// each edge has the origin vertex, twin edge, and the left face. +// two edges (prev, next) representing a list of edges surrounding a face. +// +struct DoublyConnectedEdgeList { + vector incident_edge; // vertex + vector origin, twin, prev, next, incident_face; // edge + vector component; // face + int edges() const { return origin.size(); } + int vertices() const { return incident_edge.size(); } + int faces() const { return component.size(); } + + vector point; + int newVertex(Point p, int e = -1) { + point.push_back(p); + incident_edge.push_back(e); + return vertices()-1; + } + int newEdge(int o = -1) { + origin.push_back(o); + twin.push_back(-1); + prev.push_back(-1); + next.push_back(-1); + incident_face.push_back(-1); + return edges()-1; + } + int newFace(int e = -1) { + component.push_back(e); + return component.size()-1; + } + void completeFaces() { + component.clear(); + fill(all(incident_face), -1); + for (int e = 0; e < edges(); ++e) { + if (incident_face[e] >= 0) continue; + int f = newFace(e), x = e; + do { + incident_face[x] = f; + x = next[x]; + } while (x != e); + } + } +}; + +struct Arrangement : DoublyConnectedEdgeList { + vector segs; + + unordered_map> adj; // (Vertex, Vertex) -> Edge + + struct Node { // Sweep-Line Structure (RBST) + int index, size = 1; + Node *left = 0, *right = 0; + } *root = 0; + vector ns; + Node *update(Node *x) { + if (x) { + x->size = 1; + if (x->left) x->size += x->left->size; + if (x->right) x->size += x->right->size; + } + return x; + } + Node *merge(Node *x, Node *y) { + if (!x) return y; + if (!y) return x; + if (rand() % (x->size + y->size) < x->size) { + x->right = merge(x->right, y); + return update(x); + } else { + y->left = merge(x, y->left); + return update(y); + } + } + template // 3-way split: cond(x) < 0, cond(x) == 0, cond(x) > 0 + tuple split(Node *x, C cond) { + if (!x) return make_tuple(x,x,x); + if (cond(x) == 0) { + auto a = split(x->left, cond); + auto b = split(x->right, cond); + x->left = x->right = 0; update(x); + get<1>(a) = merge(merge(get<1>(a), x), get<1>(b)); + get<2>(a) = get<2>(b); + return a; + } + if (cond(x) < 0) { + auto a = split(x->right, cond); + x->right = 0; update(x); + get<0>(a) = merge(x, get<0>(a)); + return a; + } + if (cond(x) > 0) { + auto a = split(x->left, cond); + x->left = 0; update(x); + get<2>(a) = merge(get<2>(a), x); + return a; + } + } + Node *leftmost(Node *x) { while (x && x->left) x = x->left; return x; } + Node *rightmost(Node *x) { while (x && x->right) x = x->right; return x; } + template + void process(Node *x, F func) { + if (!x) return; + process(x->left, func); + func(x); + process(x->right, func); + } + Arrangement(vector segs_) : segs(segs_) { + ns.resize(segs.size()); + set events; + map> L, R; + + for (int i = 0; i < segs.size(); ++i) { + if (segs[i].q < segs[i].p) swap(segs[i].p, segs[i].q); + events.insert(segs[i].p); + events.insert(segs[i].q); + L[segs[i].p].insert(i); + R[segs[i].q].insert(i); + ns[i].index = i; + } + vector last(segs.size(), -1); + + while (!events.empty()) { + const Point p = *events.begin(); + events.erase(events.begin()); + int u = newVertex(p); + + auto cond = [&](Node *x) { + const Segment &s = segs[x->index]; + if (sign(s.q.x - s.p.x) == 0) { + if (sign(p.y - s.p.y) < 0) return -1; + if (sign(s.q.y - p.y) < 0) return +1; + return 0; + } + return -sign(cross(s.p - p, s.q - p)); + }; + auto z = split(root, cond); + vector inserter; + process(get<1>(z), [&](Node *x) { + int v = last[x->index]; + if (!adj[u].count(v)) { + int e = newEdge(u), f = newEdge(v); + adj[u][v] = e; + adj[v][u] = f; + twin[e] = f; + twin[f] = e; + } + if (!R[p].count(x->index)) + inserter.push_back(x); + }); + for (int i: L[p]) + if (!R[p].count(i)) + inserter.push_back(&ns[i]); + + sort(all(inserter), [&](Node *x, Node *y) { + const Segment &s = segs[x->index], &t = segs[y->index]; + return sign(cross(s.q - s.p, t.q - t.p)) >= 0; + }); + auto addEvent = [&](Node *x, Node *y) { + if (!x || !y) return; + vector ps = intersect(segs[x->index], segs[y->index]); + for (Point q: ps) + if (p < q) events.insert(q); + }; + if (inserter.empty()) { + addEvent(rightmost(get<0>(z)), leftmost(get<2>(z))); + } else { + addEvent(rightmost(get<0>(z)), inserter[0]); + addEvent(leftmost(get<2>(z)), inserter.back()); + } + root = 0; + for (int i = 0; i < inserter.size(); ++i) { + last[inserter[i]->index] = u; + inserter[i]->left = inserter[i]->right = 0; + root = merge(root, update(inserter[i])); + } + root = merge(merge(get<0>(z), root), get<2>(z)); + } + vector next_inc(next.size()), prev_inc(prev.size()); + for (auto &pp: adj) { + int u = pp.fst; + vector es; + for (auto z: pp.snd) es.push_back(z.snd); + sort(all(es), [&](int e, int f) { // polar sort + auto quad = [](Point p) { + for (int i = 1; i <= 4; ++i, swap(p.x = -p.x, p.y)) + if (p.x > 0 && p.y >= 0) return i; + return 0; + }; + const Point p = point[origin[twin[e]]] - point[origin[e]]; + const Point q = point[origin[twin[f]]] - point[origin[f]]; + if (quad(p) != quad(q)) return quad(p) < quad(q); + return sign(cross(p, q)) > 0; + }); + incident_edge[u] = es[0]; + for (int i = 0; i < es.size(); ++i) { + int j = (i + 1) % es.size(); + next_inc[es[i]] = es[j]; + prev_inc[es[j]] = es[i]; + } + } + for (int e = 0; e < edges(); ++e) { + next[e] = prev_inc[twin[e]]; + prev[e] = twin[next_inc[e]]; + } + } +}; +void AOJ1226() { + for (int n; ~scanf("%d", &n) && n; ) { + vector> a(4, vector(n)); + for (int k = 0; k < 4; ++k) + for (int i = 0; i < n; ++i) + scanf("%lf", &a[k][i]); + + vector ss = { + {{0,0},{0,1}}, + {{0,1},{1,1}}, + {{1,1},{1,0}}, + {{1,0},{0,0}} + }; + for (int i = 0; i < n; ++i) { + ss.push_back({{a[0][i],0},{a[1][i],1}}); + ss.push_back({{0,a[2][i]},{1,a[3][i]}}); + } + Arrangement arr(ss); + arr.completeFaces(); + + double result = 0; + for (int f = 0; f < arr.faces(); ++f) { + double area = 0; + int e = arr.component[f]; + do { + area += cross(arr.point[arr.origin[e]], + arr.point[arr.origin[arr.twin[e]]]), + e = arr.next[e]; + } while (e != arr.component[f]); + result = max(result, area); + } + printf("%.6f\n", result/2); + } +} +void AOJ2448() { + int n; scanf("%d", &n); + vector ps(n); + for (int i = 0; i < n; ++i) + scanf("%lf %lf", &ps[i].x, &ps[i].y); + vector ss; + for (int i = 0; i+1 < n; ++i) + ss.push_back({ps[i], ps[i+1]}); + Arrangement arr(ss); + arr.completeFaces(); + + double result = 0; + for (int f = 0; f < arr.faces(); ++f) { + double area = 0; + int e = arr.component[f]; + do { + area += cross(arr.point[arr.origin[e]], + arr.point[arr.origin[arr.twin[e]]]), + e = arr.next[e]; + } while (e != arr.component[f]); + if (area > 0) result += area; + } + printf("%.12f\n", result/2); +} + +int main() { + AOJ2448(); + //AOJ1226(); +} diff --git a/graph/articulation_points.cc b/graph/articulation_points.cc index 07c5dd0..62b6638 100644 --- a/graph/articulation_points.cc +++ b/graph/articulation_points.cc @@ -1,5 +1,5 @@ // -// Articulation points / Biconnected components +// Block-Cut Tree (Articulation points / Biconnected components) // // Description: // Let G = (V, E). If G-v is disconnected, v in V is said to @@ -7,25 +7,19 @@ // it is said to be biconnected. // // A biconnected component is a maximal biconnected subgraph. -// The algorithm finds all articulation points and biconnected -// components. +// The algorithm finds all articulation points and biconnected +// components. It can be obtained by the Hopcroft-Tarjan DFS. // -// The most important fact is that by contracting biconnected -// components we obtain a tree, which is called the block tree. -// -// -// Algorithm: -// Hopcroft-Tarjan's DFS based algorithm. -// -// Single DFS finds a block tree rooted from the component -// that contains the specified root. +// We maintain the biconnected component decomposition by the +// block tree whose vertices are the blocks and the articulation +// points. By contracting the graph by the articulation points, +// we obtain the intersection graph of the blocks. // // Complexity: // O(n + m). // // Verified: -// SPOJ 14956: Submerging Island (articulation point) -// POJ 2942: Knights of the Round Table (biconnected components) +// AOJ_GRL_3_A (articulation point) // // References: // J. Hopcroft and R. E. Tarjan (1973): @@ -33,68 +27,107 @@ // Communications of the ACM, vol.16, no.6, pp.372-378. // -#include -#include -#include -#include -#include -#include +// g++ -std=c++17 -O3 -fmax-errors=1 -fsanitize=undefined +#include using namespace std; #define fst first #define snd second #define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } -struct graph { +struct Graph { int n; vector> adj; - graph(int n) : n(n), adj(n) { } - void add_edge(int src, int dst) { - adj[src].push_back(dst); - adj[dst].push_back(src); + Graph(int n) : n(n), adj(n) { } + void addEdge(int u, int v) { + adj[u].push_back(v); + adj[v].push_back(u); } +}; - void biconnected_components() { - vector num(n), low(n), S; - unordered_set arts; +// +// bcc.n-bcc.block.size() is the number of articulation points +// index[u] is the corresponding node in the block-cut tree. +// Here, if u in block[k] then +// if u is an articulation point, k in adj[index[u]] +// otherwise, index[u] = k +// +struct BiconnectedComponents : Graph { + vector is_articulation, index; + vector> block; - function dfs = [&](int p, int u, int &t) { - num[u] = low[u] = ++t; - S.push_back(u); - for (int v: adj[u]) { - if (v == p) continue; - if (num[v] == 0) { - dfs(u, v, t); + BiconnectedComponents(Graph g) : Graph(0) { + vector low(g.n), num(g.n), cur(g.n), par(g.n, -1), path; + is_articulation.resize(g.n); + for (int s = 0; s < g.n; ++s) { + if (num[s]) continue; + int time = 0; + vector stack = {s}; + while (!stack.empty()) { + int u = stack.back(); + if (cur[u] == 0) { + low[u] = num[u] = ++time; + path.push_back(u); + } + if (cur[u] == g.adj[u].size()) { + stack.pop_back(); + } else if (cur[u] >= 0) { + int v = g.adj[u][cur[u]++]; + if (num[v] == 0) { + cur[u] = ~cur[u]; + stack.push_back(v); + } else if (v != par[u]) { + low[u] = min(low[u], num[v]); + } + } else { + cur[u] = ~cur[u]; + int v = g.adj[u][cur[u]-1]; low[u] = min(low[u], low[v]); if (num[u] <= low[v]) { - if (num[u] != 1 || num[v] > 2) { - // here, u is an articulation point if - // (a). u is non-root - // (b). u is root with two more children - } - vector C = {u}; // biconnected component - while (C.back() != v) { - C.push_back(S.back()); - S.pop_back(); + is_articulation[u] = (num[u] > 1 || num[v] > 2); + block.push_back({u}); + while (block.back().back() != v) { + block.back().push_back(path.back()); + path.pop_back(); } } - } else low[u] = min(low[u], num[v]); + } } - }; - for (int u = 0, t; u < n; ++u) - if (!num[u]) dfs(-1, u, t = 0); - cout << arts.size() << endl; + } + index.resize(g.n); // make a block tree + n = block.size(); + for (int u = 0; u < g.n; ++u) + if (is_articulation[u]) index[u] = n++; + adj.resize(n); + for (int k = 0; k < block.size(); ++k) { + for (int u: block[k]) { + if (!is_articulation[u]) index[u] = k; + else addEdge(k, index[u]); + } + } } }; -int main() { - for (int n, m; ~scanf("%d %d", &n, &m) && n; ) { - graph g(n); - for (int i = 0; i < m; ++i) { - int u, v; scanf("%d %d", &u, &v); - g.add_edge(u-1, v-1); - } - g.biconnected_components(); +void AOJ_GRL_3_A() { + int n, m; + scanf("%d %d", &n, &m); + Graph g(n); + for (int i = 0; i < m; ++i) { + int u, v; scanf("%d %d", &u, &v); + g.addEdge(u, v); } + BiconnectedComponents bcc(g); + for (int u = 0; u < g.n; ++u) + if (bcc.is_articulation[u]) cout << u << endl; } + +int main() { + AOJ_GRL_3_A(); + //SPOJ_SUBMERGE(); + //test(); + /* + */ +} + diff --git a/graph/bridge.cc b/graph/bridge.cc new file mode 100644 index 0000000..de6cdba --- /dev/null +++ b/graph/bridge.cc @@ -0,0 +1,149 @@ +// +// Bridge-Block Tree (Bridge / Two-edge connected component) +// +// Description: +// Let G = (V, E). e in E is said to be a cut edge if G-e is +// disconnected If G has no cut edges, it is said to be two-edge +// connected. +// A two-edge connected component is a maximal two-edge connected +// subgraph. The algorithm finds all bridges with the two-edge +// connected components. +// +// We maintain the two-edge connected component decomposition by +// a bridge-block tree whose nodes are the two-edge connected +// components. +// +// +// Complexity: +// O(n + m). +// +// Verified: +// +// References: +// + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +struct Graph { + int n; + vector> adj; + Graph(int n) : n(n), adj(n) { } + void addEdge(int src, int dst) { + adj[src].push_back(dst); + adj[dst].push_back(src); + } +}; + +struct BridgeBlockTree : Graph { + vector index; // index[u] is the block index containing u + vector> block; // u in block[k] <=> index[u] == k + + BridgeBlockTree(Graph g) : Graph(0) { + index.assign(g.n, -1); + vector num(g.n), par(g.n,-1), cur(g.n); + + for (int s = 0; s < g.n; ++s) { + if (num[s]) continue; + int time = 0; + vector snum, path, stack = {s}; + while (!stack.empty()) { + int u = stack.back(); + if (cur[u] == 0) { + num[u] = ++time; + path.push_back(u); + snum.push_back(num[u]); + } + if (cur[u] == g.adj[u].size()) { + if (num[u] == snum.back()) { + snum.pop_back(); + block.push_back({}); + while (1) { + int w = path.back(); path.pop_back(); + block.back().push_back(w); + index[w] = block.size()-1; + if (u == w) break; + } + } + stack.pop_back(); + } else { + int v = g.adj[u][cur[u]++]; + if (!num[v]) { + par[v] = u; + stack.push_back(v); + } else if (v != par[u] && index[v] < 0) { + while (snum.back() > num[v]) snum.pop_back(); + } + } + } + } + n = block.size(); + adj.resize(n); + for (int u = 0; u < g.n; ++u) + if (par[u] >= 0 && index[u] != index[par[u]]) + addEdge(index[u], index[par[u]]); + } +}; + + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} + +int main() { + Graph g(6); + g.addEdge(0, 1); + g.addEdge(1, 2); + g.addEdge(2, 0); + g.addEdge(2, 3); + g.addEdge(3, 4); + g.addEdge(4, 5); + g.addEdge(5, 3); + BridgeBlockTree t(g); + + cout << t.n << endl; + for (int u = 0; u < t.n; ++u) { + for (int v: t.adj[u]) { + cout << u << " " << v << endl; + } + } + + for (auto B: t.block) { + for (int u: B) { + cout << u << " "; + } + cout << endl; + } + for (int u = 0; u < 6; ++u) { + cout << t.index[u] << " "; + } + cout << endl; + + //g.bridgeless_component(); + /* + for (int n, m; ~scanf("%d %d", &n, &m) && n; ) { + graph g(n); + for (int i = 0; i < m; ++i) { + int u, v; scanf("%d %d", &u, &v); + g.add_edge(u-1, v-1); + } + g.biconnected_components(); + } + */ +} diff --git a/graph/chromatic_number.cc b/graph/chromatic_number.cc new file mode 100644 index 0000000..aef4837 --- /dev/null +++ b/graph/chromatic_number.cc @@ -0,0 +1,96 @@ +// +// Exact Algorithm for Chromatic Number +// +// Description: +// +// A vertex coloring is an assignment of colors to the vertices +// such that no adjacent vertices have a same color. The smallest +// number of colors for a vertex coloring is called the chromatic +// number. Computing the chromatic number is NP-hard. +// +// We can compute the chromatic number by the inclusion-exlusion +// principle. The complexity is O(poly(n) 2^n). The following +// implementation runs in O(n 2^n) but is a Monte-Carlo algorithm +// since it takes modulos to avoid multiprecision numbers. +// +// Complexity: +// +// O(n 2^n) +// +// References: +// +// Andreas Bjorklund and Thore Husfeldt (2006): +// "Inclusion--Exclusion Algorithms for Counting Set Partitions." +// in Proceedings of the 47th Annual Symposium on Foundations of +// Computer Science, pp. 575--582. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct Graph { + int n; + vector> adj; + Graph(int n) : n(n), adj(n) { } + void addEdge(int u, int v) { + adj[u].push_back(v); + adj[v].push_back(u); + } +}; + +int chromaticNumber(Graph g) { + const int N = 1 << g.n; + vector nbh(g.n); + for (int u = 0; u < g.n; ++u) + for (int v: g.adj[u]) + nbh[u] |= (1 << v); + + int ans = g.n; + for (int d: {7}) { // ,11,21,33,87,93}) { + long long mod = 1e9 + d; + vector ind(N), aux(N, 1); + ind[0] = 1; + for (int S = 1; S < N; ++S) { + int u = __builtin_ctz(S); + ind[S] = ind[S^(1<> 1); // gray-code + aux[S] = (aux[S] * ind[S]) % mod; + chi += (i & 1) ? aux[S] : -aux[S]; + } + if (chi % mod) ans = k; + } + } + return ans; +} + +int main() { + int n = 6; + Graph g(n); + g.addEdge(0,1); + g.addEdge(1,2); + g.addEdge(2,3); + g.addEdge(0,2); + g.addEdge(3,4); + g.addEdge(4,5); + g.addEdge(5,0); + // 0 + // 1 5 + // + // 2 4 + // 3 + /* + for (int i = 0; i < n; ++i) + for (int j = 0; j < i; ++j) + g.addEdge(i, j); + */ + cout << chromaticNumber(g) << endl; +} diff --git a/graph/dijkstra.cc b/graph/dijkstra.cc new file mode 100644 index 0000000..dfa4510 --- /dev/null +++ b/graph/dijkstra.cc @@ -0,0 +1,317 @@ +// +// Dijkstra's Single Source Shortest Path +// +// Description: +// +// Dijkstra algorithm finds a single source shortest path on +// a nonnegative weighted graph. +// It implements two algorithms with two data structures. +// (1) standard dijkstra with standard heap +// (2) bidirectional dijkstra with standard heap +// (3) standard dijkstra with radix heap +// (4) bidirectional dijkstra with radix heap +// +// For a simple test (see the code), we observe that +// Binomial,Unidirectional 14.74[s] +// Binomial Bidirectional 0.52[s] +// Radix,Unidirectional 4.90[s] +// Radix,Bidirectional 0.31[s] +// +// Complexity: +// +// O(m log n) for binomial heap +// O(m) for radix heap +// +// Verify: +// +// SPOJ_SHPATH (bidirectional search) +// +// +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +template +struct WeightedGraph { + struct Edge { + int to; + Weight weight; + }; + int n; + vector> adj, rdj; + WeightedGraph(int n) : n(n), adj(n), rdj(n) { } + void addEdge(int u, int v, Weight w) { + adj[u].push_back({v, w}); + rdj[v].push_back({u, w}); // can be omitted for the standard dijkstra + } +}; +template +struct ShortestPath { + WeightedGraph g; + ShortestPath(WeightedGraph g) : g(g), dist(g.n), prev(g.n) { } + + vector dist; + vector prev; + void solve(int s) { + prev.assign(g.n,-1); + dist.assign(g.n,-1); dist[s] = 0; + + using Node = pair; + priority_queue, greater> que; + que.push({0,s}); + while (!que.empty()) { + auto d = que.top().fst; + auto u = que.top().snd; + que.pop(); + if (dist[u] < d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u]+w) continue; + dist[v] = dist[u] + w; + prev[v] = u; + que.push({dist[v], v}); + } + } + } + int solve(int s, int t) { + if (s == t) return dist[s] = 0; + fill(all(dist), -1); dist[s] = 0; + vector drev(g.n, -1); drev[t] = 0; + + using Node = pair; + priority_queue, greater> qs, qt; + qs.push({0,s}); qt.push({0,t}); + int mu = -1; + while (!qs.empty() && !qt.empty()) { + if (mu >= 0 && qs.top().fst + qt.top().fst >= mu) break; + if (qs.top().fst <= qt.top().fst) { + auto d = qs.top().fst; + auto u = qs.top().snd; + qs.pop(); + if (dist[u] > d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u] + w) continue; + dist[v] = dist[u] + w; + qs.push({dist[v], v}); + if (drev[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } else { + auto d = qt.top().fst; + auto u = qt.top().snd; + qt.pop(); + if (drev[u] > d) continue; + for (auto e: g.rdj[u]) { + auto v = e.to; + auto w = e.weight; + if (drev[v] >= 0 && drev[v] <= drev[u] + w) continue; + drev[v] = drev[u] + w; + qt.push({drev[v], v}); + if (dist[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } + } + return mu; + } +}; + + +// +// Dijkstra with Radix Heap +// +template +struct RadixHeap { + using uint = uint32_t; // fix bit size + static int bsr(uint a) { return a ? 31 - __builtin_clz(a) : -1; } + uint size, last; + vector> v[33]; + RadixHeap() : size(0), last(0) { } + + bool empty() const { return size == 0; } + void aux(pair p) { v[bsr(p.fst^last)+1].push_back(p); } + pair top() { + if (v[0].empty()) { + int i = 1; + while (v[i].empty()) ++i; + last = min_element(all(v[i]))->fst; + for (auto p: v[i]) aux(p); + v[i].clear(); + } + return v[0].back(); + } + void push(uint key, T value) { ++size; aux({key, value}); } + void pop() { --size; top(); v[0].pop_back(); } +}; +template <> +struct ShortestPath { + using Weight = int; + WeightedGraph g; + + vector dist; + vector prev; + ShortestPath(WeightedGraph g) : g(g), dist(g.n), prev(g.n) { } + + void solve(int s) { + fill(all(prev), -1); + fill(all(dist), -1); dist[s] = 0; + + RadixHeap que; + que.push(0,s); + while (!que.empty()) { + auto d = que.top().fst; + auto u = que.top().snd; + que.pop(); + if (dist[u] < d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u]+w) continue; + dist[v] = dist[u] + w; + prev[v] = u; + que.push(dist[v], v); + } + } + } + // Bidirectional Dijkstra + int solve(int s, int t) { + if (s == t) return dist[s] = 0; + + fill(all(dist), -1); dist[s] = 0; + vector drev(g.n, -1); drev[t] = 0; + RadixHeap qs, qt; + qs.push(0,s); qt.push(0,t); + int mu = -1; + while (!qs.empty() && !qt.empty()) { + if (mu >= 0 && qs.top().fst + qt.top().fst >= mu) break; + if (qs.top().fst <= qt.top().fst) { + auto d = qs.top().fst; + auto u = qs.top().snd; + qs.pop(); + if (dist[u] > d) continue; + for (auto e: g.adj[u]) { + auto v = e.to; + auto w = e.weight; + if (dist[v] >= 0 && dist[v] <= dist[u] + w) continue; + dist[v] = dist[u] + w; + qs.push(dist[v], v); + if (drev[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } else { + auto d = qt.top().fst; + auto u = qt.top().snd; + qt.pop(); + if (drev[u] > d) continue; + for (auto e: g.rdj[u]) { + auto v = e.to; + auto w = e.weight; + if (drev[v] >= 0 && drev[v] <= drev[u] + w) continue; + drev[v] = drev[u] + w; + qt.push(drev[v], v); + if (dist[v] >= 0) { + auto nu = dist[v] + drev[v]; + if (mu < 0 || mu > nu) mu = nu; + } + } + } + } + return mu; + } +}; + +void SPOJ_SHPATH() { + int ncase; scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + int n; + scanf("%d", &n); + WeightedGraph g(n); + map id; + for (int u = 0; u < n; ++u) { + char name[1024]; + scanf("%s", name); + id[name] = u; + int k; + scanf("%d", &k); + for (int j = 0; j < k; ++j) { + int v, d; + scanf("%d %d", &v, &d); + g.addEdge(u, v-1, d); + } + } + ShortestPath solver(g); + int k; + scanf("%d", &k); + for (int i = 0; i < k; ++i) { + char s[1024], t[1024]; + scanf("%s %s", s, t); + printf("%d\n", solver.solve(id[s], id[t])); + } + } +} + +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; +} +int test() { + int n = 5000; + WeightedGraph g(n); + for (int u = 0; u < n; ++u) { + int d = 1 + rand() % 30; + unordered_set N; + while (N.size() < d) { + int v = rand() % n; + if (u != v) N.insert(v); + } + for (auto v: N) { + int w = 1 + rand() % 10; + g.addEdge(u, v, w); + } + } + ShortestPath solver(g); + double t = 0; + for (int u = 0; u < n; ++u) { + int v = rand() % n; + tick(); + solver.solve(u); + int b = solver.dist[v]; + t += tick(); + } + cout << t << endl; + return true; +} + +int main() { + test(); +// SPOJ_SHPATH(); + /* + WeightedGraph g(3); + g.addEdge(0,1,10); + g.addEdge(0,2,20); + + ShortestPath solver(g); + solver.solve(0); + for (int u = 0; u < g.n; ++u) { + cout << solver.dist[u] << " "; + } + cout << endl; + */ +} diff --git a/graph/gabow_edmonds.cc b/graph/gabow_edmonds.cc index 2c245b2..455b9a4 100644 --- a/graph/gabow_edmonds.cc +++ b/graph/gabow_edmonds.cc @@ -2,124 +2,196 @@ // General Graph Matching (Gabow-Edmonds) // // Description: -// It computes a maximum matching in a general graph. +// +// For a graph G = (V, E), a matching M is a set of edges +// such that any vertex is contained in M at most once. +// The matching with maximum cardinality is computed by +// the Edmonds blossom algorithm. +// +// This implementation is the Gabow's simplified version +// with the lazy update technique to improve the complexity +// in sparse graphs. +// +// +// Complexity: +// +// O(n m log n) // -// Algorithm: -// Gabow's simplified version of Edmonds' blossom algorithm. -// -// Comlexity: -// O(n^3) // // Verified: -// LA3820, LA4130 +// +// SPOJ ADABLOOM +// // // References: // H.Gabow (1976): // An efficient implementation of Edmonds' algorithm for maximum matching on graphs. // Journal of the ACM, vol.23, no.2, pp.221-234. // +// http://min-25.hatenablog.com/entry/2016/11/21/222625 +// +// -#include -#include -#include -#include -#include -#include -#include -#include - +// g++ -std=c++17 -O3 -fmax-errors=1 -fsanitize=undefined +#include using namespace std; -struct graph { +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +struct Graph { int n; - vector> adj; - graph(int n) : n(n), adj(n) { }; - void add_edge(int x, int y) { - adj[x].push_back(y); - adj[y].push_back(x); + vector< vector > adj; + Graph(int n) : n(n), adj(n) { }; + void addEdge(int u, int v) { + adj[u].push_back(v); + adj[v].push_back(u); } - queue Q; - vector label, mate, cycle; - void rematch(int x, int y) { - int m = mate[x]; mate[x] = y; - if (mate[m] == x) { - if (label[x] < n) { - rematch(mate[m] = label[x], m); + + vector mate; + int maximumMatching() { + mate.assign(n+1, n); + vector first(n+1, n), que(n); + vector> label(n+1, make_pair(-1,-1)); + int head = 0, tail = 0; + + function rematch = [&](int v, int w) { + int t = mate[v]; mate[v] = w; + if (mate[t] != v) return; + if (label[v].snd == -1) { + mate[t] = label[v].fst; + rematch(mate[t], t); } else { - int s = (label[x]-n)/n, t = (label[x]-n)%n; - rematch(s, t); rematch(t, s); + int x, y; tie(x, y) = label[v]; + rematch(x, y); rematch(y, x); } - } - } - void traverse(int x) { - vector save = mate; - rematch(x, x); - for (int u = 0; u < n; ++u) - if (mate[u] != save[u]) cycle[u] ^= 1; - save.swap(mate); - } - void relabel(int x, int y) { - cycle = vector(n, 0); - traverse(x); - traverse(y); - for (int u = 0; u < n; ++u) { - if (!cycle[u] || label[u] >= 0) continue; - label[u] = n+x+y*n; - Q.push(u); - } - } - int augment(int r) { - label.assign(n, -2); - label[r] = -1; - Q = queue(); Q.push(r); - while (!Q.empty()) { - int x = Q.front(); Q.pop(); - for (int y: adj[x]) { - if (mate[y] < 0 && r != y) { - rematch(mate[y] = x, y); return 1; - } else if (label[y] >= -1) { - relabel(x, y); - } else if (label[mate[y]] < -1) { - label[mate[y]] = x; - Q.push(mate[y]); + }; + auto relabel = [&](int x, int y) { + function findFirst = [&](int u) { + return label[first[u]].fst < 0 ? first[u] : + first[u] = findFirst(first[u]); + }; + int r = findFirst(x), s = findFirst(y); + if (r == s) return; + auto h = make_pair(~x, y); + label[r] = label[s] = h; + int join; + while (1) { + if (s != n) swap(r, s); + r = findFirst(label[mate[r]].fst); + if (label[r] == h) { + join = r; + break; + } else { + label[r] = h; } } - } - return 0; - } - int maximum_matching() { - mate.assign(n, -2); + for (int v: {first[x], first[y]}) { + for (; v != join; v = first[label[mate[v]].fst]) { + label[v] = make_pair(x, y); + first[v] = join; + que[tail++] = v; + } + } + }; + auto augment = [&](int u) { + label[u] = make_pair(n, -1); + first[u] = n; + head = tail = 0; + for (que[tail++] = u; head < tail;) { + int x = que[head++]; + for (int y: adj[x]) { + if (mate[y] == n && y != u) { + mate[y] = x; + rematch(x, y); + return true; + } else if (label[y].fst >= 0) { + relabel(x, y); + } else if (label[mate[y]].fst == -1) { + label[mate[y]].fst = x; + first[mate[y]] = y; + que[tail++] = mate[y]; + } + } + } + return false; + }; int matching = 0; - for (int u = 0; u < n; ++u) - if (mate[u] < 0) matching += augment(u); + for (int u = 0; u < n; ++u) { + if (mate[u] < n || !augment(u)) continue; + ++matching; + for (int i = 0; i < tail; ++i) + label[que[i]] = label[mate[que[i]]] = make_pair(-1,-1); + label[n] = make_pair(-1, -1); + } return matching; } }; -int doit() { - int n, m; - scanf("%d %d", &n, &m); - vector v(n); - for (int i = 0; i < n; ++i) { - scanf("%d", &v[i]); +void LA3820() { + int ncase; scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + int n, m; + scanf("%d %d", &n, &m); + vector v(n); + for (int i = 0; i < n; ++i) { + scanf("%d", &v[i]); + } + set S; + for (int i = 0; i < m; ++i) { + int x; + scanf("%d", &x); + S.insert(x); + } + Graph G(n); + for (int i = 0; i < n; ++i) { + for (int j = i+1; j < n; ++j) { + if (S.count(v[i] + v[j])) + G.addEdge(i, j); + } + } + printf("%d\n", G.maximumMatching()); } - set S; +} + +void UOJ79() { + int n, m; cin >> n >> m; + Graph g(n); for (int i = 0; i < m; ++i) { - int x; - scanf("%d", &x); - S.insert(x); + int u, v; + cin >> u >> v; + g.addEdge(u-1, v-1); } - - graph g(n); - for (int i = 0; i < n; ++i) { - for (int j = i+1; j < n; ++j) { - if (S.count(v[i] + v[j])) - g.add_edge(i, j); + cout << g.maximumMatching() << endl; + for (int u = 0; u < n; ++u) { + if (u > 0) cout << " "; + if (g.mate[u] >= n) cout << 0; + else cout << g.mate[u]+1; + } + cout << endl; +} +void SPOJ_ADABLOOM() { + int ncase; scanf("%d", &ncase); + for (int icase; icase < ncase; ++icase) { + int n; scanf("%d", &n); + vector a(n); + for (int i = 0; i < n; ++i) + scanf("%lld", &a[i]); + random_shuffle(all(a)); + Graph g(n); + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + if (a[i] < (a[i] ^ a[j]) && (a[i] ^ a[j]) < a[j]) g.addEdge(i, j); + } } + cout << g.maximumMatching() << endl; } - return g.maximum_matching(); } + int main() { - doit(); + SPOJ_ADABLOOM(); + //UOJ79(); + //LA3820(); } diff --git a/graph/k_shortest_walks.cc b/graph/k_shortest_walks.cc new file mode 100644 index 0000000..d37c038 --- /dev/null +++ b/graph/k_shortest_walks.cc @@ -0,0 +1,181 @@ +// +// K Shortest Walks (Simplified Eppstein) +// +// Description +// +// We are given a weighted graph. The k-shortest walks problem +// seeks k different s-t walks (paths allowing repeated vertices) +// in the increasing order of the lengths. +// +// If we maintain each walks explicitly, it must costs O(k^2 m) time. +// To avoid this complexity, we maintain the walks in a compact format. +// Let us fix a reverse shortest path tree from t. A deviation is an +// edge that is not on the tree. Any walk is represented by a concatenation +// of deviations and paths on the tree. We enumerate all possible +// deviations and use the best-first search to find the k-th solution. +// +// The Eppstein's algorithm maintains the set of deviations by +// the augmented persistent heaps and emurates the best-first search. +// Here, we implemented a simplified version of the Eppstein's algorithm, +// which uses the simple persistent heaps instead of the augmented ones. +// It increases the space from O(m + n log n) to O(m log n). +// +// Complexity: +// +// O(m log m) construction +// O(k log k) for k-th search +// +// Verified: +// +// UTPC2013_10 J K-th Cycle +// +// References: +// +// David Eppstein (1998): +// "Finding the k shortest paths", +// SIAM Journal on computing, vol.28, no.2, pp.652--673. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct Graph { + int n, m = 0; + vector head; // Vertex + vector src, dst, next, prev; // Edge + + using Weight = long long; + vector weight; + Graph(int n) : n(n), head(n, -1) { } + int addEdge(int u, int v, Weight w) { + next.push_back(head[u]); + src.push_back(u); + dst.push_back(v); + weight.push_back(w); + return head[u] = m++; + } +}; +constexpr Graph::Weight INF = 1e15; + +struct KShortestWalks { + Graph g; + vector dist; + vector tree, order; + void reverseDijkstra(int t) { + vector> adj(g.n); + for (int u = 0; u < g.n; ++u) + for (int e = g.head[u]; e >= 0; e = g.next[e]) + adj[g.dst[e]].push_back(e); + dist.assign(g.n, INF); + tree.assign(g.n, ~g.m); + using Node = tuple; + priority_queue, greater> que; + que.push(make_tuple(0, t)); + dist[t] = 0; + while (!que.empty()) { + int u = get<1>(que.top()); que.pop(); + if (tree[u] >= 0) continue; + tree[u] = ~tree[u]; + order.push_back(u); + for (int e: adj[u]) { + int v = g.src[e]; + if (dist[v] > dist[u] + g.weight[e]) { + tree[v] = ~e; + dist[v] = dist[u] + g.weight[e]; + que.push(Node(dist[v], v)); + } + } + } + } + struct Node { // Persistent Heap (Leftist Heap) + int e; + Graph::Weight delta; + Node *left = 0, *right = 0; + int rnk = 0; + } *root = 0; + static Node *merge(Node *x, Node *y) { + if (!x) return y; + if (!y) return x; + if (x->delta > y->delta) swap(x, y); + x = new Node(*x); + x->right = merge(x->right, y); + if (!x->left || x->left->rnk < x->rnk) swap(x->left, x->right); + x->rnk = (x->right ? x->right->rnk : 0) + 1; + return x; + } + vector deviation; + void buildHeap() { + deviation.resize(g.n); + for (int u: order) { + int v = -1; + for (int e = g.head[u]; e >= 0; e = g.next[e]) { + if (tree[u] == e) v = g.dst[e]; + else if (dist[g.dst[e]] < INF) { + auto delta = g.weight[e] - dist[g.src[e]] + dist[g.dst[e]]; + deviation[u] = merge(deviation[u], new Node({e, delta})); + } + } + if (v >= 0) deviation[u] = merge(deviation[u], deviation[v]); + } + } + KShortestPaths(Graph g_, int t) : g(g_) { + reverseDijkstra(t); + buildHeap(); + } + void enumerate(int s, int kth) { + int k = 0; + Node *x = deviation[s]; + Graph::Weight len = dist[s]; + ++k; + using SearchNode = tuple; + auto comp = [](SearchNode x, SearchNode y) { return get<1>(x) > get<1>(y); }; + priority_queue, decltype(comp)> que(comp); + if (x) que.push(SearchNode(x, len + x->delta)); + while (!que.empty() && k < kth) { + tie(x, len) = que.top(); que.pop(); + int e = x->e, u = g.src[e], v = g.dst[e]; + cout << len << endl; ++k; + if (deviation[v]) que.push(SearchNode(deviation[v], len+deviation[v]->delta)); + for (Node *y: {x->left, x->right}) + if (y) que.push(SearchNode(y, len + y->delta-x->delta)); + } + while (k < kth) { cout << -1 << endl; ++k; } + } +}; + +void KSH_test() { + int n = 4; + Graph g(n); + g.addEdge(0, 1, 2); + g.addEdge(0, 2, 2); + g.addEdge(1, 3, 4); + g.addEdge(2, 3, 2); + g.addEdge(1, 2, 1); + g.addEdge(2, 1, 1); + KShortestPaths ksh(g, 3); + ksh.enumerate(0, 10); +} + +void UTPC2013_10() { + int n, m, k; + scanf("%d %d %d", &n, &m, &k); + Graph g(n); + for (int i = 0; i < m; ++i) { + int u, v; + long long w; + scanf("%d %d %lld", &u, &v, &w); + g.addEdge(u, v, w); + } + KShortestPaths ksh(g, 0); + ksh.enumerate(0, k+1); +} + +int main() { + UTPC2013_10(); + //KSH_test(); +} diff --git a/graph/link_cut_tree.cc b/graph/link_cut_tree.cc index b1217eb..0e8fcb6 100644 --- a/graph/link_cut_tree.cc +++ b/graph/link_cut_tree.cc @@ -1,8 +1,11 @@ // -// Link Cut Tree +// Link Cut Tree (Slator-Tarjan) // // Decription: -// It maintains rooted forests with link/cut operations +// It maintains rooted arborescences with the following operations +// link(u,v) : add link from u to v +// cut(u) : cut link from u (to the root direction) +// lca(u,v) : least common ancestor of u and v // // Algorithm: // Classify links into solid and dashed. @@ -18,103 +21,96 @@ // D. D. Sleator and R. E. Tarjan (1983): // A Data Structure for Dynamic Trees. // Journal oF Computer and System Sciences, vol. 26, no. 3, pp. 362-391. +// +// Verified: AOJ Spaceships + #include #include #include +#include using namespace std; struct link_cut_tree { struct node { - int x, s; // value and sum - node *ch[2], *p; + node *child[2], *parent; }; - int sum(node *t) { return t ? t->s : 0; } - node *update(node *t) { - if (t) t->s = t->x + sum(t->ch[0]) + sum(t->ch[1]); - return t; - } - node *make_node(int x) { return new node({x, x, 0, 0, 0}); } - - int dir(node *t) { return t != t->p->ch[0]; } - bool is_root(node *t) { - return !t->p || (t->p->ch[0] != t && t->p->ch[1] != t); - } - void connect(node *p, node *t, int d) { - p->ch[d] = t; if (t) t->p = p; - update(p); + bool is_root(node *x) { + return !x->parent || (x->parent->child[0] != x + && x->parent->child[1] != x); } - void rot(node *t) { - node *p = t->p; - int d = dir(t); - if (!is_root(p)) connect(p->p, t, dir(p)); - else t->p = p->p; - connect(p, t->ch[!d], d); - connect(t, p, !d); + int dir(node *x) { return x->parent && x->parent->child[1] == x; } + void rot(node* t) { + node *p = t->parent; + int d = dir(t); + p->child[d] = t->child[!d]; + if (p->child[d]) p->child[d]->parent = p; + if (!is_root(p)) p->parent->child[dir(p)] = t; + t->parent = p->parent; + t->child[!d] = p; + p->parent = t; } - void splay(node *t) { - for (; !is_root(t); rot(t)) - if (!is_root(t->p)) rot(dir(t) == dir(t->p) ? t->p : t); + void splay(node *x) { + while (!is_root(x)) { + if (!is_root(x->parent)) { + if (dir(x) == dir(x->parent)) rot(x->parent); + else rot(x); + } + rot(x); + } } - node *expose(node *t) { - node *l = 0; - for (node *s = t; s; s = s->p) { - splay(s); - connect(s, l, 1); - l = s; + node *expose(node *x) { + node *r = 0; + for (node *p = x; p; p = p->parent) { + splay(p); + p->child[1] = r; + r = p; } - splay(t); - return l; + splay(x); + return r; } - void link(node *t, node *p) { - expose(t); - expose(p); - t->p = p; + + vector ns; + link_cut_tree(int n) : ns(n) { + for (int i = 0; i < n; ++i) + ns[i].child[0] = ns[i].child[1] = ns[i].parent = 0; } - void cut(node *t) { - expose(t); - t->ch[0] = t->ch[0]->p = 0; + void link(int x, int y) { + expose(&ns[x]); + expose(&ns[y]); + ns[y].child[1] = &ns[x]; + ns[x].parent = &ns[y]; } - node *lca(node *s, node *t) { - expose(s); - node *u = expose(t); - return !s->p ? 0 : u; + void cut(int x) { + expose(&ns[x]); + node *y = ns[x].child[0]; + ns[x].child[0] = y->parent = 0; } - int sum_to_root(node *t) { - expose(t); - return sum(t->ch[0]) + t->x; + int lca(int x, int y) { + expose(&ns[x]); + node *u = expose(&ns[y]); + return ns[x].parent ? u - &ns[0] : -1; } }; int main() { - link_cut_tree LCT; - int n, m; cin >> n >> m; - - vector a(n); - for (int i = 0; i < n; ++i) { - a[i] = LCT.make_node(i+1); - } + int n, q, t, a, b; + scanf("%d %d", &n, &q); - int u, v; - link_cut_tree::node *p; - for (int k = 0; k < m; ++k) { - int t; cin >> t; - switch (t) { - case 1: - cin >> u >> v; --u; --v; - LCT.link(a[u], a[v]); - break; - case 2: - cin >> u; --u; - LCT.cut(a[u]); - break; - case 3: - cin >> u >> v; --u; --v; - p = LCT.lca(a[u], a[v]); - if (!p) cout << "-1" << endl; - else cout << p->x << endl; - break; + link_cut_tree LCT(n); + for (int i = 0; i < q; ++i) { + scanf("%d", &t); + if (t == 1) { + scanf("%d %d", &a, &b); + LCT.link(a-1, b-1); + } else if (t == 2) { + scanf("%d", &a); + LCT.cut(a-1); + } else { + scanf("%d %d", &a, &b); + int c = LCT.lca(a-1, b-1); + printf("%d\n", c < 0 ? c : c+1); } } } diff --git a/graph/plane_perfect_matchings.cc b/graph/plane_perfect_matchings.cc new file mode 100644 index 0000000..095d48a --- /dev/null +++ b/graph/plane_perfect_matchings.cc @@ -0,0 +1,196 @@ +// +// Counting Perfect Matchings in Plane Graph +// (Fisher, Kasteleyn, and Temperley) +// +// Description: +// +// Pfaffian Orientation; see https://en.wikipedia.org/wiki/FKT_algorithm +// +// Complexity: +// +// O(n^3). +// +// g++ -std=c++17 -O3 -fmax-errors=1 -fsanitize=undefined +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +using Real = long double; +struct Point { + Real x, y; +}; + +struct PlaneGraph { + vector incident_edge; // vertex record + vector origin, twin, prev, next, incident_face; // edge record + vector component; // face record + int edges() const { return origin.size(); } + int vertices() const { return incident_edge.size(); } + int faces() const { return component.size(); } + + vector point; + int newVertex(Point p, int e = -1) { + point.push_back(p); + incident_edge.push_back(e); + return vertices()-1; + } + int newEdge(int o = -1) { + origin.push_back(o); + twin.push_back(-1); + prev.push_back(-1); + next.push_back(-1); + incident_face.push_back(-1); + return edges()-1; + } + int newFace(int e = -1) { + component.push_back(e); + return component.size()-1; + } + void completeFaces() { + component.clear(); + fill(all(incident_face), -1); + for (int e = 0; e < edges(); ++e) { + if (incident_face[e] >= 0) continue; + int f = newFace(e), x = e; + do { + incident_face[x] = f; + x = next[x]; + } while (x != e); + } + } + + // assume connected + vector pfaffianOrientation() { + // take any spanning tree T + vector dir(edges(), -2), seen(vertices()); + function dfs1 = [&](int u) { + seen[u] = 1; + int e = incident_edge[u]; + do { + int v = origin[twin[e]]; + if (!seen[v]) { + dir[e] = 1; + dir[twin[e]] = -dir[e]; + dfs1(v); + } + e = next[twin[e]]; + } while (e != incident_edge[u]); + }; + for (int u = 0; u < vertices(); ++u) + if (!seen[u]) dfs1(u); + + // take any dual spanning tree that does not cross T + seen = vector(faces()); + vector come(faces(), -1); + function dfs2 = [&](int f, int p) { + int parity = 0; + int free_edge = -1; + seen[f] = 1; + int e = component[f]; + do { + int g = incident_face[twin[e]]; + if (dir[e] == -2 && !seen[g]) dfs2(g, twin[e]); + if (dir[e] == -2) { assert(free_edge == -1); free_edge = e; } + else if (dir[e] == 1) ++parity; + e = next[e]; + } while (e != component[f]); + if (free_edge != -1) { + dir[free_edge] = -(parity % 2 == 0 ? -1 : +1); + dir[twin[free_edge]] = -dir[free_edge]; + } + }; + dfs2(0, -1); + return dir; + } + using Int = __int128_t; + Int countPerfectMatching() { + vector dir = pfaffianOrientation(); + int n = vertices(); + vector> A(n, vector(n)); + for (int e = 0; e < edges(); ++e) + A[origin[e]][origin[twin[e]]] = dir[e]; + + // compute determinant + Int det = 1; + for (int j = 0; j < n; ++j) { + for (int i = j+1; i < n; ++i) { + while (A[i][j]) { + det = -det; + Int t = A[j][j] / A[i][j]; + for (int k = j; k < n; ++k) + swap(A[i][k], A[j][k] -= t * A[i][k]); + } + } + det *= A[j][j]; // % mod + } + return sqrt(det + 0.1); + } +}; + +using Int = long long; +Int dominoCount(vector> table) { + int m = table.size(), n = table[0].size(); + vector> index(m, vector(n, -1)); + PlaneGraph g; + unordered_map> adj; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (table[i][j] == '.') { + index[i][j] = g.newVertex(Point({i,j})); + } + } + } + unordered_map next_inc, prev_inc; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + vector inc; + int x = index[i][j]; + int dx[] = {1,0,-1,0}, dy[] = {0,1,0,-1}; + for (int p = 0; p < 4; ++p) { + int k = i+dx[p], l = j+dy[p]; + if (k < 0 || l < 0) continue; + if (k >= table.size() || l >= table[k].size()) continue; + if (table[i][j] != '.' || table[k][l] != '.') continue; + int y = index[k][l]; + if (!adj[x].count(y)) adj[x][y] = g.newEdge(x); + if (!adj[y].count(x)) adj[y][x] = g.newEdge(y); + g.twin[adj[x][y]] = adj[y][x]; + g.twin[adj[y][x]] = adj[x][y]; + g.incident_edge[x] = adj[x][y]; + g.incident_edge[y] = adj[y][x]; + inc.push_back(adj[x][y]); + } + for (int i = 0; i < inc.size(); ++i) { + int j = (i == inc.size()-1 ? 0 : i+1); + next_inc[inc[i]] = inc[j]; + prev_inc[inc[j]] = inc[i]; + } + } + } + for (int e = 0; e < g.edges(); ++e) { + g.next[e] = prev_inc[g.twin[e]]; + g.prev[e] = g.twin[next_inc[e]]; + } + g.completeFaces(); + return g.countPerfectMatching(); +} + +void SPOJ_GNY07H() { + int ncase; + cin >> ncase; + for (int icase = 0; icase < ncase; ++icase) { + int w; + cin >> w; + vector> table(4, vector(w, '.')) ; + cout << icase+1 << " " << dominoCount(table) << endl; + } +} + +int main() { + SPOJ_GNY07H(); +} diff --git a/graph/prufer_code.cc b/graph/prufer_code.cc new file mode 100644 index 0000000..8e4b877 --- /dev/null +++ b/graph/prufer_code.cc @@ -0,0 +1,112 @@ +// +// Prufer Code in Linear Time +// +// Description: +// Prufer code gives one-to-one correspondence +// between labeled trees and integers of length n-2. +// This immediately shows the Cayley theorem: +// the number of labeled trees is n^{n-2}. +// The algorithm computes the Prufer code in linear +// time. +// +// Complexity: +// O(n) +// +// Reference: +// Xiaodong Wang, Lei Wang, and Yingjie Wui (2009): +// "An Optimal Algorithm for Prufer Codes", +// Journal of Software Engineering and Applications, +// vol.2, 111--115. +// + +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct Tree { + int n; + vector> adj; + Tree(int n) : n(n), adj(n) { } + void addEdge(int u, int v) { + adj[u].push_back(v); + adj[v].push_back(u); + } +}; + +vector labeledTreeToCode(Tree T) { + vector deg(T.n), parent(T.n, -1), code; + function dfs = [&](int u) { + deg[u] = T.adj[u].size(); + for (int v: T.adj[u]) { + if (v != parent[u]) { + parent[v] = u; + dfs(v); + } + } + }; dfs(T.n-1); + + int index = -1; + while (deg[++index] != 1); + for (int u = index, i = 0; i < T.n-2; ++i) { + int v = parent[u]; + code.push_back(v); + if (--deg[v] == 1 && v < index) { + u = v; + } else { + while (deg[++index] != 1); + u = index; + } + } + return code; +} + +Tree codeToLabeledTree(vector code) { + int n = code.size() + 2; + Tree T(n); + vector deg(n, 1); + for (int i = 0; i < n-2; ++i) + ++deg[code[i]]; + + int index = -1; + while (deg[++index] != 1); + for (int u = index, i = 0; i < n-2; ++i) { + int v = code[i]; + T.addEdge(u, v); + --deg[u]; --deg[v]; + if (deg[v] == 1 && v < index) { + u = v; + } else { + while (deg[++index] != 1); + u = index; + } + } + for (int u = 0; u < n-1; ++u) + if (deg[u] == 1) T.addEdge(u, n-1); + return T; +} + +int main() { + Tree T(6); + T.addEdge(0, 3); + T.addEdge(1, 3); + T.addEdge(2, 3); + T.addEdge(3, 4); + T.addEdge(4, 5); + auto code = labeledTreeToCode(T); + for (int u: code) { + cout << u << " "; + } + cout << endl; + + Tree G = codeToLabeledTree(code); + for (int u = 0; u < G.adj.size(); ++u) { + for (int v: G.adj[u]) { + if (u < v) cout << u << " " << v << endl; + } + } +} diff --git a/graph/shortest_path_st.cc b/graph/shortest_path_st.cc deleted file mode 100644 index 1fbf1a9..0000000 --- a/graph/shortest_path_st.cc +++ /dev/null @@ -1,104 +0,0 @@ -// -// Single pair shortest path (Bidirectional dijkstra) -// -// Description: -// For a pair of vertices, it finds a shortest path between -// these two vertices. -// -// Algorithm: -// Bidirectional dijkstra algorithm that performs Dijkstra -// algorithm from s and t simultaneously. -// Usually, it is much faster than standard Dijkstra. -// -// Verified: -// SPOJ SHPATH -// -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -#define fst first -#define snd second - -const int INF = 99999999; -struct graph { - int n; - struct edge { int src, dst, weight; }; - vector> adj, rdj; - graph(int n) : n(n), adj(n), rdj(n) { } - void add_edge(int u, int v, int w) { - adj[u].push_back({u, v, w}); - rdj[v].push_back({v, u, w}); - } - - int shortest_path(int s, int t) { - if (s == t) return 0; - vector ds(n, INF), dt(n, INF); - typedef pair node; - priority_queue, greater> Qs, Qt; - Qs.push({ds[s] = 0, s}); - Qt.push({dt[t] = 0, t}); - int mu = INF; - while (!Qs.empty() && !Qt.empty()) { - if (Qs.top().fst + Qt.top().fst >= mu) break; - if (Qs.top().fst <= Qt.top().fst) { - node x = Qs.top(); Qs.pop(); - if (ds[x.snd] > x.fst) continue; - for (edge &e: adj[x.snd]) { - if (ds[e.src] + e.weight < ds[e.dst]) { - mu = min(mu, ds[e.src] + e.weight + dt[e.dst]); - Qs.push({ds[e.dst] = ds[e.src] + e.weight, e.dst}); - } - } - } else { - node x = Qt.top(); Qt.pop(); - if (dt[x.snd] > x.fst) continue; - for (edge &e: rdj[x.snd]) { - if (dt[e.src] + e.weight < dt[e.dst]) { - mu = min(mu, dt[e.src] + e.weight + ds[e.dst]); - Qt.push({dt[e.dst] = dt[e.src] + e.weight, e.dst}); - } - } - } - } - return mu; - } -}; - - -void solve() { - int n; - scanf("%d", &n); - graph g(n); - map id; - for (int u = 0; u < n; ++u) { - char name[1024]; - scanf("%s", name); - id[name] = u; - int k; - scanf("%d", &k); - for (int j = 0; j < k; ++j) { - int v, d; - scanf("%d %d", &v, &d); - g.add_edge(u, v-1, d); - } - } - int k; - scanf("%d", &k); - for (int i = 0; i < k; ++i) { - char s[1024], t[1024]; - scanf("%s %s", s, t); - printf("%d\n", g.shortest_path(id[s], id[t])); - } -} - -int main() { - int ncase; scanf("%d", &ncase); - for (int icase = 0; icase < ncase; ++icase) solve(); -} diff --git a/graph/topological_sort.cc b/graph/topological_sort.cc new file mode 100644 index 0000000..66cfd16 --- /dev/null +++ b/graph/topological_sort.cc @@ -0,0 +1,81 @@ +// +// Topological Sort +// +// +// Description: +// +// Let G = (V, E) be a graph. An ordering ord: [n] -> V is a topological +// ordering if i > j then there is no edge from ord[i] to ord[j]. +// G has a topological ordering if and only if G is DAG. +// +// A topological order can be obtained in O(n + m) time by using +// an iterative method (Kahn's algorithm) or a recursive method +// (by Tarjan's algorithm). The following implementation is a +// Kahn's algorithm. +// +// Note that if you want to find the all topological orders, +// +// +// Complexity: +// +// O(n + m) +// +// +// Verified: +// +// AOJ GPL_4_B +// +// References: +// +// Arthur B. Kahn (1962): +// "Topological sorting of large networks". +// Communications of the ACM, 5 (11): 558--562. +// +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +struct Graph { + int n; + vector> adj; + Graph(int n) : n(n), adj(n) { } + void addEdge(int u, int v) { + adj[u].push_back(v); + } +}; + +// return empty list if g has no topological order +vector topologicalSort(Graph g) { + vector deg(g.n); + for (int u = 0; u < g.n; ++u) + for (int v: g.adj[u]) ++deg[v]; + vector stack; + for (int u = 0; u < g.n; ++u) + if (!deg[u]) stack.push_back(u); + + vector order; + while (!stack.empty()) { + int u = stack.back(); stack.pop_back(); + order.push_back(u); + for (int v: g.adj[u]) + if (!--deg[v]) stack.push_back(v); + } + return order.size() == g.n ? order : vector(); +} + +int main() { + int n, m; cin >> n >> m; + Graph g(n); + for (int i = 0; i < m; ++i) { + int u, v; cin >> u >> v; + g.addEdge(u, v); + } + auto ord = topologicalSort(g); + for (int i = 0; i < ord.size(); ++i) { + if (i > 0) cout << " "; + cout << ord[i]; + } +} diff --git a/machine_learning/roc-auc.cc b/machine_learning/roc-auc.cc new file mode 100644 index 0000000..5af7947 --- /dev/null +++ b/machine_learning/roc-auc.cc @@ -0,0 +1,40 @@ +#include + +using namespace std; + +double trapezoid(double x1, double x2, double y1, double y2) { + return (y2+y1)/2 * abs(x2-x1); +} + +double auc(vector test, vector pred) { + int n = test.size(); + assert(n == pred.size()); + + vector idx(n); + for (int i = 0; i < n; ++i) idx[i] = i; + sort(idx.begin(), idx.end(), [&](int i, int j) { return pred[i] > pred[j]; }); + + double a = 0.0; + double fp = 0, tp = 0, fp_prev = 0, tp_prev = 0; + double prev_score = -1.0/0.0; + for (int i: idx) { + if (pred[i] != prev_score) { + a += trapezoid(fp, fp_prev, tp, tp_prev); + prev_score = pred[i]; + fp_prev = fp; + tp_prev = tp; + } + if (test[i] == 1) { + tp += 1; + } else { + fp += 1; + } + } + a += trapezoid(fp, fp_prev, tp, tp_prev); + return a / (tp * fp); +} +int main() { + vector test = {0, 1, 0, 1, 1}; + vector pred = {0.2, 0.3, 0.4, 0.5, 0.6}; + cout << auc(test, pred) << endl; +} diff --git a/math/continued_fraction.cc b/math/continued_fraction.cc new file mode 100644 index 0000000..2a34d84 --- /dev/null +++ b/math/continued_fraction.cc @@ -0,0 +1,176 @@ +// +// Continued Fraction +// +// Description: +// see https://perl.plover.com/yak/cftalk/ +// +// Gosper's algorithm +// +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +using Int = long long; +struct Generator { + using Pointer = shared_ptr; + virtual Int value() = 0; + virtual Pointer next() = 0; +}; + +// (a x + b)/(c x + d) +struct HoloGen : Generator { + Int a, b, c, d; + Pointer x; + HoloGen(Pointer x, Int a, Int b, Int c, Int d) : x(x), a(a), b(b), c(c), d(d) { } + void normalize() { + while (1) { + if (c == 0 && d == 0) break; + double b_ac = (double)a/c, b_bd = (double)b/d; + if ((Int)b_ac == (Int)b_bd) break; + if (!x) { + tie(a,b,c,d) = make_tuple(a,a,c,c); + } else { + Int p = x->value(); x = x->next(); + tie(a,b,c,d) = make_tuple(a*p+b,a,c*p+d,c); + } + } + } + virtual Int value() { normalize(); return a/c; } + virtual Pointer next() { + Int r = value(); + if (a-c*r == 0 && b-d*r == 0) return 0; + return Pointer(new HoloGen(x,c,d,a-c*r,b-d*r)); + } +}; +// (a x y + b x + c y + d)/(e x y + f x + g y + h) +struct ArithGen : Generator { + Int a, b, c, d, e, f, g, h; + Pointer x, y; + ArithGen(Pointer x, Pointer y, Int a, Int b, Int c, Int d, Int e, Int f, Int g, Int h) : x(x), y(y), a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) { } + void normalize() { + while (1) { + if (e == 0 && f == 0 && g == 0 && h == 0) break; + double b_ae = (double)a/e, b_cg = (double)c/g, + b_bf = (double)b/f, b_dh = (double)d/h; + if ((Int)b_ae == (Int)b_cg && + (Int)b_cg == (Int)b_bf && + (Int)b_bf == (Int)b_dh) break; + auto idiff = [&](double a, double b) { + if (isinf(a) && isinf(b)) return 0.0; + if (isinf(a) || isinf(b)) return 1.0/0.0; + return fabs(a - b); + }; + if (max(idiff(b_ae, b_cg), idiff(b_bf, b_dh)) + > max(idiff(b_ae, b_bf), idiff(b_cg, b_dh))) { + if (!x) { + tie(a,b,c,d,e,f,g,h) = make_tuple(a,b,a,b,e,f,e,f); + } else { + Int p = x->value(); x = x->next(); + tie(a,b,c,d,e,f,g,h) = make_tuple(a*p+c,b*p+d,a,b,e*p+g,f*p+h,e,f); + } + } else { + if (!y) { + tie(a,b,c,d,e,f,g,h) = make_tuple(a,a,c,c,e,e,g,g); + } else { + Int p = y->value(); y = y->next(); + tie(a,b,c,d,e,f,g,h) = make_tuple(a*p+b,a,c*p+d,c,e*p+f,e,g*p+h,g); + } + } + } + } + virtual Int value() { normalize(); return a/e; } + virtual Pointer next() { + Int r = value(); + if (a-e*r == 0 && b-f*r == 0 && c-g*r == 0 && d-h*r == 0) return 0; + return Pointer(new ArithGen(x,y,e,f,g,h,a-e*r,b-f*r,c-g*r,d-h*r)); + } +}; +struct ContinuedFraction { + using Pointer = shared_ptr; + Pointer head; + ContinuedFraction(Pointer head) : head(head) { } + double toReal() { + Pointer run = head; + function eval = [&](Pointer run, int depth) { + if (!run) return 1.0/0.0; + return run->value() + 1.0 / eval(run->next(), depth-1); + }; + return eval(head, 20); + } +}; +ContinuedFraction operator+(ContinuedFraction x, ContinuedFraction y) { + return ContinuedFraction(ContinuedFraction::Pointer( + new ArithGen(x.head, y.head, 0, 1, 1, 0, 0, 0, 0, 1))); +} +ContinuedFraction operator-(ContinuedFraction x, ContinuedFraction y) { + return ContinuedFraction(ContinuedFraction::Pointer( + new ArithGen(x.head, y.head, 0, 1, -1, 0, 0, 0, 0, 1))); +} +ContinuedFraction operator*(ContinuedFraction x, ContinuedFraction y) { + return ContinuedFraction(ContinuedFraction::Pointer( + new ArithGen(x.head, y.head, 1, 0, 0, 0, 0, 0, 0, 1))); +} +ContinuedFraction operator/(ContinuedFraction x, ContinuedFraction y) { + return ContinuedFraction(ContinuedFraction::Pointer( + new ArithGen(x.head, y.head, 0, 1, 0, 0, 0, 0, 1, 0))); +} +ContinuedFraction operator*(ContinuedFraction x, Int a) { + return ContinuedFraction(ContinuedFraction::Pointer( + new HoloGen(x.head, a, 0, 0, 1))); +} + +int compare(ContinuedFraction x, ContinuedFraction y) { + auto i = x.head, j = y.head; + while (1) { + if (!i && !j) return 0; + if (!j || i->value() < j->value()) return -1; + if (!i || i->value() > j->value()) return +1; + tie(i, j) = make_tuple(j->next(), i->next()); + } +} +bool operator==(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) == 0; } +bool operator!=(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) != 0; } +bool operator<=(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) <= 0; } +bool operator>=(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) >= 0; } +bool operator<(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) < 0; } +bool operator>(ContinuedFraction x, ContinuedFraction y) { return compare(x, y) > 0; } + +struct Rational : ContinuedFraction { + struct RationalGen : Generator { + Int num, den; + RationalGen(Int num, Int den) : num(num), den(den) { } + virtual Int value() { + return num / den - (num < 0); + } + virtual Pointer next() { + if (num - value() * den == 0) return 0; + return Pointer(new RationalGen(den, num - value() * den)); + } + }; + Rational(Int a, Int b) : + ContinuedFraction(Pointer(new RationalGen(a, b))) { } +}; +struct NapierGenerator : Generator { + int i; + NapierGenerator(int i = 0) : i(i) { } + virtual Int value() { + if (i == 0) return 2; + if (i % 3 == 2) return 2 * (i/3) + 2; + return 1; + } + virtual Pointer next() { + return Pointer(new NapierGenerator(value())); + } +}; +ContinuedFraction e(ContinuedFraction::Pointer(new NapierGenerator(0))); + + + +int main() { + ContinuedFraction x = Rational(-8, 11), y = Rational(-1, 2); + cout << compare(x, y) << endl; + cout << x.toReal() << endl; +} diff --git a/math/lattice_below_line.cc b/math/lattice_below_line.cc new file mode 100644 index 0000000..e9ee769 --- /dev/null +++ b/math/lattice_below_line.cc @@ -0,0 +1,74 @@ +// +// Number of lattice points below a line +// +// Description: +// +// Let a, b, n, m be nonnegative integers. The task is to compute +// sum_{i in [0,n)} floor((a + ib)/m). +// +// We compute this quantity in two directions alternately. +// First, let +// a = (a/m) m + (a%m), +// b = (b/m) m + (b%m). +// Then the quantity is +// sum [(a/m)+i*(b/m)] + floor(((a%m) + i(b%m))/m) +// Here, the first term is analytically evaluated. +// The second term is zero if b%m == 0. Otherwise, the task is +// reduced to compute +// sum_{i in [0,n)} floor((a + ib)/m) +// where a < m, b < m. By changing the axes, this quantity is +// sum_{i in [0,n')} floor((a' + ib')/m') +// where +// n' = (a + b n) / m, +// a' = (a + b n) % m, +// b' = m, +// m' = b. +// +// We evaluate the number of iterations. Since the computation +// between b and m is the same as the one of the Euclidean +// algorithm. Thus it terminates in O(log m) time. +// +// Complexity: +// +// O(log m). +// +// Verified: +// +// Somewhere + +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +// +// sum_{0<=i= 0, a >= 0, b >= 0 +// +// +using Int = long long; +Int latticeBelowLine(Int n, Int a, Int b, Int m) { + Int ans = 0; + while (m) { + ans += (n-1)*n/2*(b/m) + n*(a/m); + a %= m; + b %= m; + auto z = (a+b*n); + a = z%m; + n = z/m; + swap(b, m); + } + return ans; +} + +int main() { + srand(time(0)); + Int a = rand(), b = rand(), n = rand(), m = rand(); + cout << latticeBelowLine(n, a, b, m) << endl; +} diff --git a/math/rational.cc b/math/rational.cc new file mode 100644 index 0000000..ad41fc4 --- /dev/null +++ b/math/rational.cc @@ -0,0 +1,157 @@ +// +// Rational Type +// +#include +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) + +using Int = long long; +struct Rational { + Int num, den; // x = num/den + + static Int gcd(Int a, Int b) { + for (; a; swap(a, b %= a)); + return b; + } + Rational(Int a = 0) : num(a), den(1) { } + Rational(Int a, Int b, bool do_normalize = false) : num(a), den(b) { + if (do_normalize) { + auto g = gcd(num, den); + num /= g; den /= g; + if (den < 0) { num = -num; den = -den; } + } + } + static Rational inf() { return Rational(1,0); } + + Rational inv() const { + if (num < 0) return {-den, -num}; + else return { den, num}; + } + Rational operator+() const { return *this; } + Rational operator-() const { return Rational(-num,den); } + Rational &operator+=(Rational x) { + auto g = gcd(den, x.den); + num = num*(x.den/g) + (den/g)*x.num; + den = den*(x.den/g); + return *this; + } + Rational &operator*=(Rational x) { + auto g = gcd(num, x.den), h = gcd(den, x.num); + num = (num/g)*(x.num/h); + den = (den/h)*(x.den/g); + if (den < 0) { num = -num; den = -den; } + return *this; + } + Rational &operator-=(Rational x) { return *this += -x; } + Rational &operator/=(Rational x) { return *this *= x.inv(); } +}; +Rational operator+(Rational x, Rational y) { return x += y; } +Rational operator-(Rational x, Rational y) { return x -= y; } +Rational operator*(Rational x, Rational y) { return x *= y; } +Rational operator/(Rational x, Rational y) { return x /= y; } +int compare(Rational x, Rational y) { // sign(x-y) + if (x.num == 0) return (y.num < 0) - (y.num > 0); + if (x.num < 0) return y.num >= 0 ? -1 : compare(-y, -x); + if (y.num <= 0) return 1; + while (x.den != 0 && y.den != 0) { + auto a = x.num/x.den, b = y.num/y.den; + if (a != b) return a - b; + swap(x.num -= a*x.den, x.den); + swap(y.num -= b*y.den, y.den); + swap(x, y); + } + if (x.den != 0) return -y.num; + if (y.den != 0) return x.num; + return x.num - y.num; +} +bool operator==(Rational x, Rational y) { return compare(x,y)==0; } +bool operator!=(Rational x, Rational y) { return compare(x,y)!=0; } +bool operator<=(Rational x, Rational y) { return compare(x,y)<=0; } +bool operator>=(Rational x, Rational y) { return compare(x,y)>=0; } +bool operator<(Rational x, Rational y) { return compare(x,y)<0; } +bool operator>(Rational x, Rational y) { return compare(x,y)>0; } + +ostream &operator<<(ostream &os, Rational x) { os<= 0; --i) + swap(num, den += as[i] * num); + if (abs(num) >= 1e9 || abs(den) >= 1e9) { + num = num_; den = den_; + break; // overflow; backup and forgive + } + auto error = fabs(Real(num)/den - a); + b -= as[k]; + if (b == 0 || error < 1e-16) break; + b = 1 / b; + } + if (den < 0) { num = -num; den = -den; } + return Rational(num, den, false); +} + + +/* +Rational approx(Rational::Real a) { + Rational::Int num = 1, den = 0; + Rational::Int as[30] = {0}; + auto b = a; + for (int k = 0; k < 30; ++k) { + as[k] = round(b); + auto numk = num, denk = den; + for (int i = k; i >= 0; --i) + swap(numk, denk += as[i] * numk); + if (abs(numk) >= 1e9 || abs(denk) >= 1e9) break; // overflow + auto error = fabs(Real(numk)/denk - a); + if (error < 1e-9) { + num = numk; den = denk; + break; + } + b -= as[k]; + if (b == 0) break; + b = 1 / b; + } + return Rational(num, den); +} +*/ +void verify_compare() { + srand( time(0) ); + for (int iter = 0; iter < 100000; ++iter) { + cout << iter << endl; + Rational x(rand()%100, 1 + rand()%100); + Rational y(rand()%100, 1 + rand()%100); + assert( (x < y) == (-y < -x) ); + assert( x == x ); + assert( -x == -x ); + assert( (x == y) == (-x == -y) ); + assert( (x != y) == (-x != -y) ); + if (x != Rational(0,1)) assert( (y + x) != (y - x) ); + if (x > Rational(0,1)) assert( (y-x) < (y+x) ); + if (x > Rational(0,1)) assert( (-y-x) < (-y+x) ); + } +} + +int main() { + // 0/1 < 1/1 + /* + Rational x(2,1), y(3,1); + cout << x + y << endl; + */ + /* + Rational x = atan(sqrt(Rational(1,2))); + cout << x << endl; + printf("%.12f\n%.12f\n", (double)x, atan(sqrt(1.0/2.0))); + */ + verify_compare(); +} diff --git a/number_theory/modular_arithmetics.cc b/number_theory/modular_arithmetics.cc index 32e0ce8..5110efe 100644 --- a/number_theory/modular_arithmetics.cc +++ b/number_theory/modular_arithmetics.cc @@ -1,179 +1,442 @@ // -// Modular arithmetics (long long) +// Modular Arithmetics // -// Note: -// int < 2^31 < 10^9 -// long long < 2^63 < 10^18 +// long long: 10^18 < 2^63-1 < 10^19 (strict inequality) +// __int128_t: 10^38 < 2^127-1 < 10^39 // -// feasible for M < 2^62 (10^18 < 2^62 < 10^19) -// -// -// Verified: -// SPOJ 11409: Fibonacci With a Twist -// SPOJ 9832: Matrix Inverse -// -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include +// g++ -std=c++17 -O3 -fmax-errors=1 -fsanitize=undefined +#include +#pragma GCC optimize ("O3") using namespace std; - - -#define All(c) c.begin(), c.end() -#define FOR(i,c) for(typeof(c.begin())i=c.begin();i!=c.end();++i) -#define REP(i,n) for(int i=0;i vec; -typedef vector mat; -ll add(ll a, ll b, ll M) { - a += b; - if (a >= M) a -= M; - return a; -} -ll sub(ll a, ll b, ll M) { - if (a < b) a += M; - return a - b; +// === tick a time === +#include +double tick() { + static clock_t oldtick; + clock_t newtick = clock(); + double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; + oldtick = newtick; + return diff; } -// Correctness of mul -// ab = floor(ab / M) * M + (ab % M) -// -> (ab % M) = ab - floor(ab / M) * M -ll mul(ll a, ll b, ll M) { - ll r = a*b - floor(1.0*a*b/M)*M; - return r < 0 ? r + M : r >= M ? r - M : r; + +template +ostream &operator<<(ostream &os, const vector &v) { + os << "["; + for (int i = 0; i < v.size(); os << v[i++]) + if (i > 0) os << " "; + os << "]"; + return os; +} +template +ostream &operator<<(ostream &os, const vector> &v) { + os << "["; + for (int i = 0; i < v.size(); os << v[i++]) + if (i > 0) os << endl << " "; + os << "]"; + return os; } -ll pow(ll a, ll b, ll M) { - ll x = 1; - for (; b > 0; b >>= 1) { - if (b & 1) x = mul(x, a, M); - a = mul(a, a, M); +using Int = long long; +struct ModInt { + static Int mod; // Set this value + Int val; + ModInt(Int v=0) : val(v%mod) { } + ModInt operator-() const { return ModInt(val?mod-val:val); } + ModInt &operator+=(ModInt a) { + if ((val += a.val) >= mod) val -= mod; + return *this; + } + ModInt &operator-=(ModInt a) { + if ((val -= a.val) < 0) val += mod; + return *this; + } + ModInt &operator*=(ModInt a) { + val = (__uint128_t(val) * a.val) % mod; + return *this; + } + ModInt &operator/=(ModInt a) { + Int u = 1, v = a.val, s = 0, t = mod; + while (v) { + Int q = t / v; + swap(s -= u * q, u); + swap(t -= v * q, v); + } + a.val = (s < 0 ? s + mod : s); + val /= t; + return (*this) *= a; + } + ModInt inv() const { return ModInt(1) /= (*this); } + bool operator<(ModInt x) const { return val < x.val; } +}; +Int ModInt::mod = 1e9+7; + +ostream &operator<<(ostream &os, ModInt a) { os << a.val; return os; } +ModInt operator+(ModInt a, ModInt b) { return a += b; } +ModInt operator-(ModInt a, ModInt b) { return a -= b; } +ModInt operator*(ModInt a, ModInt b) { return a *= b; } +ModInt operator/(ModInt a, ModInt b) { return a /= b; } +ModInt pow(ModInt a, Int e) { + ModInt x(1); + for (; e > 0; e /= 2) { + if (e % 2 == 1) x *= a; + a *= a; } return x; } -ll div(ll a, ll b, ll M) { - ll u = 1, x = 0, s = b, t = M; - while (s) { - ll q = t / s; - swap(x -= u * q, u); - swap(t -= s * q, s); - } - if (a % t) return -1; // infeasible - return mul(x < 0 ? x + M : x, a / t, M); +ModInt stringToModInt(string s) { + Int val = 0; + for (int i = 0; i < s.size(); ++i) + val = (val*10 + (s[i]-'0')) % ModInt::mod; + return ModInt(val); +} + +// compute inv[1], inv[2], ..., inv[mod-1] in O(n) time +vector inverse() { + Int mod = ModInt::mod; + vector inv(mod); + inv[1].val = 1; + for (Int a = 2; a < mod; ++a) + inv[a] = inv[mod % a] * ModInt(mod - mod/a); + return inv; } -// Modular Matrix -mat eye(int n) { - mat I(n, vec(n)); - REP(i, n) I[i][i] = 1; - return I; +// +// Solve x^2 = n; mod should be a prime +// +// Verified: Code Forces Quadratic Equations +// +bool isQuadraticResidue(ModInt n) { + return n.val == 0 || n.mod == 2 || pow(n, (n.mod-1)/2).val == 1; } -mat zeros(int n) { - return mat(n, vec(n)); +ModInt sqrt(ModInt n) { + const Int mod = ModInt::mod; + if (n.val == 0 || mod == 2) return n; + int M = __builtin_ctz(mod-1), Q = (mod-1)>>M; + ModInt z(2); + while (isQuadraticResidue(z)) ++z.val; + ModInt c = pow(z, Q); + ModInt t = pow(n, Q); + ModInt R = pow(n, (Q+1)/2); + while (t.val != 1) { + int i = 0; + for (ModInt s = t; s.val != 1; s *= s) ++i; + if (M == i) exit(0); + ModInt b = pow(c, 1<<(M-i-1)); + M = i; + c = b*b; + t *= c; + R *= b; + } + return R; } -mat mul(mat A, mat B, ll M) { - int l = A.size(), m = B.size(), n = B[0].size(); - mat C(l, vec(n)); - REP(i,l) REP(k,m) REP(j,n) - C[i][j] = add(C[i][j], mul(A[i][k], B[k][j], M), M); - return C; +vector quadraticEquation(ModInt a, ModInt b, ModInt c) { + if (ModInt::mod == 2) { + vector ans; + if (c.val == 0) ans.push_back(c); + if ((a + b + c).val == 0) ans.push_back(ModInt(1)); + return ans; + } else { + b /= (a+a); c /= a; + ModInt D = b*b - c; + if (!isQuadraticResidue(D)) return {}; + ModInt s = sqrt(D), x = -b+s, y = -b-s; + return (x.val < y.val) ? vector({x, y}) : + (x.val > y.val) ? vector({y, x}) : + vector({x}); + } } -mat pow(mat A, ll b, ll M) { - mat X = eye(A.size()); - for (; b > 0; b >>= 1) { - if (b & 1) X = mul(X, A, M); - A = mul(A, A, M); + +// Discrete Logarithm by Shanks' Baby-Step Giant-Step +// Find k such that a^k == b +Int log(ModInt a, ModInt b) { + Int h = ceil(sqrt(ModInt::mod+1e-9)); + unordered_map hash; + ModInt x(1); + for (Int i = 0; i < h; ++i) { + if (!hash.count(x.val)) hash[x.val] = i; + x *= a; } - return X; + x = x.inv(); + ModInt y = b; + for (int i = 0; i < h; ++i) { + if (hash.count(y.val)) return i*h+hash[y.val]; + y *= x; + } + return -1; } -// assume: M is prime (singular ==> -// verify: SPOJ9832 -mat inv(mat A, ll M) { - int n = A.size(); - mat B(n, vec(n)); - for (int i = 0; i < n; ++i) - B[i][i] = 1; - - for (int i = 0; i < n; ++i) { - int j = i; - while (j < n && A[j][i] == 0) ++j; - if (j == n) return {}; - swap(A[i], A[j]); - swap(B[i], B[j]); - - ll inv = div(1, A[i][i], M); - for (int k = i; k < n; ++k) - A[i][k] = mul(A[i][k], inv, M); - for (int k = 0; k < n; ++k) - B[i][k] = mul(B[i][k], inv, M); + +struct ModMatrix { + int m, n; // m times n matrix + vector> val; + ModInt &operator()(int i, int j) { return val[i][j]; } + ModMatrix(int m, int n) : + m(m), n(n), val(m, vector(n)) { } + ModMatrix operator-() const { + ModMatrix A(m, n); + for (int i = 0; i < m; ++i) + for (int j = 0; j < n; ++j) + A.val[i][j] = -val[i][j]; + return A; + } + ModMatrix &operator+=(ModMatrix A) { + for (int i = 0; i < m; ++i) + for (int j = 0; j < n; ++j) + val[i][j] += A.val[i][j]; + return *this; + } + ModMatrix &operator-=(ModMatrix A) { + for (int i = 0; i < m; ++i) + for (int j = 0; j < n; ++j) + val[i][j] -= A.val[i][j]; + return *this; + } + ModMatrix &operator*=(ModMatrix A) { + for (int i = 0; i < m; ++i) { + vector row(A.n); + for (int j = 0; j < A.n; ++j) { + for (int k = 0; k < A.m; ++k) + row[j] += val[i][k] * A.val[k][j]; + } + val[i] = row; + } + return *this; + } + static ModMatrix eye(int n) { + ModMatrix I(n, n); + for (int i = 0; i < n; ++i) I.val[i][i].val = 1; + return I; + } + static ModMatrix zero(int n) { + return ModMatrix(n, n); + } + // mod should be prime + ModMatrix inv() const { + ModMatrix B = eye(n); + vector> a = val; + vector> &b = B.val; + for (int i = 0, j, k; i < n; ++i) { + for (j = i; j < n && a[j][i].val == 0; ++j); + if (j == n) return ModMatrix(0,0); // regularity is checked by m = 0 + swap(a[i], a[j]); + swap(b[i], b[j]); + ModInt inv = a[i][i].inv(); + for (k = i; k < n; ++k) a[i][k] *= inv; + for (k = 0; k < n; ++k) b[i][k] *= inv; + for (j = 0; j < n; ++j) { + if (i == j || a[j][i].val == 0) continue; + ModInt c = a[j][i]; + for (k = i; k < n; ++k) a[j][k] -= c * a[i][k]; + for (k = 0; k < n; ++k) b[j][k] -= c * b[i][k]; + } + } + return B; + } + // It can be used for any composite modulo. + ModInt det() const { + vector> a = val; + ModInt D(1); for (int j = 0; j < n; ++j) { - if (i == j || A[j][i] == 0) continue; - ll cor = A[j][i]; - for (int k = i; k < n; ++k) - A[j][k] = sub(A[j][k], mul(cor, A[i][k], M), M); - for (int k = 0; k < n; ++k) - B[j][k] = sub(B[j][k], mul(cor, B[i][k], M), M); + for (int i = j+1; i < n; ++i) { + while (a[i][j].val) { + D = -D; + ModInt t(a[j][j].val/a[i][j].val); + for (int k = j; k < n; ++k) + swap(a[i][k], a[j][k] -= t * a[i][k]); + } + } + D *= a[j][j]; } + return D; + } +}; +ModMatrix operator+(ModMatrix A, ModMatrix B) { return A += B; } +ModMatrix operator-(ModMatrix A, ModMatrix B) { return A -= B; } +ModMatrix operator*(ModMatrix A, ModMatrix B) { return A *= B; } +ModMatrix pow(ModMatrix A, int k) { + ModMatrix X = ModMatrix::eye(A.n); + for (; k > 0; k /= 2) { + if (k % 2 == 1) X *= A; + A *= A; } - return B; + return X; +} +ModInt dot(ModMatrix A, ModMatrix B) { + ModInt val; + for (int i = 0; i < A.m; ++i) + for (int j = 0; j < A.n; ++j) + val += A.val[i][j] * B.val[i][j]; + return val; +} +using ModVector = vector; +ModVector operator*(ModMatrix A, ModVector x) { + vector y(A.m); + for (int i = 0; i < A.m; ++i) + for (int j = 0; j < A.n; ++j) + y[i] += A.val[i][j] * x[j]; + return y; +} +ModInt dot(ModVector a, ModVector b) { + ModInt val; + for (int i = 0; i < a.size(); ++i) + val += a[i] * b[i]; + return val; } +// +// Only available for prime modulos. +// If you want to compute multiple inverses, +// use LU decomposition instead of computing the inverse. +// +struct LUDecomposition { + int n; + vector pi; + vector> val; + LUDecomposition(ModMatrix A) : n(A.n), val(A.val) { + pi.resize(n+1); + iota(all(pi), 0); + for (int i = 0, j, k; i < n; ++i) { + for (k = i; k < n; ++k) + if (val[k][i].val) break; + if (k == n) { pi[n] = -1; return; } // NG + if (k != i) { + swap(pi[i], pi[k]); + swap(val[i], val[k]); + ++pi[n]; + } + for (j = i+1; j < n; ++j) { + if (val[j][i].val == 0) continue; + val[j][i]/= val[i][i]; + for (k = i+1; k < n; ++k) + val[j][k] -= val[j][i] * val[i][k]; + } + } + } + bool isRegular() const { return pi[n] >= 0; } + ModVector solve(ModVector b) { + vector x(b.size()); + for (int i = 0; i < n; ++i) { + x[i] = b[pi[i]]; + for (int k = 0; k < i; ++k) + x[i] -= val[i][k] * x[k]; + } + for (int i = n-1; i >= 0; --i) { + for (int k = i+1; k < n; ++k) + x[i] -= val[i][k] * x[k]; + x[i] /= val[i][i]; + } + return x; + } + ModMatrix inverse() { // do not compute the inverse + ModMatrix B(n, n); + for (int j = 0; j < n; ++j) { + for (int i = 0; i < n; ++i) { + if (pi[i] == j) B.val[i][j].val = 1; + for (int k = 0; k < i; k++) + B.val[i][j] -= val[i][k] * B.val[k][j]; + } + for (int i = n-1; i >= 0; --i) { + for (int k = i+1; k < n; ++k) + B.val[i][j] -= val[i][k] * B.val[k][j]; + B.val[i][j] /= val[i][i]; + } + } + return B; + } + ModInt det() { + ModInt D = val[0][0]; + for (int i = 1; i < n; i++) + D *= val[i][i]; + return ((pi[n] - n) % 2 != 0) ? -D : D; + } +}; +void mulTest() { + ModInt::mod = 1e9+7; + int m = 4, n = 4; + ModMatrix A(m,n); + ModMatrix B(m,n); + vector b(n); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + A(i,j).val = rand() % ModInt::mod; + B(i,j).val = rand() % ModInt::mod; + } + b[i].val = rand() % ModInt::mod; + } + ModMatrix C = A * B; -void disp(mat A) { - cout << "["; - REP(i, A.size()) { - if (i != 0) cout << " "; - REP(j, A[i].size()) { - cout << A[i][j]; - if (j != A[i].size()-1) cout << ", "; - else cout << "; "; + for (int i = 0; i < C.m; ++i) { + for (int j = 0; j < C.n; ++j) { + cout << C(i,j) << " "; } cout << endl; } - cout << endl; -} + cout << C.det() << endl; + LUDecomposition LU(C); + cout << LU.det() << endl; -ll binomial(ll n, ll k, ll M) { - ll num = 1, den = 1; - while (n > 0 || k > 0) { - ll m = n % M, l = k % M; - if (m < l) return 0; - if (l > m - l) l = m - l; - while (l > 0) { - num = mul(num, m--, M); - den = mul(den, l--, M); - } - n /= M; k /= M; - } - return div(num, den, M); + // A^{-1} b = x + auto x = LU.solve(b); + cout << b << " " << (C * x) << endl; + cout << "end" << endl; } +void CF_QUADRATIC_EQUATIONS() { + int ncase; cin >> ncase; + for (int icase = 0; icase < ncase; ++icase) { + Int a, b, c, p; + cin >> a >> b >> c >> p; + ModInt::mod = p; + vector ans = quadraticEquation( + ModInt(a), ModInt(b), ModInt(c)); + cout << ans.size(); + for (int i = 0; i < ans.size(); ++i) + cout << " " << ans[i].val; + cout << endl; + } +} -// tick a time -double tick() { - static clock_t oldtick; - clock_t newtick = clock(); - double diff = 1.0*(newtick - oldtick) / CLOCKS_PER_SEC; - oldtick = newtick; - return diff; +void CF_DISCLOG() { + ModInt::mod = 999998999999; + ModInt a(21309), b(696969); + cout << log(a, b) << endl; } +int SPOJ_MIFF() { + for (int icase = 0; ; ++icase) { + int n, p; scanf("%d %d", &n, &p); + if (n == 0 && p == 0) break; + if (icase > 0) printf("\n"); + ModInt::mod = p; + ModMatrix A(n, n); + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + scanf("%d", &A(i,j)); + + ModMatrix B = A.inv(); + if (B.m > 0) { + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + printf("%d ", B(i,j)); + } + printf("\n"); + } + } else { + printf("singular\n"); + } + } +} -const int N = 10000000; -ll x[N]; int main() { + SPOJ_MIFF(); + //CF_DISCLOG(); + //CF_QUADRATIC_EQUATIONS(); + //mulTest(); } diff --git a/math/ODE_dormand_prince.cc b/numeric/ODE_dormand_prince.cc similarity index 100% rename from math/ODE_dormand_prince.cc rename to numeric/ODE_dormand_prince.cc diff --git a/math/ODE_runge_kutta.cc b/numeric/ODE_runge_kutta.cc similarity index 100% rename from math/ODE_runge_kutta.cc rename to numeric/ODE_runge_kutta.cc diff --git a/math/assignment.cc b/numeric/assignment.cc similarity index 100% rename from math/assignment.cc rename to numeric/assignment.cc diff --git a/numeric/chebyshev.cc b/numeric/chebyshev.cc new file mode 100644 index 0000000..c2b5b0e --- /dev/null +++ b/numeric/chebyshev.cc @@ -0,0 +1,125 @@ +// +// Chebyshev approximation of smooth function +// +// Description: +// +// Given a smooth function f: [0,1] -> R. It approximates f by +// f(x) \sim p(x) := sum_{k=0}^{n-1} ck Tk(x) +// where Tk(x) is the Chebyshev polynomial of the first kind: +// Tk(cos(u)) = cos(ku). +// This almost minimizes the maximum error: +// sup_x | f(x) - p(x) | +// This also provides accurate dp/dx and \int_{a^x} p(u) du. +// +// We can construct the Chebyshev approximation in O(n^2) time +// by using the orthogonality with Clenshow's relation. +// +// Complexity: +// +// O(n^2), where n is usually 10--30. +// +// References: +// +// C. W. Clenshaw (1995): +// "A note on the summation of Chebyshev series." +// Mathematical Tables and Other Aids to Computation. +// vol.9, no.51, pp.118--120. +// + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +using Real = long double; +struct Chebyshev { + static constexpr Real PI = acos(-1.0); + int n; + Real a, b; + vector c; + Chebyshev(Real a, Real b, int n) : n(n), a(a), b(b), c(n) { } + + template + Chebyshev(F f, Real a, Real b, int n = 20) : n(n), a(a), b(b), c(n) { + vector h(n); + for (int k = 0; k < n; ++k) { + Real y = cos(PI*(k+0.5)/n); + h[k] = f((b-a)/2*y + (b+a)/2); + } + for (int j = 0; j < n; ++j) { + for (int k = 0; k < n; ++k) + c[j] += h[k] * cos(PI*j*(k+0.5)/n); + c[j] *= 2.0/n; + } + } + Real operator()(Real x) const { + Real y = (2*x - a-b)/(b-a), u = 0, v = 0; + for (int j = n-1; j >= 1; --j) { + Real w = 2*y*u - v + c[j]; + v = u; u = w; + } + return y*u - v + 0.5*c[0]; + } +}; +Chebyshev differentiate(Chebyshev f) { + Chebyshev g = f; + g.c[f.n-2] = 2 * (f.n-1) * f.c[f.n-1]; + for (int j = f.n-3; j >= 0; --j) + g.c[j] = g.c[j+2] + 2 * (j+1) * f.c[j+1]; + for (int j = 0; j < g.n; ++j) + g.c[j] *= 2.0/(g.b - g.a); + return g; +} +Chebyshev integrate(Chebyshev f) { + Chebyshev g = f; + Real sum = 0, coef = (f.b-f.a)/4, sign = 1.0; + for (int j = 1; j <= g.n-2; ++j) { + g.c[j] = coef * (f.c[j-1] - f.c[j+1]) / j; + sum += sign * g.c[j]; + sign = -sign; + } + g.c[f.n-1] = coef * f.c[f.n-2] / (f.n-1); + sum += sign * g.c[f.n-1]; + g.c[0] = 2 * sum; + return g; +} + +int main() { + auto f = [&](Real x) { + return sqrt(1 + x*x); + }; + auto df = [&](Real x) { + return x / sqrt(1 + x*x); + }; + auto F = [&](Real x) { + return (x*sqrt(1 + x*x) + asinh(x))/2; + }; + Chebyshev g(f, 0, 1, 10); + Chebyshev dg = differentiate(g); + Chebyshev G = integrate(g); + + cout << "---" << endl; + for (int i = 0; i < 10; ++i) { + Real u = i / 10.0; + cout << f(u) - g(u) << endl; + } + cout << "---" << endl; + for (int i = 0; i < 10; ++i) { + Real u = i / 10.0; + cout << df(u) - dg(u) << endl; + } + cout << "---" << endl; + for (int i = 0; i < 10; ++i) { + Real u = i / 10.0; + cout << F(u) - G(u) << endl; + } +} diff --git a/math/derivative.cc b/numeric/derivative.cc similarity index 100% rename from math/derivative.cc rename to numeric/derivative.cc diff --git a/numeric/dual_number.cc b/numeric/dual_number.cc new file mode 100644 index 0000000..33fe5df --- /dev/null +++ b/numeric/dual_number.cc @@ -0,0 +1,58 @@ +// +// Automatic Differentiation by Dual Numbers +// +// Description: +// +// Dual number is an extended real number of the form a + epsilon b, +// where epsilon is the first order infinitesimal (i.e, epsilon^2 = 0). +// By overloading each function for dual numbers, as in the code, +// we can obtain the derivative of f at a by evaluating f(a + epsilon). +// +// Complexity: +// +// Linear in composition depth. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +using Real = double; +struct DualNumber { + Real a, b; // a + epsilon b + DualNumber(Real a = 0, Real b = 0) : a(a), b(b) { } + DualNumber &operator+=(DualNumber x) { b+=x.b; a+=x.a; return *this; } + DualNumber &operator*=(DualNumber x) { b=b*x.a+a*x.b; a*=x.a; return *this; } + DualNumber operator+() const { return *this; } + DualNumber operator-() const { return {-a, -b}; } + DualNumber inv() const { return {1.0/a, -b/(a*a)}; } + DualNumber &operator-=(DualNumber x) { return *this += -x; } + DualNumber &operator/=(DualNumber x) { return *this *= x.inv(); } +}; +DualNumber operator+(DualNumber x, DualNumber y) { return x += y; } +DualNumber operator-(DualNumber x, DualNumber y) { return x -= y; } +DualNumber operator*(DualNumber x, DualNumber y) { return x *= y; } +DualNumber operator/(DualNumber x, DualNumber y) { return x /= y; } + +// define functions with its derivative +DualNumber pow(DualNumber x, Real e) { return {pow(x.a,e),x.b*pow(x.a,e-1)}; } +DualNumber sqrt(DualNumber x) { return pow(x,0.5); } +DualNumber exp(DualNumber x) { return {exp(x.a),x.b*exp(x.a)}; } +DualNumber cos(DualNumber x) { return {cos(x.a),-x.b*sin(x.a)}; } +DualNumber sin(DualNumber x) { return {sin(x.a),x.b*cos(x.a)}; } +DualNumber tan(DualNumber x) { return sin(x)/cos(x); } +DualNumber log(DualNumber x) { return {log(x.a),x.b/x.a}; } + +int main() { + DualNumber x = 3, y = 4; + auto f = [&](DualNumber x) { + return sin(x*x) + cos(exp(x)) + tan(x); + }; + x.b = 1; // set infinitesimal part + cout << f(x).b << endl; +} + diff --git a/math/find_min_unimodal.cc b/numeric/find_min_unimodal.cc similarity index 100% rename from math/find_min_unimodal.cc rename to numeric/find_min_unimodal.cc diff --git a/math/integrate.cc b/numeric/integrate.cc similarity index 100% rename from math/integrate.cc rename to numeric/integrate.cc diff --git a/math/integrate_DE.cc b/numeric/integrate_DE.cc similarity index 100% rename from math/integrate_DE.cc rename to numeric/integrate_DE.cc diff --git a/math/nelder_mead.cc b/numeric/nelder_mead.cc similarity index 98% rename from math/nelder_mead.cc rename to numeric/nelder_mead.cc index f48bb0d..bd24796 100644 --- a/math/nelder_mead.cc +++ b/numeric/nelder_mead.cc @@ -2,7 +2,7 @@ // Nelder Mead method (aka. Downhill Simplex Method) // // Description: -// Nelder Mead method is a first-order optimization method +// Nelder Mead method is a zeroth-order optimization method // that only requires function evaluation oracle. // Typically, it performs well on a function on a small // dimensional space. diff --git a/string/dfa_minimization.cc b/string/dfa_minimization.cc new file mode 100644 index 0000000..731338a --- /dev/null +++ b/string/dfa_minimization.cc @@ -0,0 +1,289 @@ +// +// Deterministic Finite Automata Minimization +// +// Description: +// +// Hopcroft minimization algorithm. See Wikipedia. +// +// Complexity: +// +// O(|A| n log n). +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct Automaton { + vector> trans; + vector is_accept; + int init = 0; + int next(int state, int a) { return trans[state][a]; } + bool accept(int state) { return is_accept[state]; } + int size() { return trans.size(); } +}; +template +Automaton minimizeAutomaton(AM A) { + // remove unreachables + vector seen(A.size()); + seen[A.init] = 1; + vector partition = {A.init}, pos, label; + for (int i = 0; i < partition.size(); ++i) { + pos.push_back(i); + label.push_back(0); + int state = partition[i]; + for (int a = 0; a <= 9; ++a) { + int state_ = A.next(state, a); + if (!seen[state_]) { + seen[state_] = 1; + partition.push_back(state_); + } + } + } + // make inverse mapping + vector inverse[partition.size()][10]; + for (int i = 0; i < partition.size(); ++i) { + int state = partition[i]; + for (int a = 0; a <= 9; ++a) { + inverse[A.next(state, a)][a].push_back(state); + } + } + // Hopcroft minimization + vector begin = {0}, mid = {0}, end = {partition.size()}; + auto mark = [&](int state) { + int x = label[state]; + if (pos[state] < mid[x]) return; + int state_ = partition[mid[x]++]; + swap(pos[state], pos[state_]); + swap(partition[pos[state]], partition[pos[state_]]); + }; + auto refine = [&](int x) { + if (mid[x] == begin[x]) return -1; + if (mid[x] == end[x]) { mid[x] = begin[x]; return -1; } + int y = begin.size(); + if (mid[x] - begin[x] < end[x] - mid[x]) { + begin.push_back(begin[x]); + end.push_back(mid[x]); + mid.push_back(begin[x]); + begin[x] = mid[x]; + } else { + begin.push_back(mid[x]); + end.push_back(end[x]); + mid.push_back(mid[x]); + end[x] = mid[x]; + mid[x] = begin[x]; + } + for (int i = begin.back(); i < end.back(); ++i) + label[partition[i]] = y; + return y; + }; + for (int state: partition) + if (A.accept(state)) mark(state); + + if (refine(0) >= 0) { // do Hopcroft minimization + fill(all(seen), 0); + seen[0] = seen[1] = 1; + vector process = {0, 1}; + vector is_suspect(partition.size()); + while (!process.empty()) { + int x = process.back(); process.pop_back(); + seen[x] = 0; + for (int a = 0; a <= 9; ++a) { + vector suspect; + for (int i = begin[x]; i < end[x]; ++i) { + int u = partition[i]; + for (int state: inverse[u][a]) { + int y = label[state]; + mark(state); + if (!is_suspect[y]) { + is_suspect[y] = 1; + suspect.push_back(y); + } + } + } + for (int y: suspect) { + is_suspect[y] = 0; + int z = refine(y); + if (z < 0) continue; + if (seen[y]) { + process.push_back(z); + seen[z] = 1; + } else { + if (end[y] - begin[y] < end[z] - begin[z]) { + process.push_back(y); + seen[y] = 1; + } else { + process.push_back(z); + seen[z] = 1; + } + } + } + } + } + } + Automaton M; // completion + M.trans.assign(begin.size(), vector(10)); + M.is_accept.resize(begin.size()); + for (int x = 0; x < begin.size(); ++x) { + int state = partition[begin[x]]; + M.is_accept[x] = A.accept(state); + for (int a = 0; a <= 9; ++a) { + int y = label[A.next(state, a)]; + M.trans[x][a] = label[A.next(state, a)]; + } + } + M.init = label[A.init]; + return M; +} + + +// state = x : x == n % mod +struct ModuloAutomaton { + int mod; + ModuloAutomaton(int mod) : mod(mod) { } + int init = 0; + int size() { return mod; } + int next(int state, int a) { return (10 * state + a) % mod; } + bool accept(int state) { return state == 0; } +}; +// state = 0 : empty +// 1 : fail +// 2 ... 10 : singleton and last number is state-1 +// 11 ... 19 : increased and last number is state-10 +// 20 ... 28 : decreased and last number is state-20 +struct ZigZagAutomaton { + int init = 0; + int size() { return 29; } + int next(int state, int a) { + if (state == 0) return a == 0 ? 0 : a + 1; + if (state == 1) return 1; + if (state <= 10) { + int last = state - 1; + if (a > last) return a + 10; + else if (a < last) return a + 20; + } else if (state <= 19) { + int last = state - 10; + if (a < last) return a + 20; + } else if (state <= 28) { + int last = state - 20; + if (a > last) return a + 10; + } + return 1; + } + bool accept(int state) { return state != 1; } +}; +template +Automaton intersectionAutomaton(Automaton1 A, Automaton2 B) { + Automaton M; + vector> table(A.size(), vector(B.size(), -1)); + vector x = {A.init}, y = {B.init}; + table[x[0]][y[0]] = 0; + for (int i = 0; i < x.size(); ++i) { + M.trans.push_back(vector(10, -1)); + M.is_accept.push_back(A.accept(x[i]) && B.accept(y[i])); + for (int a = 0; a <= 9; ++a) { + int u = A.next(x[i], a), v = B.next(y[i], a); + if (table[u][v] == -1) { + table[u][v] = x.size(); + x.push_back(u); + y.push_back(v); + } + M.trans[i][a] = table[u][v]; + } + } + return M; +} + +template +int digitDP(string num, Automaton A, int eq = 1) { + int n = num.size(); + vector>> dp(n+1); + + dp[0] = vector>(2, vector(A.size())); + dp[0][1][A.init] = 1; + auto addTo = [&](int &x, int y) { + if ((x += y) >= 10000) x -= 10000; + }; + for (int i = 0; i < n; ++i) { + dp[i+1] = vector>(2, vector(A.size())); + for (int tight = 0; tight <= 1; ++tight) { + for (int state = 0; state < A.size(); ++state) { + if (dp[i][tight][state] == 0) continue; + int lim = (tight ? num[i] - '0' : 9); + for (int d = 0; d <= lim; ++d) { + int tight_ = tight && d == lim; + int state_ = A.next(state, d); + addTo(dp[i+1][tight_][state_], dp[i][tight][state]); + } + } + } + dp[i].clear(); + } + int ans = 0; + for (int tight = 0; tight <= eq; ++tight) + for (int state = 0; state < A.size(); ++state) + if (A.accept(state)) addTo(ans, dp[n][tight][state]); + return ans; +} + +template +int debug(string num, Automaton A) { + function rec + = [&](int i, int tight, int state, string s) { + if (i == num.size()) { + if (A.accept(state)) cout << s << endl; + return; + } + int lim = (tight ? num[i] - '0' : 9); + for (int d = 0; d <= lim; ++d) { + int tight_ = tight && d == lim; + int state_ = A.next(state, d); + s.push_back('0' + d); + rec(i+1, tight_, state_, s); + s.pop_back(); + } + }; + rec(0, 1, A.init, ""); +} + +void AOJ_ZIGZAG() { + char A[1000], B[1000]; + int M; + scanf("%s %s %d", A, B, &M); + ZigZagAutomaton zigzag; + ModuloAutomaton modulo(M); + auto IM = minimizeAutomaton(intersectionAutomaton(zigzag, modulo)); + int a = digitDP(A, IM, 0); + int b = digitDP(B, IM, 1); + cout << (b + (10000 - a)) % 10000 << endl; +} +int main() { + AOJ_ZIGZAG(); + /* + Automaton A; + A.trans.assign(7, vector(10, 6)); + A.trans[0][0] = 1; + A.trans[0][1] = 2; + A.trans[1][0] = 0; + A.trans[1][1] = 3; + A.trans[2][0] = 4; + A.trans[2][1] = 5; + A.trans[3][0] = 4; + A.trans[3][1] = 5; + A.trans[4][0] = 4; + A.trans[4][1] = 5; + A.trans[5][0] = 5; + A.trans[5][1] = 5; + A.is_accept.assign(7, 0); + A.is_accept[2] = 1; + A.is_accept[3] = 1; + A.is_accept[4] = 1; + auto B = minimizeAutomaton(A); + cout << B.size() << endl; + */ + //minimizeAutomaton(ZigZagAutomaton()); +} diff --git a/string/factor_automaton.cc b/string/factor_automaton.cc deleted file mode 100644 index 6b38e12..0000000 --- a/string/factor_automaton.cc +++ /dev/null @@ -1,134 +0,0 @@ -// -// Factor Automaton (aka. Directed Acyclig Word Graph) -// -// Description: -// For a given string s, the factor automaton is an -// automaton that accepts all substrings s[i,j). -// The automaton has O(n) state. -// -// Algorithm: -// Blumer et al's online construction. -// See Section 6.3 of Crochemore-Rytter. -// -// Complexity: -// O(n) time and space. -// -// Verified: -// SPOJ 22531 -// -// References: -// A. Blumer, J. Blumer, D. Haussler, A. Ehrenfeucht, -// M. T. Chen, and J. Seiferas (1985): -// The smallest automation recognizing the subwords of a text. -// Theoretical Computer Science, vol. 40, pp. 31-55. -// -// M. Crochemore, and W. Rytter (1994): -// Text Algorithms. -// Oxford University Press. -// -#include -#include -#include -#include -#include -#include - -using namespace std; - -#define fst first -#define snd second -#define all(c) ((c).begin()), ((c).end()) - -struct factor_automaton { - vector> link; - vector> bold; - vector suf; - int root; - int add_node() { - link.push_back(vector(0x100)); - bold.push_back(vector(0x100)); - suf.push_back(0); - return link.size()-1; - } - factor_automaton(const char s[]) { - add_node(); // = nil - int sink = root = add_node(); - suf[root] = 0; - for (int i = 0; s[i]; ++i) { - char a = s[i]; - int newsink = add_node(); - link[sink][a] = newsink; - bold[sink][a] = true; - int w = suf[sink]; - while (w != 0 && link[w][a] == 0) { - link[w][a] = newsink; - bold[w][a] = false; - w = suf[w]; - } - int v = link[w][a]; - if (w == 0) suf[newsink] = root; - else if (bold[w][a]) suf[newsink] = v; - else { - int newnode = add_node(); - link[newnode] = link[v]; - link[w][a] = newnode; - bold[w][a] = true; - suf[newsink] = newnode; - suf[newnode] = suf[v]; - suf[v] = newnode; - w = suf[w]; - while (w != 0 && link[w][a] == v && bold[w][a] == false) { - link[w][a] = newnode; - w = suf[w]; - } - } - sink = newsink; - } - } - - void disp() { - cout << "--- display ---" << endl; - for (int i = 1; i < link.size(); ++i) { - cout << " state " << i << endl; - for (int c = 0; c < 0x100; ++c) { - if (link[i][c] > 0) { - if (bold[i][c]) cout << " ==" << (char)c << "==> " << link[i][c] << endl; - else cout << " --" << (char)c << "--> " << link[i][c] << endl; - } - } - } - - } -}; - - -int main() { - for (char text[100000]; ~scanf("%s", text); ) { - factor_automaton FA(text); - - vector> prev(FA.link.size()); - queue que; - que.push(FA.root); - while (prev[0].fst == 0) { - int s = que.front(); - que.pop(); - for (int c = 'A'; c <= 'Z'; ++c) { - //for (int c = 'A'; c <= 'B'; ++c) { // for test - if (prev[FA.link[s][c]].fst == 0) { - prev[FA.link[s][c]] = {s, c}; - que.push(FA.link[s][c]); - //cout << s << " --" << (char)c << "--> " << FA.link[s][c] << endl; - } - } - } - int s = 0; - vector result; - do { - result.push_back(prev[s].snd); - s = prev[s].fst; - } while (s > 1); - for (int i = result.size()-1; i >= 0; --i) - printf("%c", result[i]); - printf("\n"); - } -} diff --git a/string/suffix_automaton.cc b/string/suffix_automaton.cc new file mode 100644 index 0000000..8e6e64a --- /dev/null +++ b/string/suffix_automaton.cc @@ -0,0 +1,167 @@ +// +// Suffix Automaton (aka. Suffix Directed Acyclic Word Graph) +// +// Description: +// +// It is an automaton that accepts all suffixes +// of a given string. It can be constructed in O(n) time +// by using Blumer et al.'s online construction. +// +// Note that a factor automaton is obtained from +// the suffix automaton by setting the all states as terminal. +// +// Complexity: +// O(n) +// +// Verified: +// +// SPOJ_SUBST1 +// SPOJ_SUBLEX +// +// References: +// A. Blumer, J. Blumer, D. Haussler, A. Ehrenfeucht, +// M. T. Chen, and J. Seiferas (1985): +// The smallest automation recognizing the subwords of a text. +// Theoretical Computer Science, vol. 40, pp. 31-55. +// +// M. Crochemore, and W. Rytter (1994): +// Text Algorithms. +// Oxford University Press. +// +#include + +using namespace std; + +#define fst first +#define snd second +#define all(c) ((c).begin()), ((c).end()) +#define TEST(s) if (!(s)) { cout << __LINE__ << " " << #s << endl; exit(-1); } + +struct SuffixAutomaton { + vector length = {0}; // maximum length corresponding to the node + vector link = {-1}; // suffix link of the node + vector> next = {map()}; + int size() const { return next.size(); } + + int extend(int p, int c) { + int head = next.size(); + length.push_back(length[p]+1); + link.push_back(0); + next.push_back(map()); + while (p >= 0 && !next[p].count(c)) { + next[p][c] = head; + p = link[p]; + } + if (p >= 0) { + int q = next[p][c]; + if (length[p]+1 == length[q]) { + link[head] = q; + } else { + int clone = next.size(); // clone of q + length.push_back(length[p]+1); + link.push_back(link[q]); + next.push_back(next[q]); + link[q] = link[head] = clone; + while (p >= 0 && next[p][c] == q) { + next[p][c] = clone; + p = link[p]; + } + } + } + return head; + } + vector topological_order; + SuffixAutomaton(const char s[]) { // can be constructed online + int p = 0; + for(int i = 0; s[i]; ++i) + p = extend(p, s[i]); + vector mark(size()); // topological sort + for (int i = 0; i < size(); ++i) + for (auto z: next[i]) ++mark[z.snd]; + topological_order.push_back(0); + for (int i = 0; i < size(); ++i) + for (auto z: next[i]) + if (--mark[z.snd] == 0) topological_order.push_back(z.snd); + } + template // topological order + void process(F func) { + for (int i = 0; i < topological_order.size(); ++i) func(i); + } + template + void processRev(F func) { // reverse topological order + for (int i = topological_order.size()-1; i >= 0; --i) func(i); + } +}; +int countDistinctSubstrings(const char s[]) { + SuffixAutomaton M(s); + vector dp(M.size()); + int ans = 0; + dp[0] = 1; + M.process([&](int i) { + ans += dp[i]; + for (auto z: M.next[i]) + dp[z.snd] += dp[i]; + }); + return ans; +} + +string kthSubstring(const char s[], int k) { + SuffixAutomaton M(s); + vector num_terminal(M.size()); // preprocess that can be reused + M.processRev([&](int i) { + num_terminal[i] = 1; + for (auto z: M.next[i]) + num_terminal[i] += num_terminal[z.snd]; + }); + string ret; // answer to query + for (int p = 0; k-- > 0; ) { + for (auto z: M.next[p]) { + if (num_terminal[z.snd] > k) { + ret.push_back(z.fst); + p = z.snd; break; + } else k -= num_terminal[z.snd]; + } + } + return ret; +} + +void SPOJ_SUBST1() { + int ncase; + scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + char s[100000]; + scanf("%s", s); + printf("%d\n", countDistinctSubstrings(s)-1); + } +} +void SPOJ_SUBLEX() { + char s[100000]; + scanf("%s", s); + SuffixAutomaton M(s); + + vector num_terminal(M.size()); + M.processRev([&](int i) { + num_terminal[i] = 1; + for (auto z: M.next[i]) + num_terminal[i] += num_terminal[z.snd]; + }); + int ncase; scanf("%d", &ncase); + for (int icase = 0; icase < ncase; ++icase) { + int k; scanf("%d", &k); + string ret; + for (int p = 0; k-- > 0; ) { + for (auto z: M.next[p]) { + if (num_terminal[z.snd] > k) { + ret.push_back(z.fst); + p = z.snd; break; + } else k -= num_terminal[z.snd]; + } + } + printf("%s\n", ret.c_str()); + } +} + +int main() { + //SPOJ_SUBST1(); + SPOJ_SUBLEX(); +}