diff --git a/README.md b/README.md index e133a2b..d721fd7 100644 --- a/README.md +++ b/README.md @@ -25,165 +25,165 @@ ![doughnut](https://assets-cdn.github.com/images/icons/emoji/unicode/1f369.png?v5) ![cookie](https://assets-cdn.github.com/images/icons/emoji/unicode/1f36a.png?v5) - - + + **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [1. Basic](#1-basic) - - [1.1 C++ Solution Template](#11-c-solution-template) - - [1.1.1 Optional include list](#111-optional-include-list) - - [1.2 Strings](#12-strings) - - [1.2.1 C++ String](#121-c-string) - - [read one line](#read-one-line) - - [Convert to char array](#convert-to-char-array) - - [1.2.2 C String (Character Array)](#122-c-string-character-array) - - [Input C String](#input-c-string) - - [Convert to C++ string](#convert-to-c-string) - - [1.3 STL Algorithm](#13-stl-algorithm) - - [1.3.1 Permutation](#131-permutation) - - [1.3.2 Binary Search](#132-binary-search) - - [1.3.3 Lower Bound](#133-lower-bound) - - [1.3.4 Swap](#134-swap) - - [1.3.5 Heap](#135-heap) - - [1.3.6 Sort](#136-sort) - - [1.3.7 Compare](#137-compare) - - [Using lambda expression](#using-lambda-expression) - - [Compare function](#compare-function) - - [Define operator <()](#define-operator-) - - [Define operator()()](#define-operator) - - [1.4 STL Containers](#14-stl-containers) - - [1.4.1 Map](#141-map) - - [Define a Map](#define-a-map) - - [Commonly used method](#commonly-used-method) - - [Red-black Tree](#red-black-tree) - - [Hash Map (Unordered Map)](#hash-map-unordered-map) - - [Commonly used method](#commonly-used-method-1) - - [1.4.2 Pair](#142-pair) - - [1.4.3 Vector](#143-vector) - - [Constructor](#constructor) - - [Methods](#methods) - - [1.4.4 List](#144-list) - - [Methods](#methods-1) - - [1.4.5 Queue](#145-queue) - - [1.4.6 Double-ended Queue](#146-double-ended-queue) - - [1.4.7 Stack](#147-stack) - - [1.4.8 Priority Queue](#148-priority-queue) -- [2. Advanced Data Structures](#2-advanced-data-structures) - - [2.1 Heap](#21-heap) - - [2.2 Tree](#22-tree) - - [2.2.0 Tree Traversal](#220-tree-traversal) - - [2.2.1 Pointer Jumping](#221-pointer-jumping) - - [2.2.2 Heavy-Light Decomposition](#222-heavy-light-decomposition) - - [2.2.3 Lowest Common Ancestor](#223-lowest-common-ancestor) - - [2.2.3.1 Tarjan's Off-line Algorithm](#2231-tarjans-off-line-algorithm) - - [2.2.4 Centroid Decomposition](#224-centroid-decomposition) - - [2.3 Trie / Trie Graph / AC Automaton](#23-trie--trie-graph--ac-automaton) - - [2.4 Suffix Tree](#24-suffix-tree) - - [2.5 Suffix Array](#25-suffix-array) - - [2.5.1 Build Suffix Array](#251-build-suffix-array) - - [2.5.2 Pattern Matching](#252-pattern-matching) - - [2.5.3 Longest Common Prefix](#253-longest-common-prefix) - - [2.5.4 Longest Repeated Substring](#254-longest-repeated-substring) - - [2.5.5 Longest Common Substring](#255-longest-common-substring) - - [2.6 Binary Indexed Tree](#26-binary-indexed-tree) - - [2.7 Segment Tree](#27-segment-tree) - - [2.7.0 Range Update + Range Query](#270-range-update--range-query) - - [2.7.1 Color](#271-color) - - [2.7.2 Range Sum + Range Replace](#272-range-sum--range-replace) - - [2.8 Range Minimum Query RMQ](#28-range-minimum-query-rmq) - - [2.9 Union-find Set](#29-union-find-set) - - [2.9.1 Union-find Set - application](#291-union-find-set---application) - - [2.10 Bloom Filter (?) (Similar)](#210-bloom-filter--similar) -- [3. Methodology](#3-methodology) - - [3.0 Greedy](#30-greedy) - - [3.1 Recursive](#31-recursive) - - [3.1.1 Hanoi](#311-hanoi) - - [3.2 Dynamic Programming](#32-dynamic-programming) - - [3.2.1 Longest Increasing Subsequence (LIS)](#321-longest-increasing-subsequence-lis) - - [3.3 Divide and Conquer](#33-divide-and-conquer) - - [3.3.1 binary search](#331-binary-search) - - [3.4 Search](#34-search) - - [3.4.2 双向 BFS](#342-%E5%8F%8C%E5%90%91-bfs) - - [3.4.3 从终点开始搜](#343-%E4%BB%8E%E7%BB%88%E7%82%B9%E5%BC%80%E5%A7%8B%E6%90%9C) - - [3.4.4 迭代加深搜索 (binary increase/decrease)](#344-%E8%BF%AD%E4%BB%A3%E5%8A%A0%E6%B7%B1%E6%90%9C%E7%B4%A2-binary-increasedecrease) - - [3.5 Brute Force](#35-brute-force) - - [3.5.1 子集生成](#351-%E5%AD%90%E9%9B%86%E7%94%9F%E6%88%90) -- [4. String](#4-string) - - [4.1 KMP](#41-kmp) - - [4.2 Boyer-Moore](#42-boyer-moore) - - [4.3 Longest palindromic substring (Manacher's algorithm)](#43-longest-palindromic-substring-manachers-algorithm) -- [5. Graph](#5-graph) - - [5.1 Graph Structure](#51-graph-structure) - - [5.2 Minimium Spanning Tree](#52-minimium-spanning-tree) - - [5.2.1 Prim's](#521-prims) - - [5.2.2 Kruskal](#522-kruskal) - - [5.3 Shortest Path](#53-shortest-path) - - [5.3.1 任意两点](#531-%E4%BB%BB%E6%84%8F%E4%B8%A4%E7%82%B9) - - [5.3.2 Bellman–Ford](#532-bellman%E2%80%93ford) - - [5.3.3 SPFA](#533-spfa) - - [5.3.4 Dijkstra](#534-dijkstra) - - [5.4 Maximum Matching](#54-maximum-matching) - - [5.4.1 on Bipartite Graph 二分图](#541-on-bipartite-graph-%E4%BA%8C%E5%88%86%E5%9B%BE) - - [5.4.1.1 Hungarian algorithm 匈牙利算法](#5411-hungarian-algorithm-%E5%8C%88%E7%89%99%E5%88%A9%E7%AE%97%E6%B3%95) - - [5.4.1.2 Hopcroft–Karp Algorithm](#5412-hopcroft%E2%80%93karp-algorithm) - - [5.4.2 on General Graph](#542-on-general-graph) - - [5.4.2.1 Blossom Algorithm](#5421-blossom-algorithm) - - [5.5 Maximum Flow Problem 最大流](#55-maximum-flow-problem-%E6%9C%80%E5%A4%A7%E6%B5%81) - - [5.5.1 Dinic](#551-dinic) - - [5.5.2 Improved SAP + Gap Optimization](#552-improved-sap--gap-optimization) - - [5.5.3 Minimum-Cost Maximum-Flow](#553-minimum-cost-maximum-flow) - - [5.5.4 More Applications and Properties](#554-more-applications-and-properties) - - [5.6 强连通分量 图的 割点, 桥, 双连通分支](#56-%E5%BC%BA%E8%BF%9E%E9%80%9A%E5%88%86%E9%87%8F-%E5%9B%BE%E7%9A%84-%E5%89%B2%E7%82%B9-%E6%A1%A5-%E5%8F%8C%E8%BF%9E%E9%80%9A%E5%88%86%E6%94%AF) - - [5.7 Topological Sort / 拓扑排序](#57-topological-sort--%E6%8B%93%E6%89%91%E6%8E%92%E5%BA%8F) - - [5.8 Euler Cycle/Path, Hamilton Cycle/Path](#58-euler-cyclepath-hamilton-cyclepath) - - [5.9 find negative (weight) Cycle on a graph](#59-find-negative-weight-cycle-on-a-graph) -- [6. Number + Mathematics](#6-number--mathematics) - - [6.1 BigInteger + BigDecimal](#61-biginteger--bigdecimal) - - [6.1.1 C++ Big Integer](#611-c-big-integer) - - [6.1.2 The Java Approach](#612-the-java-approach) - - [6.2 Matrix](#62-matrix) - - [6.3 Number Theory](#63-number-theory) - - [6.3.1 欧拉函数 ?](#631-%E6%AC%A7%E6%8B%89%E5%87%BD%E6%95%B0-) - - [6.3.2 欧几里得算法 / gcd](#632-%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E7%AE%97%E6%B3%95--gcd) - - [6.3.3 扩展欧几里得算法](#633-%E6%89%A9%E5%B1%95%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E7%AE%97%E6%B3%95) - - [6.3.4 求解不定方程](#634-%E6%B1%82%E8%A7%A3%E4%B8%8D%E5%AE%9A%E6%96%B9%E7%A8%8B) - - [6.3.5 求解模线性方程(线性同余方程)](#635-%E6%B1%82%E8%A7%A3%E6%A8%A1%E7%BA%BF%E6%80%A7%E6%96%B9%E7%A8%8B%EF%BC%88%E7%BA%BF%E6%80%A7%E5%90%8C%E4%BD%99%E6%96%B9%E7%A8%8B%EF%BC%89) - - [6.3.6 求解模的逆元](#636-%E6%B1%82%E8%A7%A3%E6%A8%A1%E7%9A%84%E9%80%86%E5%85%83) - - [6.3.7 中国剩余定理](#637-%E4%B8%AD%E5%9B%BD%E5%89%A9%E4%BD%99%E5%AE%9A%E7%90%86) - - [6.3.8 最小公倍数](#638-%E6%9C%80%E5%B0%8F%E5%85%AC%E5%80%8D%E6%95%B0) - - [6.3.9 分解质因数](#639-%E5%88%86%E8%A7%A3%E8%B4%A8%E5%9B%A0%E6%95%B0) - - [6.3.10 因数个数](#6310-%E5%9B%A0%E6%95%B0%E4%B8%AA%E6%95%B0) - - [6.3.11 素数判定](#6311-%E7%B4%A0%E6%95%B0%E5%88%A4%E5%AE%9A) - - [6.3.11.1 Miller Rabin Primality Test](#63111-miller-rabin-primality-test) - - [6.3.12 进制转换](#6312-%E8%BF%9B%E5%88%B6%E8%BD%AC%E6%8D%A2) - - [6.3.13 A / C](#6313-a--c) - - [6.3.14 质数表](#6314-%E8%B4%A8%E6%95%B0%E8%A1%A8) - - [6.3.15 Fast Exponention](#6315-fast-exponention) - - [6.3.16 Fast Fourier Transform FFT](#6316-fast-fourier-transform-fft) - - [6.4 Game Theory 博弈论](#64-game-theory-%E5%8D%9A%E5%BC%88%E8%AE%BA) - - [6.4.1 Impartial Combinatorial Game](#641-impartial-combinatorial-game) - - [6.4.1.1 Nim Game](#6411-nim-game) - - [6.4.1.1 Composite Games – Sprague-Grundy Theorem and Nim Value](#6411-composite-games-%E2%80%93-sprague-grundy-theorem-and-nim-value) -- [7. Geometry](#7-geometry) - - [7.1 2-Dimension Space](#71-2-dimension-space) - - [7.1.1 Template of Point](#711-template-of-point) - - [7.1.2 向量点乘 叉乘](#712-%E5%90%91%E9%87%8F%E7%82%B9%E4%B9%98-%E5%8F%89%E4%B9%98) - - [7.1.3 dot product](#713-dot-product) - - [7.1.4 cross product](#714-cross-product) - - [7.1.5 直线公式](#715-%E7%9B%B4%E7%BA%BF%E5%85%AC%E5%BC%8F) - - [7.1.6 Convex Hull](#716-convex-hull) - - [Gift Wrapping](#gift-wrapping) - - [QuickHull](#quickhull) - - [Graham scan](#graham-scan) -- [8. Tricks + Miscellaneous](#8-tricks--miscellaneous) - - [8.1 Bit Manipulation](#81-bit-manipulation) - - [8.1 Cantor Expansion / Reverse Cantor Expansion](#81-cantor-expansion--reverse-cantor-expansion) - - [8.2 pass 2-D array](#82-pass-2-d-array) - - [8.3 Binary Display](#83-binary-display) - - [8.4 Fast Log](#84-fast-log) - - [8.5 Squre Root](#85-squre-root) - - + +- [1. Basic](#1-basic) + - [1.1 C++ Solution Template](#11-c-solution-template) + - [1.1.1 Optional include list](#111-optional-include-list) + - [1.2 Strings](#12-strings) + - [1.2.1 C++ String](#121-c-string) + - [read one line](#read-one-line) + - [Convert to char array](#convert-to-char-array) + - [1.2.2 C String (Character Array)](#122-c-string-character-array) + - [Input C String](#input-c-string) + - [Convert to C++ string](#convert-to-c-string) + - [1.3 STL Algorithm](#13-stl-algorithm) + - [1.3.1 Permutation](#131-permutation) + - [1.3.2 Binary Search](#132-binary-search) + - [1.3.3 Lower Bound](#133-lower-bound) + - [1.3.4 Swap](#134-swap) + - [1.3.5 Heap](#135-heap) + - [1.3.6 Sort](#136-sort) + - [1.3.7 Compare](#137-compare) + - [Using lambda expression](#using-lambda-expression) + - [Compare function](#compare-function) + - [Define operator <()](#define-operator-) + - [Define operator()()](#define-operator) + - [1.4 STL Containers](#14-stl-containers) + - [1.4.1 Map](#141-map) + - [Define a Map](#define-a-map) + - [Commonly used method](#commonly-used-method) + - [Red-black Tree](#red-black-tree) + - [Hash Map (Unordered Map)](#hash-map-unordered-map) + - [Commonly used method](#commonly-used-method-1) + - [1.4.2 Pair](#142-pair) + - [1.4.3 Vector](#143-vector) + - [Constructor](#constructor) + - [Methods](#methods) + - [1.4.4 List](#144-list) + - [Methods](#methods-1) + - [1.4.5 Queue](#145-queue) + - [1.4.6 Double-ended Queue](#146-double-ended-queue) + - [1.4.7 Stack](#147-stack) + - [1.4.8 Priority Queue](#148-priority-queue) +- [2. Advanced Data Structures](#2-advanced-data-structures) + - [2.1 Heap](#21-heap) + - [2.2 Tree](#22-tree) + - [2.2.0 Tree Traversal](#220-tree-traversal) + - [2.2.1 Pointer Jumping](#221-pointer-jumping) + - [2.2.2 Heavy-Light Decomposition](#222-heavy-light-decomposition) + - [2.2.3 Lowest Common Ancestor](#223-lowest-common-ancestor) + - [2.2.3.1 Tarjan's Off-line Algorithm](#2231-tarjans-off-line-algorithm) + - [2.2.4 Centroid Decomposition](#224-centroid-decomposition) + - [2.3 Trie / Trie Graph / AC Automaton](#23-trie--trie-graph--ac-automaton) + - [2.4 Suffix Tree](#24-suffix-tree) + - [2.5 Suffix Array](#25-suffix-array) + - [2.5.1 Build Suffix Array](#251-build-suffix-array) + - [2.5.2 Pattern Matching](#252-pattern-matching) + - [2.5.3 Longest Common Prefix](#253-longest-common-prefix) + - [2.5.4 Longest Repeated Substring](#254-longest-repeated-substring) + - [2.5.5 Longest Common Substring](#255-longest-common-substring) + - [2.6 Binary Indexed Tree](#26-binary-indexed-tree) + - [2.7 Segment Tree](#27-segment-tree) + - [2.7.0 Range Update + Range Query](#270-range-update--range-query) + - [2.7.1 Color](#271-color) + - [2.7.2 Range Sum + Range Replace](#272-range-sum--range-replace) + - [2.8 Range Minimum Query RMQ](#28-range-minimum-query-rmq) + - [2.9 Union-find Set](#29-union-find-set) + - [2.9.1 Union-find Set - application](#291-union-find-set---application) + - [2.10 Bloom Filter (?) (Similar)](#210-bloom-filter--similar) +- [3. Methodology](#3-methodology) + - [3.0 Greedy](#30-greedy) + - [3.1 Recursive](#31-recursive) + - [3.1.1 Hanoi](#311-hanoi) + - [3.2 Dynamic Programming](#32-dynamic-programming) + - [3.2.1 Longest Increasing Subsequence (LIS)](#321-longest-increasing-subsequence-lis) + - [3.3 Divide and Conquer](#33-divide-and-conquer) + - [3.3.1 binary search](#331-binary-search) + - [3.4 Search](#34-search) + - [3.4.2 双向 BFS](#342-%E5%8F%8C%E5%90%91-bfs) + - [3.4.3 从终点开始搜](#343-%E4%BB%8E%E7%BB%88%E7%82%B9%E5%BC%80%E5%A7%8B%E6%90%9C) + - [3.4.4 迭代加深搜索 (binary increase/decrease)](#344-%E8%BF%AD%E4%BB%A3%E5%8A%A0%E6%B7%B1%E6%90%9C%E7%B4%A2-binary-increasedecrease) + - [3.5 Brute Force](#35-brute-force) + - [3.5.1 子集生成](#351-%E5%AD%90%E9%9B%86%E7%94%9F%E6%88%90) +- [4. String](#4-string) + - [4.1 KMP](#41-kmp) + - [4.2 Boyer-Moore](#42-boyer-moore) + - [4.3 Longest palindromic substring (Manacher's algorithm)](#43-longest-palindromic-substring-manachers-algorithm) +- [5. Graph](#5-graph) + - [5.1 Graph Structure](#51-graph-structure) + - [5.2 Minimium Spanning Tree](#52-minimium-spanning-tree) + - [5.2.1 Prim's](#521-prims) + - [5.2.2 Kruskal](#522-kruskal) + - [5.3 Shortest Path](#53-shortest-path) + - [5.3.1 任意两点](#531-%E4%BB%BB%E6%84%8F%E4%B8%A4%E7%82%B9) + - [5.3.2 Bellman–Ford](#532-bellman%E2%80%93ford) + - [5.3.3 SPFA](#533-spfa) + - [5.3.4 Dijkstra](#534-dijkstra) + - [5.4 Maximum Matching](#54-maximum-matching) + - [5.4.1 on Bipartite Graph 二分图](#541-on-bipartite-graph-%E4%BA%8C%E5%88%86%E5%9B%BE) + - [5.4.1.1 Hungarian algorithm 匈牙利算法](#5411-hungarian-algorithm-%E5%8C%88%E7%89%99%E5%88%A9%E7%AE%97%E6%B3%95) + - [5.4.1.2 Hopcroft–Karp Algorithm](#5412-hopcroft%E2%80%93karp-algorithm) + - [5.4.2 on General Graph](#542-on-general-graph) + - [5.4.2.1 Blossom Algorithm](#5421-blossom-algorithm) + - [5.5 Maximum Flow Problem 最大流](#55-maximum-flow-problem-%E6%9C%80%E5%A4%A7%E6%B5%81) + - [5.5.1 Dinic](#551-dinic) + - [5.5.2 Improved SAP + Gap Optimization](#552-improved-sap--gap-optimization) + - [5.5.3 Minimum-Cost Maximum-Flow](#553-minimum-cost-maximum-flow) + - [5.5.4 More Applications and Properties](#554-more-applications-and-properties) + - [5.6 强连通分量 图的 割点, 桥, 双连通分支](#56-%E5%BC%BA%E8%BF%9E%E9%80%9A%E5%88%86%E9%87%8F-%E5%9B%BE%E7%9A%84-%E5%89%B2%E7%82%B9-%E6%A1%A5-%E5%8F%8C%E8%BF%9E%E9%80%9A%E5%88%86%E6%94%AF) + - [5.7 Topological Sort / 拓扑排序](#57-topological-sort--%E6%8B%93%E6%89%91%E6%8E%92%E5%BA%8F) + - [5.8 Euler Cycle/Path, Hamilton Cycle/Path](#58-euler-cyclepath-hamilton-cyclepath) + - [5.9 find negative (weight) Cycle on a graph](#59-find-negative-weight-cycle-on-a-graph) +- [6. Number + Mathematics](#6-number--mathematics) + - [6.1 BigInteger + BigDecimal](#61-biginteger--bigdecimal) + - [6.1.1 C++ Big Integer](#611-c-big-integer) + - [6.1.2 The Java Approach](#612-the-java-approach) + - [6.2 Matrix](#62-matrix) + - [6.3 Number Theory](#63-number-theory) + - [6.3.1 欧拉函数 ?](#631-%E6%AC%A7%E6%8B%89%E5%87%BD%E6%95%B0-) + - [6.3.2 欧几里得算法 / gcd](#632-%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E7%AE%97%E6%B3%95--gcd) + - [6.3.3 扩展欧几里得算法](#633-%E6%89%A9%E5%B1%95%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E7%AE%97%E6%B3%95) + - [6.3.4 求解不定方程](#634-%E6%B1%82%E8%A7%A3%E4%B8%8D%E5%AE%9A%E6%96%B9%E7%A8%8B) + - [6.3.5 求解模线性方程(线性同余方程)](#635-%E6%B1%82%E8%A7%A3%E6%A8%A1%E7%BA%BF%E6%80%A7%E6%96%B9%E7%A8%8B%EF%BC%88%E7%BA%BF%E6%80%A7%E5%90%8C%E4%BD%99%E6%96%B9%E7%A8%8B%EF%BC%89) + - [6.3.6 求解模的逆元](#636-%E6%B1%82%E8%A7%A3%E6%A8%A1%E7%9A%84%E9%80%86%E5%85%83) + - [6.3.7 中国剩余定理](#637-%E4%B8%AD%E5%9B%BD%E5%89%A9%E4%BD%99%E5%AE%9A%E7%90%86) + - [6.3.8 最小公倍数](#638-%E6%9C%80%E5%B0%8F%E5%85%AC%E5%80%8D%E6%95%B0) + - [6.3.9 分解质因数](#639-%E5%88%86%E8%A7%A3%E8%B4%A8%E5%9B%A0%E6%95%B0) + - [6.3.10 因数个数](#6310-%E5%9B%A0%E6%95%B0%E4%B8%AA%E6%95%B0) + - [6.3.11 素数判定](#6311-%E7%B4%A0%E6%95%B0%E5%88%A4%E5%AE%9A) + - [6.3.11.1 Miller Rabin Primality Test](#63111-miller-rabin-primality-test) + - [6.3.12 进制转换](#6312-%E8%BF%9B%E5%88%B6%E8%BD%AC%E6%8D%A2) + - [6.3.13 A / C](#6313-a--c) + - [6.3.14 质数表](#6314-%E8%B4%A8%E6%95%B0%E8%A1%A8) + - [6.3.15 Fast Exponention](#6315-fast-exponention) + - [6.3.16 Fast Fourier Transform FFT](#6316-fast-fourier-transform-fft) + - [6.4 Game Theory 博弈论](#64-game-theory-%E5%8D%9A%E5%BC%88%E8%AE%BA) + - [6.4.1 Impartial Combinatorial Game](#641-impartial-combinatorial-game) + - [6.4.1.1 Nim Game](#6411-nim-game) + - [6.4.1.1 Composite Games – Sprague-Grundy Theorem and Nim Value](#6411-composite-games-%E2%80%93-sprague-grundy-theorem-and-nim-value) +- [7. Geometry](#7-geometry) + - [7.1 2-Dimension Space](#71-2-dimension-space) + - [7.1.1 Template of Point](#711-template-of-point) + - [7.1.2 向量点乘 叉乘](#712-%E5%90%91%E9%87%8F%E7%82%B9%E4%B9%98-%E5%8F%89%E4%B9%98) + - [7.1.3 dot product](#713-dot-product) + - [7.1.4 cross product](#714-cross-product) + - [7.1.5 直线公式](#715-%E7%9B%B4%E7%BA%BF%E5%85%AC%E5%BC%8F) + - [7.1.6 Convex Hull](#716-convex-hull) + - [Gift Wrapping](#gift-wrapping) + - [QuickHull](#quickhull) + - [Graham scan](#graham-scan) +- [8. Tricks + Miscellaneous](#8-tricks--miscellaneous) + - [8.1 Bit Manipulation](#81-bit-manipulation) + - [8.1 Cantor Expansion / Reverse Cantor Expansion](#81-cantor-expansion--reverse-cantor-expansion) + - [8.2 pass 2-D array](#82-pass-2-d-array) + - [8.3 Binary Display](#83-binary-display) + - [8.4 Fast Log](#84-fast-log) + - [8.5 Squre Root](#85-squre-root) + + ## 1. Basic @@ -294,7 +294,7 @@ Output ```c++ char arrstr[] = "this is a string"; -string target = string(arr); +string target = string(arrstr); ``` ### 1.3 STL Algorithm @@ -412,6 +412,8 @@ Usage ```c++ void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp); + //As for Compare comp, it takes 'smaller than' ('<') as the parameter for comparison. For sorting in descending order, we take +void sort(RandomAccessIterator first,RandomAccessIterator last,std::greater()); void stable_sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp ); ``` @@ -584,7 +586,7 @@ template < class Key, // unordered_map::key_t #### 1.4.3 Vector -##### Constructor +##### Constructor ```c++ std::vector second (4,100); // four ints with value 100 @@ -739,7 +741,7 @@ while (three_priority_queue.size() != 0) { ### 2.1 Heap ### 2.2 Tree - + #### 2.2.0 Tree Traversal #### 2.2.1 Pointer Jumping @@ -1064,7 +1066,7 @@ struct Graph { } } - void heavy_light_decomposition() { + void heavy_light_decomposition() { int root = 1; parent[root] = -1; assert(n == size_parent(root)); @@ -1212,8 +1214,8 @@ int main() { > > preprocess: euler tour O(n) + RMQ init O(nlog(n)) > -> query: RMQ O(1) -> +> query: RMQ O(1) +> > [tutorial](https://www.topcoder.com/community/data-science/data-science-tutorials/range-minimum-query-and-lowest-common-ancestor/) ```c++ @@ -1254,156 +1256,156 @@ int main() { // 1 // 2 -#include -#include -#include -#include - -using namespace std; - -struct Graph { - struct Edge { - int to; - int len; - }; - - const static int MAXNODE = 1 * 1e5 + 2; - - vector g[MAXNODE]; - vector edge; - int n; - - int root = 0; - - void init(int nn, int m=0) { - n = nn; - for (int i = 0; i <= n; i++) - g[i].clear(); - edge.clear(); - m *= 2; - edge.reserve(m); // may speedup // add_e too slow - } - - void add_e(int x, int y, int len) { - g[x].push_back(edge.size()); - edge.push_back((Edge){y, len}); - - g[y].push_back(edge.size()); - edge.push_back((Edge){x, len}); - } - - void show() { - for (int i = 0; i <= n; i++) { - printf("%d:", i); - for (int ie : g[i]) - printf(" %d", edge[ie].to); - printf("\n"); - } - printf("\n"); - } - - // - // --- start of LCA --- - // - vector dis_to_root; - vector first_visit_time; // max possible number of visits to all nodes == 2 * number of nodes - 1 - vector visit; - int visit_counter; - vector> rmq; - - int range_minimum_query(int l, int r) { // query [l, r] - if (l > r) - swap(l, r); - - int interval_len = r - l; // (r - l + 1) - 1 - - int first_half = 1; - while ((1 << first_half) <= interval_len) - first_half++; - first_half--; - - int second_half = r - (1 << first_half) + 1; - if (first_visit_time[rmq[l][first_half]] < first_visit_time[rmq[second_half][first_half]]) - return rmq[l][first_half]; - return rmq[second_half][first_half]; - } - - int get_lca(int x, int y) { - return range_minimum_query(first_visit_time[x], first_visit_time[y]); - } - - int dist(int x, int y) { - int lca = get_lca(x, y); - return dis_to_root[x] + dis_to_root[y] - 2 * dis_to_root[lca]; - } - - void euler_tour(int cur) { - visit[++visit_counter] = cur; // v_t[node] = time // needed in case don't have two child - if (first_visit_time[cur] == 0) // if first time - first_visit_time[cur] = visit_counter; // record time f_v_t[node] = time - for (int ie : g[cur]) { - const Edge& e = edge[ie]; - int nx = e.to; - int len = e.len; - if (first_visit_time[nx] == 0) { - dis_to_root[nx] = dis_to_root[cur] + len; - euler_tour(nx); - visit[++visit_counter] = cur; // every two child_visit_time have one parent_visit_time inserted between - } - } - } - - void build_lca() { // O(Nlog(N)) - int one_n = n + 1; - int two_n = 2 * one_n; - vector(one_n, 0).swap(dis_to_root); - vector(one_n, 0).swap(first_visit_time); - vector(two_n, 0).swap(visit); - - int LOG_MAXLENGTH = log2(two_n) + 2; - vector>(two_n, vector(LOG_MAXLENGTH)).swap(rmq); - - visit_counter = 0; - euler_tour(root); - - for (int i = 0; i < visit_counter; i++) - rmq[i][0] = visit[i]; - - for (int j = 1; j < LOG_MAXLENGTH; j++) - for (int i = 0; i < visit_counter; i++) { - if (i + (1 << j) > visit_counter) - break; - rmq[i][j] = rmq[i][j - 1]; - if (first_visit_time[rmq[i][j - 1]] > first_visit_time[rmq[i + (1 << (j - 1))][j - 1]]) - rmq[i][j] = rmq[i + (1 << (j - 1))][j-1]; - } - } - // - // --- end of LCA --- - // -}; - -int n, m; -Graph g; - -int main(int argc, char const *argv[]) { - scanf("%d", &n); - g.init(n, n); - for (int i = 1; i < n; i++) { - int x, y, d; - scanf("%d %d %d", &x, &y, &d); - g.add_e(x, y, d); - } - - g.build_lca(); - - scanf("%d", &m); - for (int i = 0; i < m; i++) { - int x, y; - scanf("%d %d", &x, &y); - printf("%d\n", g.dist(x, y)); - } -} +#include +#include +#include +#include + +using namespace std; + +struct Graph { + struct Edge { + int to; + int len; + }; + + const static int MAXNODE = 1 * 1e5 + 2; + + vector g[MAXNODE]; + vector edge; + int n; + + int root = 0; + + void init(int nn, int m=0) { + n = nn; + for (int i = 0; i <= n; i++) + g[i].clear(); + edge.clear(); + m *= 2; + edge.reserve(m); // may speedup // add_e too slow + } + + void add_e(int x, int y, int len) { + g[x].push_back(edge.size()); + edge.push_back((Edge){y, len}); + + g[y].push_back(edge.size()); + edge.push_back((Edge){x, len}); + } + + void show() { + for (int i = 0; i <= n; i++) { + printf("%d:", i); + for (int ie : g[i]) + printf(" %d", edge[ie].to); + printf("\n"); + } + printf("\n"); + } + + // + // --- start of LCA --- + // + vector dis_to_root; + vector first_visit_time; // max possible number of visits to all nodes == 2 * number of nodes - 1 + vector visit; + int visit_counter; + vector> rmq; + + int range_minimum_query(int l, int r) { // query [l, r] + if (l > r) + swap(l, r); + + int interval_len = r - l; // (r - l + 1) - 1 + + int first_half = 1; + while ((1 << first_half) <= interval_len) + first_half++; + first_half--; + + int second_half = r - (1 << first_half) + 1; + if (first_visit_time[rmq[l][first_half]] < first_visit_time[rmq[second_half][first_half]]) + return rmq[l][first_half]; + return rmq[second_half][first_half]; + } + + int get_lca(int x, int y) { + return range_minimum_query(first_visit_time[x], first_visit_time[y]); + } + + int dist(int x, int y) { + int lca = get_lca(x, y); + return dis_to_root[x] + dis_to_root[y] - 2 * dis_to_root[lca]; + } + + void euler_tour(int cur) { + visit[++visit_counter] = cur; // v_t[node] = time // needed in case don't have two child + if (first_visit_time[cur] == 0) // if first time + first_visit_time[cur] = visit_counter; // record time f_v_t[node] = time + for (int ie : g[cur]) { + const Edge& e = edge[ie]; + int nx = e.to; + int len = e.len; + if (first_visit_time[nx] == 0) { + dis_to_root[nx] = dis_to_root[cur] + len; + euler_tour(nx); + visit[++visit_counter] = cur; // every two child_visit_time have one parent_visit_time inserted between + } + } + } + + void build_lca() { // O(Nlog(N)) + int one_n = n + 1; + int two_n = 2 * one_n; + vector(one_n, 0).swap(dis_to_root); + vector(one_n, 0).swap(first_visit_time); + vector(two_n, 0).swap(visit); + + int LOG_MAXLENGTH = log2(two_n) + 2; + vector>(two_n, vector(LOG_MAXLENGTH)).swap(rmq); + + visit_counter = 0; + euler_tour(root); + + for (int i = 0; i < visit_counter; i++) + rmq[i][0] = visit[i]; + + for (int j = 1; j < LOG_MAXLENGTH; j++) + for (int i = 0; i < visit_counter; i++) { + if (i + (1 << j) > visit_counter) + break; + rmq[i][j] = rmq[i][j - 1]; + if (first_visit_time[rmq[i][j - 1]] > first_visit_time[rmq[i + (1 << (j - 1))][j - 1]]) + rmq[i][j] = rmq[i + (1 << (j - 1))][j-1]; + } + } + // + // --- end of LCA --- + // +}; + +int n, m; +Graph g; + +int main(int argc, char const *argv[]) { + scanf("%d", &n); + g.init(n, n); + for (int i = 1; i < n; i++) { + int x, y, d; + scanf("%d %d %d", &x, &y, &d); + g.add_e(x, y, d); + } + + g.build_lca(); + + scanf("%d", &m); + for (int i = 0; i < m; i++) { + int x, y; + scanf("%d %d", &x, &y); + printf("%d\n", g.dist(x, y)); + } +} ``` Another implementation, only used by ZXZ. @@ -1673,135 +1675,135 @@ int main(int argc, char const *argv[]) { // For each second type query print the reply in a single line. // -struct Graph { - struct Edge { - int to; - }; - - const static int MAXNODE = 1 * 1e5 + 2; - - vector g[MAXNODE]; - vector edge; - int n; - - int root = 1; - - void init(int nn, int m=0) { - n = nn; - for (int i = 0; i <= n; i++) - g[i].clear(); - edge.clear(); - m *= 2; - edge.reserve(m); // may speedup // add_e too slow - } - - void add_e(int x, int y) { - g[x].push_back(edge.size()); - edge.push_back((Edge){y}); - - g[y].push_back(edge.size()); - edge.push_back((Edge){x}); - } - - void show() { - for (int i = 0; i <= n; i++) { - printf("%d:", i); - for (int ie : g[i]) - printf(" %d", edge[ie].to); - printf("\n"); - } - printf("\n"); - } - - // - // --- start of centroid decomposition --- - // - vector centroid; // index of upper level centroid node - - vector subtree_size; - vector parent; - - vector deleted; - int compute_subtree(int cur) { - int& size = subtree_size[cur]; - for (int ie : g[cur]) { - const Edge& e = edge[ie]; - int nx = e.to; - if (parent[nx] == -1) { - parent[nx] = cur; - size += compute_subtree(nx); - } - } - return size; - } - - void centroid_decomposite(int cur, int from, int tree_size) { // O(Nlog(N)) - int half_size = tree_size / 2; - - while (subtree_size[cur] <= half_size) // go up until centroid is in subtree - cur = parent[cur]; - - while (1) { - int candidate = cur; - for (int ie : g[cur]) { // go down if centroid is in subtree - const Edge& e = edge[ie]; - int nx = e.to; - if (!deleted[nx] && nx != parent[cur]) { - if (subtree_size[nx] > half_size) { - SHOW(cur, nx, subtree_size[nx], candidate) - candidate = nx; - } - } - } - if (candidate == cur) - break; - cur = candidate; - } - - deleted[cur] = true; - centroid[cur] = from; - - int temp = parent[cur]; - int cur_size = subtree_size[cur]; - while (!deleted[temp] && temp != parent[temp]) { // update all the subtree_size of parent - subtree_size[temp] -= cur_size; - temp = parent[temp]; - } - - for (int ie : g[cur]) { // decomposite parent and children - const Edge& e = edge[ie]; - int nx = e.to; - if (!deleted[nx]) { - int nx_tree_size; // size of next level centroid tree - if (nx == parent[cur]) - nx_tree_size = tree_size - cur_size; - else - nx_tree_size = subtree_size[nx]; - - if (nx_tree_size == 1) - centroid[nx] = cur; // don't need to go into it - else - centroid_decomposite(nx, cur, nx_tree_size); - } - } - } - - void centroid_decomposite() { - vector(n + 1, -1).swap(centroid); - vector(n + 1, 1).swap(subtree_size); // initialized each to be 1 (itself) - vector(n + 1, -1).swap(parent); - vector(n + 1, false).swap(deleted); - - parent[root] = root; - compute_subtree(root); - - centroid_decomposite(root, -1, n); - } - // - // --- end of centroid decomposition --- - // +struct Graph { + struct Edge { + int to; + }; + + const static int MAXNODE = 1 * 1e5 + 2; + + vector g[MAXNODE]; + vector edge; + int n; + + int root = 1; + + void init(int nn, int m=0) { + n = nn; + for (int i = 0; i <= n; i++) + g[i].clear(); + edge.clear(); + m *= 2; + edge.reserve(m); // may speedup // add_e too slow + } + + void add_e(int x, int y) { + g[x].push_back(edge.size()); + edge.push_back((Edge){y}); + + g[y].push_back(edge.size()); + edge.push_back((Edge){x}); + } + + void show() { + for (int i = 0; i <= n; i++) { + printf("%d:", i); + for (int ie : g[i]) + printf(" %d", edge[ie].to); + printf("\n"); + } + printf("\n"); + } + + // + // --- start of centroid decomposition --- + // + vector centroid; // index of upper level centroid node + + vector subtree_size; + vector parent; + + vector deleted; + int compute_subtree(int cur) { + int& size = subtree_size[cur]; + for (int ie : g[cur]) { + const Edge& e = edge[ie]; + int nx = e.to; + if (parent[nx] == -1) { + parent[nx] = cur; + size += compute_subtree(nx); + } + } + return size; + } + + void centroid_decomposite(int cur, int from, int tree_size) { // O(Nlog(N)) + int half_size = tree_size / 2; + + while (subtree_size[cur] <= half_size) // go up until centroid is in subtree + cur = parent[cur]; + + while (1) { + int candidate = cur; + for (int ie : g[cur]) { // go down if centroid is in subtree + const Edge& e = edge[ie]; + int nx = e.to; + if (!deleted[nx] && nx != parent[cur]) { + if (subtree_size[nx] > half_size) { + SHOW(cur, nx, subtree_size[nx], candidate) + candidate = nx; + } + } + } + if (candidate == cur) + break; + cur = candidate; + } + + deleted[cur] = true; + centroid[cur] = from; + + int temp = parent[cur]; + int cur_size = subtree_size[cur]; + while (!deleted[temp] && temp != parent[temp]) { // update all the subtree_size of parent + subtree_size[temp] -= cur_size; + temp = parent[temp]; + } + + for (int ie : g[cur]) { // decomposite parent and children + const Edge& e = edge[ie]; + int nx = e.to; + if (!deleted[nx]) { + int nx_tree_size; // size of next level centroid tree + if (nx == parent[cur]) + nx_tree_size = tree_size - cur_size; + else + nx_tree_size = subtree_size[nx]; + + if (nx_tree_size == 1) + centroid[nx] = cur; // don't need to go into it + else + centroid_decomposite(nx, cur, nx_tree_size); + } + } + } + + void centroid_decomposite() { + vector(n + 1, -1).swap(centroid); + vector(n + 1, 1).swap(subtree_size); // initialized each to be 1 (itself) + vector(n + 1, -1).swap(parent); + vector(n + 1, false).swap(deleted); + + parent[root] = root; + compute_subtree(root); + + centroid_decomposite(root, -1, n); + } + // + // --- end of centroid decomposition --- + // }; -``` +``` Key functions @@ -2226,7 +2228,8 @@ int suffix_array[HH]; int suffix_array_temp[HH]; int counter[HH]; -void counting_sort(int k) { +void counting_ +(int k) { memset(counter, 0, sizeof(counter)); int len = s.length(); @@ -2573,131 +2576,131 @@ struct SegmentTree { struct Op { // store lazy operation int h; }; - struct Node { - int l; // [l, ] - int r; // [, r] - - int h; // value - - bool lazy; - Op op; + struct Node { + int l; // [l, ] + int r; // [, r] + + int h; // value + + bool lazy; + Op op; }; vector node; - void init(int l, int r) { // [l, r] - int tree_range = r - l + 1; - if (tree_range <= 0) - return ; - - int tree_size = 1; - while (tree_size <= tree_range) - tree_size <<= 1; - if (__builtin_popcount(tree_range) != 1) // count number of '1' bits - tree_size <<= 1; - - node.resize(tree_size); // (tree_range, tree_size): (001001, 100000) (001000, 010000) - - Node& root = node[1]; - root.l = l, root.r = r; - root.h = root.op.h = 0; - for (int i = 2; i < node.size(); i++) { - Node& cur = node[i]; - cur.h = 0; - - const Node& par = node[i / 2]; // parent node - if (par.l == par.r) // if parent is end node, skip - cur.l = cur.r = -1; - else { - int m = (par.l + par.r) / 2; - if (i % 2) - cur.l = m + 1, cur.r = par.r; - else - cur.l = par.l, cur.r = m; - } - } - } + void init(int l, int r) { // [l, r] + int tree_range = r - l + 1; + if (tree_range <= 0) + return ; + + int tree_size = 1; + while (tree_size <= tree_range) + tree_size <<= 1; + if (__builtin_popcount(tree_range) != 1) // count number of '1' bits + tree_size <<= 1; + + node.resize(tree_size); // (tree_range, tree_size): (001001, 100000) (001000, 010000) + + Node& root = node[1]; + root.l = l, root.r = r; + root.h = root.op.h = 0; + for (int i = 2; i < node.size(); i++) { + Node& cur = node[i]; + cur.h = 0; + + const Node& par = node[i / 2]; // parent node + if (par.l == par.r) // if parent is end node, skip + cur.l = cur.r = -1; + else { + int m = (par.l + par.r) / 2; + if (i % 2) + cur.l = m + 1, cur.r = par.r; + else + cur.l = par.l, cur.r = m; + } + } + } - void show() { - SHOW("SegmentTree NAME") - for (int i = 1; i < node.size(); i++) { - Node& cur = node[i]; - if (cur.l == -1 && cur.r == -1) - continue; - PRINTLN("(%2d) [%2d,%2d] val: %d", i, cur.l, cur.r, cur.internal) - } - } + void show() { + SHOW("SegmentTree NAME") + for (int i = 1; i < node.size(); i++) { + Node& cur = node[i]; + if (cur.l == -1 && cur.r == -1) + continue; + PRINTLN("(%2d) [%2d,%2d] val: %d", i, cur.l, cur.r, cur.internal) + } + } - int query(int xl, int xr, int i = 1) { // query [xl, xr] - Node& cur = node[i]; - if (cur.l == cur.r) // if end node - return cur.h; - - if (xl <= cur.l && cur.r <= xr) // if query cover the node - return cur.h; - - int lci = i * 2; - const Node& lc = node[lci]; - int rci = lci + 1; - const Node& rc = node[rci]; - if (cur.lazy) { // if have lazy operation, push down - update(lc.l, lc.r, cur.op.h, lci); - update(rc.l, rc.r, cur.op.h, rci); - cur.lazy = false; - } - - int ret = INT_MAX; - if (xl <= lc.r) { // if query cover left child - int temp = query(xl, xr, lci); - if (ret > temp) - ret = temp; - } - if (rc.l <= xr) { // if query cover right child - int temp = query(xl, xr, rci); - if (ret > temp) - ret = temp; - } - return ret; - } - - void update(int xl, int xr, int xh, int i = 1) { // update [xl, xr] value xh - Node& cur = node[i]; - if (cur.l == cur.r) { // if end node - if (cur.h < xh) - cur.h = xh; - return ; - } - - if (xl <= cur.l && cur.r <= xr) { // if query cover the node - if (cur.h < xh) { // update node value - cur.h = xh; - } - if (cur.lazy) { // update the lazy operation // slow if push down now - if (cur.op.h < xh) - cur.op.h = xh; - } - else { // store lazy operation - cur.op.h = xh; - cur.lazy = true; - } - return ; - } - - int lci = i * 2; - const Node& lc = node[lci]; - int rci = lci + 1; - const Node& rc = node[rci]; - if (cur.lazy) { // if have lazy operation, push down - update(lc.l, lc.r, cur.op.h, lci); - update(rc.l, rc.r, cur.op.h, rci); - cur.lazy = false; - } - - if (xl <= lc.r) // if update cover left node - update(xl, xr, xh, lci); - if (rc.l <= xr) // if update cover right node - update(xl, xr, xh, rci); - - cur.h = min(lc.h, rc.h); // reduce two children + int query(int xl, int xr, int i = 1) { // query [xl, xr] + Node& cur = node[i]; + if (cur.l == cur.r) // if end node + return cur.h; + + if (xl <= cur.l && cur.r <= xr) // if query cover the node + return cur.h; + + int lci = i * 2; + const Node& lc = node[lci]; + int rci = lci + 1; + const Node& rc = node[rci]; + if (cur.lazy) { // if have lazy operation, push down + update(lc.l, lc.r, cur.op.h, lci); + update(rc.l, rc.r, cur.op.h, rci); + cur.lazy = false; + } + + int ret = INT_MAX; + if (xl <= lc.r) { // if query cover left child + int temp = query(xl, xr, lci); + if (ret > temp) + ret = temp; + } + if (rc.l <= xr) { // if query cover right child + int temp = query(xl, xr, rci); + if (ret > temp) + ret = temp; + } + return ret; + } + + void update(int xl, int xr, int xh, int i = 1) { // update [xl, xr] value xh + Node& cur = node[i]; + if (cur.l == cur.r) { // if end node + if (cur.h < xh) + cur.h = xh; + return ; + } + + if (xl <= cur.l && cur.r <= xr) { // if query cover the node + if (cur.h < xh) { // update node value + cur.h = xh; + } + if (cur.lazy) { // update the lazy operation // slow if push down now + if (cur.op.h < xh) + cur.op.h = xh; + } + else { // store lazy operation + cur.op.h = xh; + cur.lazy = true; + } + return ; + } + + int lci = i * 2; + const Node& lc = node[lci]; + int rci = lci + 1; + const Node& rc = node[rci]; + if (cur.lazy) { // if have lazy operation, push down + update(lc.l, lc.r, cur.op.h, lci); + update(rc.l, rc.r, cur.op.h, rci); + cur.lazy = false; + } + + if (xl <= lc.r) // if update cover left node + update(xl, xr, xh, lci); + if (rc.l <= xr) // if update cover right node + update(xl, xr, xh, rci); + + cur.h = min(lc.h, rc.h); // reduce two children } }; @@ -3003,119 +3006,119 @@ void query(int left, int right, long long &sum, int u) { ### 2.8 Range Minimum Query RMQ -```c++ -struct RMQ { // not tested - const static int MAXLENGTH = 2 * 1e5 + 3; - const static int LOG_MAXLENGTH = 20; - int rmq[MAXLENGTH][LOG_MAXLENGTH]; - - void init(int* arr, int len) { - for (int i = 0; i < len; i++) - rmq[i][0] = arr[i]; - for (int j = 1; j < LOG_MAXLENGTH; j++) - for (int i = 0; i < len; i++) { - if (i + (1 << j) > len) - break; - rmq[i][j] = rmq[i][j - 1]; - rmq[i][j] = min(rmq[i][j - 1], rmq[i + (1 << (j - 1))][j-1]); - } - } - - int range_minimum_query(int l, int r) { - if (l > r) - swap(l, r); - - int interval_len = r - l; // less 1 - - int first_half = 1; - while ((1 << first_half) <= interval_len) - first_half++; - first_half--; - - int second_half = r - (1 << first_half) + 1; - return min(rmq[l][first_half], rmq[second_half][first_half]); - } -}; -``` - -### 2.9 Union-find Set +```c++ +struct RMQ { // not tested + const static int MAXLENGTH = 2 * 1e5 + 3; + const static int LOG_MAXLENGTH = 20; + int rmq[MAXLENGTH][LOG_MAXLENGTH]; + + void init(int* arr, int len) { + for (int i = 0; i < len; i++) + rmq[i][0] = arr[i]; + for (int j = 1; j < LOG_MAXLENGTH; j++) + for (int i = 0; i < len; i++) { + if (i + (1 << j) > len) + break; + rmq[i][j] = rmq[i][j - 1]; + rmq[i][j] = min(rmq[i][j - 1], rmq[i + (1 << (j - 1))][j-1]); + } + } + + int range_minimum_query(int l, int r) { + if (l > r) + swap(l, r); + + int interval_len = r - l; // less 1 + + int first_half = 1; + while ((1 << first_half) <= interval_len) + first_half++; + first_half--; + + int second_half = r - (1 << first_half) + 1; + return min(rmq[l][first_half], rmq[second_half][first_half]); + } +}; +``` + +### 2.9 Union-find Set ```C++ -struct UnionFindSet { - vector parent; - void init(int nn) { - parent.resize(nn + 1); - for (int i = 0; i < parent.size(); i++) - parent[i] = i; - } - - void merge(int x, int y) { - parent[find(x)] = find(y); - } - int find(int x) { - return x == parent[x] ? x : parent[x] = find(parent[x]); - } - bool together(int x, int y) { - return find(x) == find(y); - } +struct UnionFindSet { + vector parent; + void init(int nn) { + parent.resize(nn + 1); + for (int i = 0; i < parent.size(); i++) + parent[i] = i; + } + + void merge(int x, int y) { + parent[find(x)] = find(y); + } + int find(int x) { + return x == parent[x] ? x : parent[x] = find(parent[x]); + } + bool together(int x, int y) { + return find(x) == find(y); + } }; -``` +``` #### 2.9.1 Union-find Set - application -> place holder - -### 2.10 Bloom Filter (?) (Similar) - -> Can calculate hash of number sequence quickly. -> -> If too slow, set REPEAT smaller. Or try again:) - -```c++ -#include - -struct BloomFilterSimilar { - static const int MAXN = 100002; - static const int REPEAT = 10; - - unsigned long long hash_constant[REPEAT][MAXN]; - set hash[REPEAT]; - - void init_hash(int max_n=MAXN) { - random_device rd; - mt19937 gen(rd()); - uniform_int_distribution dis(1, ULLONG_MAX); - for (int i = 0; i < REPEAT; i++) { - for (int j = 0; j < max_n; j++) - hash_constant[i][j] = dis(gen); - } - } - - vector get_hash(int val) { - vector h(REPEAT); - for (int i = 0; i < REPEAT; i++) - h[i] = hash_constant[i][val]; - return move(h); - } - - // bool exist(int val) { - // return exist(get_hash(val)); - // } - bool exist(const vector& h) { - for (int i = 0; i < REPEAT; i++) - if (hash[i].find(h[i]) == end(hash[i])) - return false; - return true; // possible False Positive - } - - // void insert(int val) { - // insert(get_hash(val)); - // } - void insert(const vector& h) { - for (int i = 0; i < REPEAT; i++) - hash[i].insert(h[i]); - } -}; +> place holder + +### 2.10 Bloom Filter (?) (Similar) + +> Can calculate hash of number sequence quickly. +> +> If too slow, set REPEAT smaller. Or try again:) + +```c++ +#include + +struct BloomFilterSimilar { + static const int MAXN = 100002; + static const int REPEAT = 10; + + unsigned long long hash_constant[REPEAT][MAXN]; + set hash[REPEAT]; + + void init_hash(int max_n=MAXN) { + random_device rd; + mt19937 gen(rd()); + uniform_int_distribution dis(1, ULLONG_MAX); + for (int i = 0; i < REPEAT; i++) { + for (int j = 0; j < max_n; j++) + hash_constant[i][j] = dis(gen); + } + } + + vector get_hash(int val) { + vector h(REPEAT); + for (int i = 0; i < REPEAT; i++) + h[i] = hash_constant[i][val]; + return move(h); + } + + // bool exist(int val) { + // return exist(get_hash(val)); + // } + bool exist(const vector& h) { + for (int i = 0; i < REPEAT; i++) + if (hash[i].find(h[i]) == end(hash[i])) + return false; + return true; // possible False Positive + } + + // void insert(int val) { + // insert(get_hash(val)); + // } + void insert(const vector& h) { + for (int i = 0; i < REPEAT; i++) + hash[i].insert(h[i]); + } +}; ``` ## 3. Methodology @@ -3264,242 +3267,242 @@ int main () { } ``` -## 5. Graph - -### 5.1 Graph Structure - -```c++ -struct Graph { - struct Edge { - int from; - int to; - int len; - }; - - const static int MAXNODE = 3 * 1e5 + 2; - vector g[MAXNODE]; - vector edge; - int n; - void init(int nn) { - n = nn; - for (int i = 0; i <= n; i++) - g[i].clear(); - edge.clear(); - } - - void add_e(int x, int y, int len) { - g[x].push_back(edge.size()); - edge.push_back((Edge){x, y, len}); - g[y].push_back(edge.size()); - edge.push_back((Edge){y, x, len}); - } - - void show() { - for (int i = 0; i <= n; i++) { - printf("%d:", i); - for (int ie : g[i]) - printf(" %d", edge[ie].to); - printf("\n"); - } - printf("\n"); - } -}; -``` - -```c++ -struct Network { - struct Edge { - int to; - int pre_edge; - int cap; - int flow; - }; - - vector last; - - int nv; // total number of vertex, index range: [0, nv) - vector edge; - void init(int _nv) { - nv = _nv; - vector().swap(edge); - vector(nv + 1, -1).swap(last); - } - - void add_e(int x, int y, int cap, int r_cap = 0) { - Edge e{y, last[x], cap, 0}; - last[x] = edge.size(); - edge.push_back(move(e)); - - Edge r_e{x, last[y], r_cap, 0}; - last[y] = edge.size(); - edge.push_back(move(r_e)); - } - void show_edge() { - for (int i = 0; i < nv; i++) { - printf("%d:", i); - for (int ie = last[i]; ie != -1; ) { - const Edge& e = edge[ie]; - ie = e.pre_edge; - printf(" (%d)%d/%d", e.to, e.flow, e.cap); - } - printf("\n"); - } - printf("\n"); - } -} -``` +## 5. Graph -### 5.2 Minimium Spanning Tree +### 5.1 Graph Structure -#### 5.2.1 Prim's +```c++ +struct Graph { + struct Edge { + int from; + int to; + int len; + }; -> O((V + E)log(V)) + const static int MAXNODE = 3 * 1e5 + 2; + vector g[MAXNODE]; + vector edge; + int n; + void init(int nn) { + n = nn; + for (int i = 0; i <= n; i++) + g[i].clear(); + edge.clear(); + } + + void add_e(int x, int y, int len) { + g[x].push_back(edge.size()); + edge.push_back((Edge){x, y, len}); + g[y].push_back(edge.size()); + edge.push_back((Edge){y, x, len}); + } -```C++ -struct Graph { - struct Edge { - int from; - int to; - int len; - }; - - const static int MAXNODE = 3 * 1e5 + 2; - vector g[MAXNODE]; - vector edge; - int n; - void init(int nn) { - n = nn; - for (int i = 0; i <= n; i++) - g[i].clear(); - edge.clear(); - } - - void add_e(int x, int y, int len) { - g[x].push_back(edge.size()); - edge.push_back((Edge){x, y, len}); - g[y].push_back(edge.size()); - edge.push_back((Edge){y, x, len}); - } - - void show() { - for (int i = 0; i <= n; i++) { - printf("%d:", i); - for (int ie : g[i]) - printf(" %d", edge[ie].to); - printf("\n"); - } - printf("\n"); - } - - // - // ---- start of Minimum Spanning Tree --- - // - vector added; - vector mindis; // little optimization - void mst() { - vector(n + 1, false).swap(added); - vector(n + 1, INT_MAX).swap(mindis); - - auto cmp = [](const Edge& a, const Edge& b) { - return a.len > b.len; - }; - priority_queue, decltype(cmp)> near(cmp); - for (int i = 0; i < g[1].size(); i++) { - const Edge& e = edge[g[1][i]]; - near.push(e); - mindis[e.to] = e.len; // little optimization - } - added[1] = true; - - while (near.size()) { - Edge cur = near.top(); near.pop(); - added[cur.to] = true; - // add Edge cur - for (int ie : g[cur.to]) { - const Edge& nxe = edge[ie]; - int nx = nxe.to; - if (!added[nx] - && mindis[nx] > nxe.len) { // little optimization - mindis[nx] = nxe.len; // little optimization - near.push(nxe); - } - } - while (near.size() && added[near.top().to]) - near.pop(); - } - // - } - // - // ---- end of Minimum Spanning Tree --- - // + void show() { + for (int i = 0; i <= n; i++) { + printf("%d:", i); + for (int ie : g[i]) + printf(" %d", edge[ie].to); + printf("\n"); + } + printf("\n"); + } }; ``` -#### 5.2.2 Kruskal +```c++ +struct Network { + struct Edge { + int to; + int pre_edge; + int cap; + int flow; + }; -> Elog(E) + Elog(V) + vector last; -```C++ -struct Graph { - struct Edge { - int from; - int to; - int len; - }; - - const static int MAXNODE = 3 * 1e5 + 2; - vector g[MAXNODE]; - vector edge; - int n; - void init(int nn) { - n = nn; - for (int i = 0; i <= n; i++) - g[i].clear(); - edge.clear(); - } - - void add_e(int x, int y, int len) { - g[x].push_back(edge.size()); - edge.push_back((Edge){x, y, len}); - g[y].push_back(edge.size()); - edge.push_back((Edge){y, x, len}); - } - - void show() { - for (int i = 0; i <= n; i++) { - printf("%d:", i); - for (int ie : g[i]) - printf(" %d", edge[ie].to); - printf("\n"); - } - printf("\n"); - } - - // - // ---- start of Minimum Spanning Tree --- - // - UnionFindSet ufs; - void mst() { - ufs.init(n); - vector eee = edge; - sort(begin(eee), end(eee), [](const Edge& a, const Edge& b) { - return a.len < b.len; - }); - - int need = n - 1; - for (const auto& e : eee) { - if (!ufs.together(e.from, e.to)) { - // add Edge e - ufs.merge(e.from, e.to); - need--; - if (!need) - break; - } - } - } - // - // ---- end of Minimum Spanning Tree --- - // + int nv; // total number of vertex, index range: [0, nv) + vector edge; + void init(int _nv) { + nv = _nv; + vector().swap(edge); + vector(nv + 1, -1).swap(last); + } + + void add_e(int x, int y, int cap, int r_cap = 0) { + Edge e{y, last[x], cap, 0}; + last[x] = edge.size(); + edge.push_back(move(e)); + + Edge r_e{x, last[y], r_cap, 0}; + last[y] = edge.size(); + edge.push_back(move(r_e)); + } + void show_edge() { + for (int i = 0; i < nv; i++) { + printf("%d:", i); + for (int ie = last[i]; ie != -1; ) { + const Edge& e = edge[ie]; + ie = e.pre_edge; + printf(" (%d)%d/%d", e.to, e.flow, e.cap); + } + printf("\n"); + } + printf("\n"); + } +} +``` + +### 5.2 Minimium Spanning Tree + +#### 5.2.1 Prim's + +> O((V + E)log(V)) + +```C++ +struct Graph { + struct Edge { + int from; + int to; + int len; + }; + + const static int MAXNODE = 3 * 1e5 + 2; + vector g[MAXNODE]; + vector edge; + int n; + void init(int nn) { + n = nn; + for (int i = 0; i <= n; i++) + g[i].clear(); + edge.clear(); + } + + void add_e(int x, int y, int len) { + g[x].push_back(edge.size()); + edge.push_back((Edge){x, y, len}); + g[y].push_back(edge.size()); + edge.push_back((Edge){y, x, len}); + } + + void show() { + for (int i = 0; i <= n; i++) { + printf("%d:", i); + for (int ie : g[i]) + printf(" %d", edge[ie].to); + printf("\n"); + } + printf("\n"); + } + + // + // ---- start of Minimum Spanning Tree --- + // + vector added; + vector mindis; // little optimization + void mst() { + vector(n + 1, false).swap(added); + vector(n + 1, INT_MAX).swap(mindis); + + auto cmp = [](const Edge& a, const Edge& b) { + return a.len > b.len; + }; + priority_queue, decltype(cmp)> near(cmp); + for (int i = 0; i < g[1].size(); i++) { + const Edge& e = edge[g[1][i]]; + near.push(e); + mindis[e.to] = e.len; // little optimization + } + added[1] = true; + + while (near.size()) { + Edge cur = near.top(); near.pop(); + added[cur.to] = true; + // add Edge cur + for (int ie : g[cur.to]) { + const Edge& nxe = edge[ie]; + int nx = nxe.to; + if (!added[nx] + && mindis[nx] > nxe.len) { // little optimization + mindis[nx] = nxe.len; // little optimization + near.push(nxe); + } + } + while (near.size() && added[near.top().to]) + near.pop(); + } + // + } + // + // ---- end of Minimum Spanning Tree --- + // +}; +``` + +#### 5.2.2 Kruskal + +> Elog(E) + Elog(V) + +```C++ +struct Graph { + struct Edge { + int from; + int to; + int len; + }; + + const static int MAXNODE = 3 * 1e5 + 2; + vector g[MAXNODE]; + vector edge; + int n; + void init(int nn) { + n = nn; + for (int i = 0; i <= n; i++) + g[i].clear(); + edge.clear(); + } + + void add_e(int x, int y, int len) { + g[x].push_back(edge.size()); + edge.push_back((Edge){x, y, len}); + g[y].push_back(edge.size()); + edge.push_back((Edge){y, x, len}); + } + + void show() { + for (int i = 0; i <= n; i++) { + printf("%d:", i); + for (int ie : g[i]) + printf(" %d", edge[ie].to); + printf("\n"); + } + printf("\n"); + } + + // + // ---- start of Minimum Spanning Tree --- + // + UnionFindSet ufs; + void mst() { + ufs.init(n); + vector eee = edge; + sort(begin(eee), end(eee), [](const Edge& a, const Edge& b) { + return a.len < b.len; + }); + + int need = n - 1; + for (const auto& e : eee) { + if (!ufs.together(e.from, e.to)) { + // add Edge e + ufs.merge(e.from, e.to); + need--; + if (!need) + break; + } + } + } + // + // ---- end of Minimum Spanning Tree --- + // }; ``` @@ -3590,316 +3593,316 @@ void dijkstra(int s) { } ``` -### 5.4 Maximum Matching - -#### 5.4.1 on Bipartite Graph 二分图 - -> 1. A graph is bipartite if and only if it does not contain an odd cycle. -> 2. A graph is bipartite if and only if it is 2-colorable, (i.e. its chromatic number is less than or equal to 2). -> 3. The spectrum of a graph is symmetric if and only if it's a bipartite graph. - -##### 5.4.1.1 Hungarian algorithm 匈牙利算法 - -> O(E * V) - -```c++ -struct Network { - struct Edge { - int to; - int pre_edge; - int cap; - int flow; - }; - - #define MAXNODE 405 - int last[MAXNODE]; - - int nv; // total number of vertex, index range: [0, nv) - vector edge; - void init(int _nv) { - nv = _nv; - edge.clear(); - fill(last, last + nv, -1); - } - - void add_e(int x, int y, int cap, int r_cap = 0) { - Edge e = {y, last[x], cap, 0}; - // Edge e{y, last[x], cap, 0}; - last[x] = edge.size(); - // edge.push_back(move(e)); - edge.push_back(e); - - Edge r_e = {x, last[y], r_cap, 0}; - // Edge r_e{x, last[y], r_cap, 0}; - last[y] = edge.size(); - // edge.push_back(move(r_e)); - edge.push_back(r_e); - } - void show_edge() { - for (int i = 0; i < nv; i++) { - printf("v [%d]:", i); - for (int ie = last[i]; ie != -1; ) { - const Edge& e = edge[ie]; - ie = e.pre_edge; - printf(" [%d]%d/%d", e.to, e.flow, e.cap); - } - printf("\n"); - } - printf("\n"); - } - - // - // bipartite match - // O(V * E) - int peer[MAXNODE]; - bool went[MAXNODE]; - int bipartite_match() { - fill(peer, peer + nv, -1); - int ans = 0; - for (int i = 0; i < nv; i++) { - if (last[i] == -1 || peer[i] != -1) - continue; - fill(went, went + nv, false); - if (match(i)) - ans++; - } - return ans; - } - bool match(int cur) { - for (int ie = last[cur]; ie != -1; ) { - const Edge& e = edge[ie]; - ie = e.pre_edge; - int to = e.to; - if (went[to]) - continue; - went[to] = true; - if (peer[to] == -1 || match(peer[to])) { - peer[to] = cur; - peer[cur] = to; - return true; - } - } - return false; - } - void show_peer() { - for (int i = 0; i < nv; i++) - printf("%d peer-> %d\n", i, peer[i]); - } - // end of - // bipartite match - // -}; -``` - -##### 5.4.1.2 Hopcroft–Karp Algorithm - -> O(sqrt(V)*E) - -```c++ -#define MAXN 1010 -#define MAXINT 0x7fffffff - -int n, m, top, x, y; -int ans; - -int disx[MAXN], disy[MAXN], matx[MAXN], maty[MAXN];//x,y,分别为二分图的两个点集,mat为每个点在对侧集合的匹配点,如果当前没有匹配点则为-1 - -struct edge { - int to; - edge *next; -}e[MAXN*MAXN], *prev[MAXN]; - -void insert(int u,int v) { - e[++top].to = v; - e[top].next = prev[u]; - prev[u] = &e[top]; -} - -bool bfs() { // 寻找最短增广路 - bool ret = 0; - queue q; - memset(disx, 0, sizeof(disx)); - memset(disy, 0, sizeof(disy)); - for (int i = 1; i <= n; i++) - if (matx[i] == -1) - q.push(i); // 找到未盖点,入队 - while (!q.empty()) { // 在二分图另一个点集的非盖点中寻找增广路 - int x = q.front(); q.pop(); - for (edge *i = prev[x]; i; i = i->next) - if (!disy[i->to]) { - disy[i->to] = disx[x] + 1; - if (maty[i->to]==-1) - ret = 1; // 找到增广路 - else - disx[maty[i->to]] = disy[i->to] + 1, q.push(maty[i->to]); - } - } - return ret; -} - -bool dfs(int x) { // 沿增广路增广 - for (edge *i = prev[x]; i; i = i->next) { - if (disy[i->to] == disx[x] + 1) { - disy[i->to] = 0; - if (maty[i->to] == -1 || dfs(maty[i->to])) { - matx[x] = i->to; - maty[i->to] = x; - return 1; - } - } - } - return 0; -} - -int main() { - scanf("%d%d",&n,&m); - memset(matx, -1, sizeof(matx)); - memset(maty, -1, sizeof(maty)); - /*for (int i=1;i<=n;i++) - { - scanf("%d%d",&x,&y);x++;y++; - insert(i,x);insert(i,y); - }建图请自动忽略*/ - while (bfs()) { - for (int i = 1; i <= m; i++) - if (matx[i] == -1 && dfs(i)) - ans++; - } - cout << ans << endl; -} -``` - -#### 5.4.2 on General Graph - -##### 5.4.2.1 Blossom Algorithm - -[一般图最大匹配](http://www.conlan.cc/2013/03/08/%E4%B8%80%E8%88%AC%E5%9B%BE%E6%9C%80%E5%A4%A7%E5%8C%B9%E9%85%8D/) - -```c++ -const int NMax = 230; - -int Next[NMax]; -int spouse[NMax]; -int belong[NMax]; - -int findb(int a) { - return belong[a] == a ? a : belong[a] = findb(belong[a]); -} - -void together(int a,int b) { - a = findb(a), b = findb(b); - if (a != b) - belong[a] = b; -} - -vector E[NMax]; -int N; -int Q[NMax],bot; -int mark[NMax]; -int visited[NMax]; - -int findLCA(int x,int y) { - static int t = 0; - t++; - while (1) { - if (x!=-1) { - x = findb(x); - if (visited[x] == t) - return x; - visited[x] = t; - if (spouse[x] != -1) - x = Next[spouse[x]]; - else x = -1; - } - swap(x,y); - } -} - -void goup(int a,int p) { - while (a != p) { - int b = spouse[a], c = Next[b]; - if (findb(c) != p) - Next[c] = b; - if (mark[b] == 2) - mark[Q[bot++] = b] = 1; - if (mark[c] == 2) - mark[Q[bot++] = c] = 1; - together(a,b); - together(b,c); - a = c; - } -} - -void findaugment(int s) { - for (int i = 0; i < N; i++) - Next[i] = -1, belong[i] = i, mark[i] = 0, visited[i] = -1; - Q[0] = s; - bot = 1; - mark[s] = 1; - for (int head = 0; spouse[s] == -1 && head < bot; head++) { - int x = Q[head]; - for (int i = 0; i < (int)E[x].size(); i++) { - int y = E[x][i]; - if (spouse[x] != y && findb(x) != findb(y) && mark[y] != 2) { - if (mark[y] == 1) { - int p = findLCA(x,y); - if (findb(x) != p) - Next[x] = y; - if (findb(y) != p) - Next[y] = x; - goup(x,p); - goup(y,p); - } - else if (spouse[y] == -1) { - Next[y] = x; - for (int j = y; j != -1; ) { - int k = Next[j]; - int l = spouse[k]; - spouse[j] = k; - spouse[k] = j; - j = l; - } - break; - } - else{ - Next[y] = x; - mark[Q[bot++] = spouse[y]] = 1; - mark[y] = 2; - } - } - } - } -} - -int Map[NMax][NMax]; - -int main() { - memset(Map, 0, sizeof(Map)); - - scanf("%d",&N); - int x, y; - while (scanf("%d%d",&x,&y) != EOF) { - x--; - y--; - if (x != y && !Map[x][y]) { - Map[x][y] = Map[y][x] = 1; - E[x].push_back(y); - E[y].push_back(x); - } - } - memset(spouse, -1, sizeof(spouse)); - for (int i = 0; i < N; i++) - if (spouse[i] == -1) - findaugment(i); - int ret = 0; - for (int i = 0; i < N; i++) - if (spouse[i] != -1) - ret++; - printf("%d\n", ret); - for (int i = 0; i < N; i++) - if (spouse[i] != -1 && spouse[i] > i) - printf("pair: %d %d\n", i + 1, spouse[i] + 1); -} +### 5.4 Maximum Matching + +#### 5.4.1 on Bipartite Graph 二分图 + +> 1. A graph is bipartite if and only if it does not contain an odd cycle. +> 2. A graph is bipartite if and only if it is 2-colorable, (i.e. its chromatic number is less than or equal to 2). +> 3. The spectrum of a graph is symmetric if and only if it's a bipartite graph. + +##### 5.4.1.1 Hungarian algorithm 匈牙利算法 + +> O(E * V) + +```c++ +struct Network { + struct Edge { + int to; + int pre_edge; + int cap; + int flow; + }; + + #define MAXNODE 405 + int last[MAXNODE]; + + int nv; // total number of vertex, index range: [0, nv) + vector edge; + void init(int _nv) { + nv = _nv; + edge.clear(); + fill(last, last + nv, -1); + } + + void add_e(int x, int y, int cap, int r_cap = 0) { + Edge e = {y, last[x], cap, 0}; + // Edge e{y, last[x], cap, 0}; + last[x] = edge.size(); + // edge.push_back(move(e)); + edge.push_back(e); + + Edge r_e = {x, last[y], r_cap, 0}; + // Edge r_e{x, last[y], r_cap, 0}; + last[y] = edge.size(); + // edge.push_back(move(r_e)); + edge.push_back(r_e); + } + void show_edge() { + for (int i = 0; i < nv; i++) { + printf("v [%d]:", i); + for (int ie = last[i]; ie != -1; ) { + const Edge& e = edge[ie]; + ie = e.pre_edge; + printf(" [%d]%d/%d", e.to, e.flow, e.cap); + } + printf("\n"); + } + printf("\n"); + } + + // + // bipartite match + // O(V * E) + int peer[MAXNODE]; + bool went[MAXNODE]; + int bipartite_match() { + fill(peer, peer + nv, -1); + int ans = 0; + for (int i = 0; i < nv; i++) { + if (last[i] == -1 || peer[i] != -1) + continue; + fill(went, went + nv, false); + if (match(i)) + ans++; + } + return ans; + } + bool match(int cur) { + for (int ie = last[cur]; ie != -1; ) { + const Edge& e = edge[ie]; + ie = e.pre_edge; + int to = e.to; + if (went[to]) + continue; + went[to] = true; + if (peer[to] == -1 || match(peer[to])) { + peer[to] = cur; + peer[cur] = to; + return true; + } + } + return false; + } + void show_peer() { + for (int i = 0; i < nv; i++) + printf("%d peer-> %d\n", i, peer[i]); + } + // end of + // bipartite match + // +}; +``` + +##### 5.4.1.2 Hopcroft–Karp Algorithm + +> O(sqrt(V)*E) + +```c++ +#define MAXN 1010 +#define MAXINT 0x7fffffff + +int n, m, top, x, y; +int ans; + +int disx[MAXN], disy[MAXN], matx[MAXN], maty[MAXN];//x,y,分别为二分图的两个点集,mat为每个点在对侧集合的匹配点,如果当前没有匹配点则为-1 + +struct edge { + int to; + edge *next; +}e[MAXN*MAXN], *prev[MAXN]; + +void insert(int u,int v) { + e[++top].to = v; + e[top].next = prev[u]; + prev[u] = &e[top]; +} + +bool bfs() { // 寻找最短增广路 + bool ret = 0; + queue q; + memset(disx, 0, sizeof(disx)); + memset(disy, 0, sizeof(disy)); + for (int i = 1; i <= n; i++) + if (matx[i] == -1) + q.push(i); // 找到未盖点,入队 + while (!q.empty()) { // 在二分图另一个点集的非盖点中寻找增广路 + int x = q.front(); q.pop(); + for (edge *i = prev[x]; i; i = i->next) + if (!disy[i->to]) { + disy[i->to] = disx[x] + 1; + if (maty[i->to]==-1) + ret = 1; // 找到增广路 + else + disx[maty[i->to]] = disy[i->to] + 1, q.push(maty[i->to]); + } + } + return ret; +} + +bool dfs(int x) { // 沿增广路增广 + for (edge *i = prev[x]; i; i = i->next) { + if (disy[i->to] == disx[x] + 1) { + disy[i->to] = 0; + if (maty[i->to] == -1 || dfs(maty[i->to])) { + matx[x] = i->to; + maty[i->to] = x; + return 1; + } + } + } + return 0; +} + +int main() { + scanf("%d%d",&n,&m); + memset(matx, -1, sizeof(matx)); + memset(maty, -1, sizeof(maty)); + /*for (int i=1;i<=n;i++) + { + scanf("%d%d",&x,&y);x++;y++; + insert(i,x);insert(i,y); + }建图请自动忽略*/ + while (bfs()) { + for (int i = 1; i <= m; i++) + if (matx[i] == -1 && dfs(i)) + ans++; + } + cout << ans << endl; +} +``` + +#### 5.4.2 on General Graph + +##### 5.4.2.1 Blossom Algorithm + +[一般图最大匹配](http://www.conlan.cc/2013/03/08/%E4%B8%80%E8%88%AC%E5%9B%BE%E6%9C%80%E5%A4%A7%E5%8C%B9%E9%85%8D/) + +```c++ +const int NMax = 230; + +int Next[NMax]; +int spouse[NMax]; +int belong[NMax]; + +int findb(int a) { + return belong[a] == a ? a : belong[a] = findb(belong[a]); +} + +void together(int a,int b) { + a = findb(a), b = findb(b); + if (a != b) + belong[a] = b; +} + +vector E[NMax]; +int N; +int Q[NMax],bot; +int mark[NMax]; +int visited[NMax]; + +int findLCA(int x,int y) { + static int t = 0; + t++; + while (1) { + if (x!=-1) { + x = findb(x); + if (visited[x] == t) + return x; + visited[x] = t; + if (spouse[x] != -1) + x = Next[spouse[x]]; + else x = -1; + } + swap(x,y); + } +} + +void goup(int a,int p) { + while (a != p) { + int b = spouse[a], c = Next[b]; + if (findb(c) != p) + Next[c] = b; + if (mark[b] == 2) + mark[Q[bot++] = b] = 1; + if (mark[c] == 2) + mark[Q[bot++] = c] = 1; + together(a,b); + together(b,c); + a = c; + } +} + +void findaugment(int s) { + for (int i = 0; i < N; i++) + Next[i] = -1, belong[i] = i, mark[i] = 0, visited[i] = -1; + Q[0] = s; + bot = 1; + mark[s] = 1; + for (int head = 0; spouse[s] == -1 && head < bot; head++) { + int x = Q[head]; + for (int i = 0; i < (int)E[x].size(); i++) { + int y = E[x][i]; + if (spouse[x] != y && findb(x) != findb(y) && mark[y] != 2) { + if (mark[y] == 1) { + int p = findLCA(x,y); + if (findb(x) != p) + Next[x] = y; + if (findb(y) != p) + Next[y] = x; + goup(x,p); + goup(y,p); + } + else if (spouse[y] == -1) { + Next[y] = x; + for (int j = y; j != -1; ) { + int k = Next[j]; + int l = spouse[k]; + spouse[j] = k; + spouse[k] = j; + j = l; + } + break; + } + else{ + Next[y] = x; + mark[Q[bot++] = spouse[y]] = 1; + mark[y] = 2; + } + } + } + } +} + +int Map[NMax][NMax]; + +int main() { + memset(Map, 0, sizeof(Map)); + + scanf("%d",&N); + int x, y; + while (scanf("%d%d",&x,&y) != EOF) { + x--; + y--; + if (x != y && !Map[x][y]) { + Map[x][y] = Map[y][x] = 1; + E[x].push_back(y); + E[y].push_back(x); + } + } + memset(spouse, -1, sizeof(spouse)); + for (int i = 0; i < N; i++) + if (spouse[i] == -1) + findaugment(i); + int ret = 0; + for (int i = 0; i < N; i++) + if (spouse[i] != -1) + ret++; + printf("%d\n", ret); + for (int i = 0; i < N; i++) + if (spouse[i] != -1 && spouse[i] > i) + printf("pair: %d %d\n", i + 1, spouse[i] + 1); +} ``` ### 5.5 Maximum Flow Problem 最大流 @@ -4015,8 +4018,8 @@ struct Network { ``` -#### 5.5.2 Improved SAP + Gap Optimization - +#### 5.5.2 Improved SAP + Gap Optimization + > TODO add more optimizations ```c++ @@ -4214,14 +4217,14 @@ void min_cost_max_flow() { while (bellman_ford(flow_sum, cost_sum)); cout << flow_sum << " " << cost_sum << endl; } -``` - -#### 5.5.4 More Applications and Properties - +``` + +#### 5.5.4 More Applications and Properties + > placeholder -### 5.6 强连通分量 图的 割点, 桥, 双连通分支 - +### 5.6 强连通分量 图的 割点, 桥, 双连通分支 + ``https://www.byvoid.com/blog/biconnect`` > [点连通度与边连通度] @@ -4868,7 +4871,7 @@ int main(int argc, char const *argv[]) { #### 6.3.8 最小公倍数 ```C++ -a / gcd(a, b) * b +a / gcd(a, b) * b ``` #### 6.3.9 分解质因数 @@ -4905,78 +4908,78 @@ bool is_prime(int n) { return false; return true; } -``` - -##### 6.3.11.1 Miller Rabin Primality Test - -> O(k(logN)^3) - -```c++ -class MillerRabin { // O(k(logX)^3) - long long mulmod(long long a, long long b, long long c) { - if (a < b) - swap(a, b); - long long res = 0, x = a; - while (b > 0) { - if (b & 1) { - res = res + x; - if (res >= c) - res -= c; - } - x = x * 2; - if (x >= c) - x -= c; - b >>= 1; - } - return res % c; - } - - long long bigmod(long long a, long long p, long long mod) { - long long x = a, res = 1; - while (p) { - if (p & 1) - res = mulmod(res, x, mod); - x = mulmod(x, x, mod); - p >>= 1; - } - return res; - } - - bool witness(long long a, long long d, long long s, long long n) { - long long r = bigmod(a, d, n); - if (r == 1 || r == n - 1) - return false; - for (int i = 0; i < s - 1; i++) { - r = mulmod(r, r, n); - if (r == 1) - return true; - if (r == n - 1) - return false; - } - return true; - } - -public: - const vector aaa{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}; // enough for N < 2^64 - - bool test(long long n) { - if (n <= 1) - return false; - - long long p = n - 1; - long long s = 0; - while (!(p & 1)) { - p /= 2; - s++; - } - - for (int i = 0; i < aaa.size() && aaa[i] < n; i++) - if (witness(aaa[i], p, s, n)) - return false; - return true; - } -}; -``` +``` + +##### 6.3.11.1 Miller Rabin Primality Test + +> O(k(logN)^3) + +```c++ +class MillerRabin { // O(k(logX)^3) + long long mulmod(long long a, long long b, long long c) { + if (a < b) + swap(a, b); + long long res = 0, x = a; + while (b > 0) { + if (b & 1) { + res = res + x; + if (res >= c) + res -= c; + } + x = x * 2; + if (x >= c) + x -= c; + b >>= 1; + } + return res % c; + } + + long long bigmod(long long a, long long p, long long mod) { + long long x = a, res = 1; + while (p) { + if (p & 1) + res = mulmod(res, x, mod); + x = mulmod(x, x, mod); + p >>= 1; + } + return res; + } + + bool witness(long long a, long long d, long long s, long long n) { + long long r = bigmod(a, d, n); + if (r == 1 || r == n - 1) + return false; + for (int i = 0; i < s - 1; i++) { + r = mulmod(r, r, n); + if (r == 1) + return true; + if (r == n - 1) + return false; + } + return true; + } + +public: + const vector aaa{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}; // enough for N < 2^64 + + bool test(long long n) { + if (n <= 1) + return false; + + long long p = n - 1; + long long s = 0; + while (!(p & 1)) { + p /= 2; + s++; + } + + for (int i = 0; i < aaa.size() && aaa[i] < n; i++) + if (witness(aaa[i], p, s, n)) + return false; + return true; + } +}; +``` #### 6.3.12 进制转换 @@ -4999,9 +5002,9 @@ int convert_base_to_dec(const int s[], const int len, const int base) { } ``` -#### 6.3.13 A / C +#### 6.3.13 A / C -> C(n, k) = C(n-1, k) + C(n-1, k-1) +> C(n, k) = C(n-1, k) + C(n-1, k-1) > > C(n, k) = C(n, n-k) @@ -5048,231 +5051,231 @@ int power_modulo(int n, int p, int M) { } return result; } -``` - -#### 6.3.16 Fast Fourier Transform FFT - -> [Reference 1](www.gatevin.moe/acm/fft算法学习笔记/) -> -> [Reference 2](https://github.com/marioyc/ACM-ICPC-Library/blob/master/math/fft.cpp) -> -> Example: calculate two number C = A * B - -```c++ -#include -#include -#include - -#ifndef M_PI -const double M_PI = acos(-1); -#endif - -using namespace std; - -typedef complex Complex; - -void FFT(vector &A, int s) { - int n = A.size(); - int p = __builtin_ctz(n); - - vector a = A; - - for (int i = 0; i < n; ++i) { - int rev = 0; - for (int j = 0; j < p; ++j) { - rev <<= 1; - rev |= ((i >> j) & 1); - } - A[i] = a[rev]; - } - - Complex w, wn; - - for (int i = 1; i <= p; ++i) { - int M = (1<>1); - wn = Complex(cos(s*2.0*M_PI/(double)M), sin(s*2.0*M_PI/(double)M)); - - for (int j = 0; j < n; j += M) { - w = Complex(1.0, 0.0); - for (int l = j; l < K + j; ++l) { - Complex t = w; - t *= A[l + K]; - Complex u = A[l]; - A[l] += t; - u -= t; - A[l + K] = u; - w *= wn; - } - } - } - - if (s == -1) { - for (int i = 0; i < n; ++i) - A[i] /= (double)n; - } -} - -vector FFT_Multiply(vector &P, vector &Q) { - int n = P.size() + Q.size(); - -#define lowbit(x) (((x) ^ (x-1)) & (x)) - while (n != lowbit(n)) n += lowbit(n); -#undef lowbit - - P.resize(n, 0); - Q.resize(n, 0); - - FFT(P, 1); - FFT(Q, 1); - - vector R; - for (int i = 0; i < n; i++) R.push_back(P[i] * Q[i]); - - FFT(R, -1); - - return R; -} - -int main() { // multiply two number - string sa; // [a1 * 10^(?)] + [a2 * 10^(?)] + ... + [an * 10^(?)] - string sb; // [b1 * 10^(?)] + [b2 * 10^(?)] + ... + [bm * 10^(?)] - while (cin >> sa >> sb) { - vector a; - vector b; - - for (int i = 0; i < sa.length(); i++) - a.push_back(Complex(sa[sa.length() - i - 1] - '0', 0)); // add [a_ * (x)^(?)] - for (int i = 0; i < sb.length(); i++) - b.push_back(Complex(sb[sb.length() - i - 1] - '0', 0)); // add [b_ * (x)^(?)] - - // [c1 * 10^(?)] + [c2 * 10^(?)] + ... + [cn * 10^(?)] - // = - // [a1 * 10^(?)] + [a2 * 10^(?)] + ... + [an * 10^(?)] - // * - // [b1 * 10^(?)] + [b2 * 10^(?)] + ... + [bm * 10^(?)] - vector c = FFT_Multiply(a, b); - - vector ans(c.size()); - for (int i = 0; i < c.size(); i++) - ans[i] = c[i].real() + 0.5; // extract [c_ * (x)^(?)] // equivalent to [c_ * (x=10)^(?)] - for (int i = 0; i < ans.size() - 1; i++) { // process carry - ans[i + 1] += ans[i] / 10; - ans[i] %= 10; - } - - bool flag = false; - for (int i = ans.size() - 1; i >= 0; i--) { // print from most significant digit - if (ans[i]) - cout << ans[i], flag = true; - else if (flag || i == 0) - cout << 0; - } - cout << endl; - } -} +``` + +#### 6.3.16 Fast Fourier Transform FFT + +> [Reference 1](www.gatevin.moe/acm/fft算法学习笔记/) +> +> [Reference 2](https://github.com/marioyc/ACM-ICPC-Library/blob/master/math/fft.cpp) +> +> Example: calculate two number C = A * B + +```c++ +#include +#include +#include + +#ifndef M_PI +const double M_PI = acos(-1); +#endif + +using namespace std; + +typedef complex Complex; + +void FFT(vector &A, int s) { + int n = A.size(); + int p = __builtin_ctz(n); + + vector a = A; + + for (int i = 0; i < n; ++i) { + int rev = 0; + for (int j = 0; j < p; ++j) { + rev <<= 1; + rev |= ((i >> j) & 1); + } + A[i] = a[rev]; + } + + Complex w, wn; + + for (int i = 1; i <= p; ++i) { + int M = (1<>1); + wn = Complex(cos(s*2.0*M_PI/(double)M), sin(s*2.0*M_PI/(double)M)); + + for (int j = 0; j < n; j += M) { + w = Complex(1.0, 0.0); + for (int l = j; l < K + j; ++l) { + Complex t = w; + t *= A[l + K]; + Complex u = A[l]; + A[l] += t; + u -= t; + A[l + K] = u; + w *= wn; + } + } + } + + if (s == -1) { + for (int i = 0; i < n; ++i) + A[i] /= (double)n; + } +} + +vector FFT_Multiply(vector &P, vector &Q) { + int n = P.size() + Q.size(); + +#define lowbit(x) (((x) ^ (x-1)) & (x)) + while (n != lowbit(n)) n += lowbit(n); +#undef lowbit + + P.resize(n, 0); + Q.resize(n, 0); + + FFT(P, 1); + FFT(Q, 1); + + vector R; + for (int i = 0; i < n; i++) R.push_back(P[i] * Q[i]); + + FFT(R, -1); + + return R; +} + +int main() { // multiply two number + string sa; // [a1 * 10^(?)] + [a2 * 10^(?)] + ... + [an * 10^(?)] + string sb; // [b1 * 10^(?)] + [b2 * 10^(?)] + ... + [bm * 10^(?)] + while (cin >> sa >> sb) { + vector a; + vector b; + + for (int i = 0; i < sa.length(); i++) + a.push_back(Complex(sa[sa.length() - i - 1] - '0', 0)); // add [a_ * (x)^(?)] + for (int i = 0; i < sb.length(); i++) + b.push_back(Complex(sb[sb.length() - i - 1] - '0', 0)); // add [b_ * (x)^(?)] + + // [c1 * 10^(?)] + [c2 * 10^(?)] + ... + [cn * 10^(?)] + // = + // [a1 * 10^(?)] + [a2 * 10^(?)] + ... + [an * 10^(?)] + // * + // [b1 * 10^(?)] + [b2 * 10^(?)] + ... + [bm * 10^(?)] + vector c = FFT_Multiply(a, b); + + vector ans(c.size()); + for (int i = 0; i < c.size(); i++) + ans[i] = c[i].real() + 0.5; // extract [c_ * (x)^(?)] // equivalent to [c_ * (x=10)^(?)] + for (int i = 0; i < ans.size() - 1; i++) { // process carry + ans[i + 1] += ans[i] / 10; + ans[i] %= 10; + } + + bool flag = false; + for (int i = ans.size() - 1; i >= 0; i--) { // print from most significant digit + if (ans[i]) + cout << ans[i], flag = true; + else if (flag || i == 0) + cout << 0; + } + cout << endl; + } +} ``` ### 6.4 Game Theory 博弈论 -#### 6.4.1 Impartial Combinatorial Game - -> In combinatorial game theory, an impartial game is a game in which the allowable moves depend only on the position and not on which of the two players is currently moving, and where the payoffs are symmetric. In other words, the only difference between player 1 and player 2 is that player 1 goes first. - -> Impartial games can be analyzed using the Sprague–Grundy theorem. - -> Impartial games include Nim, Sprouts, Kayles, Quarto, Cram, Chomp, and poset games. Go and chess are not impartial, as each player can only place or move pieces of their own color. Games like ZÈRTZ and Chameleon are also not impartial, since although they are played with shared pieces, the payoffs are not necessarily symmetric for any given position. - -> A game that is not impartial is called a partisan game. -> -> [source: wiki](https://en.wikipedia.org/wiki/Impartial_game) -> -> [tutorial: topcoder](https://www.topcoder.com/community/data-science/data-science-tutorials/algorithm-games/) - -##### 6.4.1.1 Nim Game - -> One good choice: brute force to find some pattern. -> -> We will not be able to play many of the games without decomposing them to smaller parts (sub-games), pre-computing some values for them, and then obtaining the result by combining these values. -> -> Positions have the following properties: -> -> - All terminal positions are losing. -> - If a player is able to move to a losing position then he is in a winning position. -> - If a player is able to move only to the winning positions then he is in a losing position. -> -> Rules of the Game of Nim: There are n piles of coins. When it is a player’s turn he chooses one pile and takes at least one coin from it. If someone is unable to move he loses (so the one who removes the last coin is the winner). -> -> Let n1, n2, ..., nk, be the sizes of the piles. It is a losing position for the player whose turn it is if and only if n1 xor n2 xor ... xor nk = 0. - -##### 6.4.1.1 Composite Games – Sprague-Grundy Theorem and Nim Value - -> - Break composite game into subgames -> - Assign grundy number to every subgame according to which size of the pile in the Game of Nim it is equivalent to. -> - Now we have some subgames (piles), each subgame has its grundy number (size of pile) -> - xor all subgames - -> - Losing position of subgame has grundy number = 0. -> - A position has grundy number = smallest number among its next positions don't have. - -> If the table of grundy number is too large, we can precompute and find the pattern. - -```c++ -// hihocoer 1173 -const int MAXSTATE = 2e4 + 2; - -bool appear[MAXSTATE]; -int sg[MAXSTATE]; // Sprague-Grundy // Nim Value -void init_sg() { - sg[state] = 0; - for (int state = 1; state < MAXSTATE; state++) { // sg(x) = mex{sg(y) | y是x的后继局面} // mex{a[i]}表示a中未出现的最小非负整数 - fill_n(appear, MAXSTATE, false); - for (int nx = 0; nx < state; nx++) - appear[sg[nx]] = true; - int pile_a = 1; - int pile_b = state - pile_a; - while (pile_a <= pile_b) { - appear[sg[pile_a] ^ sg[pile_b]] = true; - pile_a++; - pile_b--; - } - while (appear[sg[state]]) - sg[state]++; - } -} - -int main() { - - init_sg(); - - // --- start of finding pattern --- - // - // --- end of finding pattern --- - - int n; - cin >> n; - int result = 0; - for (int i = 0; i < n; i++) { - int a; - cin >> a; - - // by grundy number - // result ^= sg[a]; - - // by pattern - // if (a % 4 == 0) - // a--; - // else if (a % 4 == 3) - // a++; - // result ^= a; - } - if (result) - cout << "Alice" << endl; - else - cout << "Bob" << endl; -} -``` - - +#### 6.4.1 Impartial Combinatorial Game + +> In combinatorial game theory, an impartial game is a game in which the allowable moves depend only on the position and not on which of the two players is currently moving, and where the payoffs are symmetric. In other words, the only difference between player 1 and player 2 is that player 1 goes first. + +> Impartial games can be analyzed using the Sprague–Grundy theorem. + +> Impartial games include Nim, Sprouts, Kayles, Quarto, Cram, Chomp, and poset games. Go and chess are not impartial, as each player can only place or move pieces of their own color. Games like ZÈRTZ and Chameleon are also not impartial, since although they are played with shared pieces, the payoffs are not necessarily symmetric for any given position. + +> A game that is not impartial is called a partisan game. +> +> [source: wiki](https://en.wikipedia.org/wiki/Impartial_game) +> +> [tutorial: topcoder](https://www.topcoder.com/community/data-science/data-science-tutorials/algorithm-games/) + +##### 6.4.1.1 Nim Game + +> One good choice: brute force to find some pattern. +> +> We will not be able to play many of the games without decomposing them to smaller parts (sub-games), pre-computing some values for them, and then obtaining the result by combining these values. +> +> Positions have the following properties: +> +> - All terminal positions are losing. +> - If a player is able to move to a losing position then he is in a winning position. +> - If a player is able to move only to the winning positions then he is in a losing position. +> +> Rules of the Game of Nim: There are n piles of coins. When it is a player’s turn he chooses one pile and takes at least one coin from it. If someone is unable to move he loses (so the one who removes the last coin is the winner). +> +> Let n1, n2, ..., nk, be the sizes of the piles. It is a losing position for the player whose turn it is if and only if n1 xor n2 xor ... xor nk = 0. + +##### 6.4.1.1 Composite Games – Sprague-Grundy Theorem and Nim Value + +> - Break composite game into subgames +> - Assign grundy number to every subgame according to which size of the pile in the Game of Nim it is equivalent to. +> - Now we have some subgames (piles), each subgame has its grundy number (size of pile) +> - xor all subgames + +> - Losing position of subgame has grundy number = 0. +> - A position has grundy number = smallest number among its next positions don't have. + +> If the table of grundy number is too large, we can precompute and find the pattern. + +```c++ +// hihocoer 1173 +const int MAXSTATE = 2e4 + 2; + +bool appear[MAXSTATE]; +int sg[MAXSTATE]; // Sprague-Grundy // Nim Value +void init_sg() { + sg[state] = 0; + for (int state = 1; state < MAXSTATE; state++) { // sg(x) = mex{sg(y) | y是x的后继局面} // mex{a[i]}表示a中未出现的最小非负整数 + fill_n(appear, MAXSTATE, false); + for (int nx = 0; nx < state; nx++) + appear[sg[nx]] = true; + int pile_a = 1; + int pile_b = state - pile_a; + while (pile_a <= pile_b) { + appear[sg[pile_a] ^ sg[pile_b]] = true; + pile_a++; + pile_b--; + } + while (appear[sg[state]]) + sg[state]++; + } +} + +int main() { + + init_sg(); + + // --- start of finding pattern --- + // + // --- end of finding pattern --- + + int n; + cin >> n; + int result = 0; + for (int i = 0; i < n; i++) { + int a; + cin >> a; + + // by grundy number + // result ^= sg[a]; + + // by pattern + // if (a % 4 == 0) + // a--; + // else if (a % 4 == 3) + // a++; + // result ^= a; + } + if (result) + cout << "Alice" << endl; + else + cout << "Bob" << endl; +} +``` + + ## 7. Geometry @@ -5280,83 +5283,83 @@ int main() { #### 7.1.1 Template of Point -```C++ -struct point { - int x, y; - - double length() { - return sqrt(x*x + y*y); - } - - point operator + (const point &rhs) const { - return (point){x + rhs.x, y + rhs.y}; - } - - point operator - (const point &rhs) const { - return (point){x - rhs.x, y - rhs.y}; - } - - long operator* (const point& b) { - return x*b.y - y*b.x; - } - - long cross_product(const point& b) { - return x * b.x + y * b.y; - } - - bool at_right_of(const point& a, const point& b) const { - // a: relative point, b: base - point vec_self = {x - b.x, y - b.y}; - point vec_that = {a.x - b.x, a.y - b.y}; - long product = vec_self * vec_that; - if (product>0) return true; - if (product==0 && vec_self.length()>vec_that.length()) return true; - return false; - } - - double to_point(const point& b) const { - return sqrt(pow(x-b.x,2) + pow(y-b.y,2)); - } - - double to_segment(const point& a, const point& b) const { - double len_ab = a.to_point(b); - if (abs(len_ab)1 || r<0) return min(to_point(a), to_point(b)); - // projection of p is on extension of AB - r = ((a.y - y)*(b.y - y) - (a.x - x)*(b.y - a.y))/pow(len_ab,2); - return fabs(r*len_ab); - } - - double to_segment(const point& a, const point& b) const { - point vec_ab = {b.x - a.x, b.y - a.y}; - point vec_ia = {x - a.x, y - a.y}; - point vec_ib = {x - b.x, y - b.y}; - if (vec_ia.cross_product(vec_ab) < 0 || vec_ib.cross_product(vec_ab) > 0) - return min(to_point(a), to_point(b)); - return abs(vec_ab * vec_ia) / vec_ab.length(); - } // same meaning with v1, need test - - double to_line(const point& a, const point& b) const { - point vec_ab = {b.x - a.x, b.y - a.y}; - point vec_ia = {x - a.x, y - a.y}; - return abs(vec_ab * vec_ia) / vec_ab.length(); - } // same meaning with v1, need test - - point rotate(const point &rhs, double angle) const { - point t = (*this) - rhs; - double c = cos(angle), s = sin(angle); - return (point){rhs.x + t.x * c - t.y * s, rhs.y + t.x * s + t.y * c}; - } -}; +```C++ +struct point { + int x, y; + + double length() { + return sqrt(x*x + y*y); + } + + point operator + (const point &rhs) const { + return (point){x + rhs.x, y + rhs.y}; + } + + point operator - (const point &rhs) const { + return (point){x - rhs.x, y - rhs.y}; + } + + long operator* (const point& b) { + return x*b.y - y*b.x; + } + + long cross_product(const point& b) { + return x * b.x + y * b.y; + } + + bool at_right_of(const point& a, const point& b) const { + // a: relative point, b: base + point vec_self = {x - b.x, y - b.y}; + point vec_that = {a.x - b.x, a.y - b.y}; + long product = vec_self * vec_that; + if (product>0) return true; + if (product==0 && vec_self.length()>vec_that.length()) return true; + return false; + } + + double to_point(const point& b) const { + return sqrt(pow(x-b.x,2) + pow(y-b.y,2)); + } + + double to_segment(const point& a, const point& b) const { + double len_ab = a.to_point(b); + if (abs(len_ab)1 || r<0) return min(to_point(a), to_point(b)); + // projection of p is on extension of AB + r = ((a.y - y)*(b.y - y) - (a.x - x)*(b.y - a.y))/pow(len_ab,2); + return fabs(r*len_ab); + } + + double to_segment(const point& a, const point& b) const { + point vec_ab = {b.x - a.x, b.y - a.y}; + point vec_ia = {x - a.x, y - a.y}; + point vec_ib = {x - b.x, y - b.y}; + if (vec_ia.cross_product(vec_ab) < 0 || vec_ib.cross_product(vec_ab) > 0) + return min(to_point(a), to_point(b)); + return abs(vec_ab * vec_ia) / vec_ab.length(); + } // same meaning with v1, need test + + double to_line(const point& a, const point& b) const { + point vec_ab = {b.x - a.x, b.y - a.y}; + point vec_ia = {x - a.x, y - a.y}; + return abs(vec_ab * vec_ia) / vec_ab.length(); + } // same meaning with v1, need test + + point rotate(const point &rhs, double angle) const { + point t = (*this) - rhs; + double c = cos(angle), s = sin(angle); + return (point){rhs.x + t.x * c - t.y * s, rhs.y + t.x * s + t.y * c}; + } +}; ``` #### 7.1.2 向量点乘 叉乘 -> a = (x1, y1) +> a = (x1, y1) > > b = (x2, y2) -> +> > i ... |i| = 1, vertical to a-b surface #### 7.1.3 dot product @@ -5375,7 +5378,7 @@ struct point { > > if 0: b is at right of a > -> a x b = area of 平行四边形 +> a x b = area of 平行四边形 > > a x b x c = area of 平行六面体, c = (x3, y3) @@ -5591,53 +5594,53 @@ void passFunc(int **a) { // ... } passFunc(array); -``` - -### 8.3 Binary Display - -```c++ -#include -void show_binary(unsigned long long x) { - printf("%s\n", bitset<64>(x).to_string().c_str()); -} -``` - -### 8.4 Fast Log - -> Built-in ``log(double)`` is not accurate for integer. -> -> Should ``(int)(log(double)+0.000....001)`` - -```c++ -int fastlog(unsigned long long x, unsigned long long base) { - // ERROR VALUE IF X == BASE == ULLONG_MAX - - const unsigned long long HALF = 1ULL << 32; - unsigned long long cache[7]; -#define INIT(i) { cache[i] = base; if (base < HALF) base *= base; else base = ULLONG_MAX; } - INIT(0); INIT(1); INIT(2); INIT(3); INIT(4); INIT(5); INIT(6); -#undef INIT - - int ret = -(x == 0); -#define S(i, k) if (x >= cache[i]) ret += k, x /= cache[i]; else return ret; - S(6, 64); S(5, 32); S(4, 16); S(3, 8); S(2, 4); S(1, 2); S(0, 1); -#undef S -} -``` - -### 8.5 Squre Root - -```c++ -long long sq(long long a) { - long long l = 1; - long long r = a + 1; - while (l + 1 < r) { - long long m = (l + r) / 2; - if (a / m < m) - r = m; - else - l = m; - } - return l; -} -``` \ No newline at end of file +``` + +### 8.3 Binary Display + +```c++ +#include +void show_binary(unsigned long long x) { + printf("%s\n", bitset<64>(x).to_string().c_str()); +} +``` + +### 8.4 Fast Log + +> Built-in ``log(double)`` is not accurate for integer. +> +> Should ``(int)(log(double)+0.000....001)`` + +```c++ +int fastlog(unsigned long long x, unsigned long long base) { + // ERROR VALUE IF X == BASE == ULLONG_MAX + + const unsigned long long HALF = 1ULL << 32; + unsigned long long cache[7]; +#define INIT(i) { cache[i] = base; if (base < HALF) base *= base; else base = ULLONG_MAX; } + INIT(0); INIT(1); INIT(2); INIT(3); INIT(4); INIT(5); INIT(6); +#undef INIT + + int ret = -(x == 0); +#define S(i, k) if (x >= cache[i]) ret += k, x /= cache[i]; else return ret; + S(6, 64); S(5, 32); S(4, 16); S(3, 8); S(2, 4); S(1, 2); S(0, 1); +#undef S +} +``` + +### 8.5 Squre Root + +```c++ +long long sq(long long a) { + long long l = 1; + long long r = a + 1; + while (l + 1 < r) { + long long m = (l + r) / 2; + if (a / m < m) + r = m; + else + l = m; + } + return l; +} +```