├── .github └── workflows │ └── gh-pages.yml ├── .gitignore ├── README.md ├── book.toml ├── md ├── SUMMARY.md ├── data_structures │ ├── bbst │ │ ├── avl_tree_array.md │ │ ├── avl_tree_array_tuned.md │ │ ├── avl_tree_map.md │ │ ├── avl_tree_map_foldable.md │ │ ├── index.md │ │ ├── persistent_avl_tree_array.md │ │ ├── splay_tree_array.md │ │ └── splay_tree_map.md │ ├── container │ │ ├── fully_retroactive_stack.md │ │ ├── hash_map.md │ │ └── index.md │ ├── heap │ │ ├── index.md │ │ └── pairing_heap.md │ ├── index.md │ ├── other │ │ ├── fenwick_tree.md │ │ ├── index.md │ │ ├── online_dicon.md │ │ ├── range_valued_array.md │ │ └── swag.md │ ├── segment_tree │ │ ├── beats_chmin_sum.md │ │ ├── beats_chminmax_sum.md │ │ ├── beats_chminmaxadd_sum.md │ │ ├── dynamic_segment_tree.md │ │ ├── index.md │ │ ├── lazy_segment_tree.md │ │ ├── li_chao.md │ │ ├── li_chao_segment.md │ │ ├── persistent_segment_tree.md │ │ └── segment_tree.md │ ├── sparse_table │ │ └── sparse_table.md │ ├── trees │ │ ├── euler_tour_path.md │ │ ├── euler_tour_subtree.md │ │ ├── heavy_light_decomposition.md │ │ ├── index.md │ │ ├── link_cut_tree.md │ │ └── toptree.md │ ├── union_find │ │ ├── index.md │ │ ├── persistent_union_find.md │ │ └── union_find.md │ └── wavelet_matrix │ │ ├── dynamic_wavelet_matrix.md │ │ ├── index.md │ │ └── wavelet_matrix.md ├── geometry │ └── geometry.md ├── graph │ ├── centroid_decomposition.md │ ├── gabow_e_algorithm.md │ ├── incremental_bridge_connectivity.md │ ├── index.md │ ├── lattice_graph.md │ ├── max_flow │ │ ├── dinic.md │ │ └── goldberg_tarjan_tuned.md │ ├── mcf │ │ └── primal_dual.md │ ├── sp │ │ ├── bfs.md │ │ ├── dial01.md │ │ └── dijkstra.md │ └── strongly_connected_components.md ├── introduction.md ├── math │ ├── adjucency_matrix_equation.md │ ├── berlekamp_massey.md │ ├── binfps.md │ ├── black_box_linear_algebra.md │ ├── comvolution │ │ └── zeta_mobius_transform.md │ ├── convolution │ │ ├── divisor_transform.md │ │ ├── fast_fourier_transform.md │ │ ├── index.md │ │ ├── multiple_transform.md │ │ ├── numeric_theoretic_transform.md │ │ └── zeta_mobius_transform.md │ ├── crt.md │ ├── factorial.md │ ├── fast_kitamasa.md │ ├── formal_power_series.md │ ├── garner.md │ ├── index.md │ ├── matrix.md │ ├── modint.md │ ├── montgomery_modint.md │ ├── mori_fps_division.md │ ├── newton_interpolation.md │ ├── osa_k.md │ ├── runtime_fp.md │ └── seidels_lp.md ├── string │ ├── 2_31rolling_hash.md │ ├── Z-algorithm.md │ ├── burrows_wheeler.md │ ├── burrows_wheller.md │ ├── index.md │ ├── manacher.md │ ├── mp.md │ ├── rolling_hash.md │ └── suffix_array.md └── tech │ ├── compression.md │ ├── fastio.md │ ├── grundy.md │ ├── index.md │ ├── mo.md │ ├── mongeDP.md │ ├── rerooting.md │ ├── slide_min.md │ └── y_combinator.md └── src ├── data_structures ├── bbst │ ├── avl_tree_array.hpp │ ├── avl_tree_array_tuned.hpp │ ├── avl_tree_foldable.hpp │ ├── avl_tree_map.hpp │ ├── persistent_avl_tree_array.hpp │ ├── splay_tree_array.hpp │ ├── splay_tree_map.hpp │ └── splay_tree_tuned.hpp ├── container │ ├── fully_retroactive_stack.hpp │ └── hash_map.hpp ├── fenwick_tree.hpp ├── heap │ ├── pairing_heap.hpp │ └── radix_heap.hpp ├── online_dynamic_connectivity.hpp ├── range_valued_array.hpp ├── segment_tree │ ├── beats_chmin_sum.hpp │ ├── beats_chminmax_sum.hpp │ ├── beats_chminmaxadd_sum.hpp │ ├── dynamic_segment_tree.hpp │ ├── lazy_segment_tree.hpp │ ├── li_chao.hpp │ ├── li_chao_segment.hpp │ ├── persistent_segment_tree.hpp │ └── segment_tree.hpp ├── sparse_table │ └── sparse_table.hpp ├── swag.hpp ├── trees │ ├── euler_tour_path.hpp │ ├── euler_tour_subtree.hpp │ ├── euler_tour_tree.hpp │ ├── heavy_light_decomposition.hpp │ ├── link_cut_tree.hpp │ ├── toptree.hpp │ └── toptree_tuned.hpp ├── union_find │ ├── persistent_union_find.hpp │ └── union_find.hpp └── wavelet_matrix │ ├── dynamic_bitvector.hpp │ ├── dynamic_wavelet_matrix.hpp │ ├── dynamic_wm_tuned.hpp │ ├── plane_to_line.hpp │ └── wavelet_matrix.hpp ├── easydoc4lib.toml ├── geometry └── geometry.hpp ├── graph ├── centroid_decomposition.hpp ├── gabow_e_algorithm.hpp ├── incremental_bridge_connectivity.hpp ├── lattice_graph.hpp ├── max_flow │ ├── dinic.hpp │ ├── goldberg_tarjan_global_relabeling.hpp │ └── goldberg_tarjan_tuned.hpp ├── mcf │ ├── capacity_scaling_primal_dual.hpp │ └── primal_dual.hpp ├── range_k_wall_graph.hpp ├── sp │ ├── bfs.hpp │ ├── dial01.hpp │ └── dijkstra.hpp └── strongly_connected_components.hpp ├── math ├── adjucency_matrix_equation.hpp ├── berlekamp_massey.hpp ├── bin_matrix.hpp ├── binfps.hpp ├── binomial.hpp ├── black_box_linear_algebra │ ├── fast_determinant.hpp │ ├── fast_matrix_pow.hpp │ └── minimal_polynomial.hpp ├── chinese_remainder_theorem.hpp ├── convolution │ ├── divisor_transform.hpp │ ├── fast_fourier_transform.hpp │ ├── multiple_transform.hpp │ ├── ntt4.hpp │ ├── ntt_stockham.hpp │ ├── number_theoretic_transform.hpp │ └── zeta_mobius_transform.hpp ├── factorial.hpp ├── fast_kitamasa.hpp ├── formal_power_series.hpp ├── fps_multiply_arb.hpp ├── fps_ntt_multiply.hpp ├── garner.hpp ├── matrix.hpp ├── modint.hpp ├── montgomery_modint.hpp ├── mori_fps_division.hpp ├── newton_interpolation.hpp ├── osa_k.hpp ├── runtime_fp.hpp └── seidels_lp.hpp ├── other ├── cppfirst.hpp ├── fastio.hpp ├── grundy.hpp ├── mongeDP.hpp ├── slide_min.hpp └── y_combinator.hpp ├── string ├── 2_61-1_rolling_hash.hpp ├── burrows_wheeler.hpp ├── manacher.hpp ├── mp.hpp ├── rolling_hash.hpp ├── suffix_array.hpp ├── suffix_array_search.hpp └── z-algorithm.hpp └── tech ├── compression.hpp ├── mo.hpp └── rerooting.hpp /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-20.04 12 | concurrency: 13 | group: ${{ github.workflow }}-${{ github.ref }} 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Setup mdBook 17 | uses: peaceiris/actions-mdbook@v1 18 | with: 19 | mdbook-version: 'latest' 20 | 21 | - run: mdbook build 22 | 23 | - name: Deploy 24 | uses: peaceiris/actions-gh-pages@v3 25 | if: ${{ github.ref == 'refs/heads/master' }} 26 | with: 27 | github_token: ${{ secrets.GITHUB_TOKEN }} 28 | publish_dir: ./docs 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | docs/ 3 | .ccls-cache/ 4 | **/.DS_Store 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cp-cpp-library 2 | 3 | [Document](https://niuez.github.io/cp-cpp-library/) 4 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["niuez"] 3 | language = "ja" 4 | multilingual = false 5 | src = "md" 6 | title = "cp-cpp-library Document" 7 | 8 | [build] 9 | build-dir = "docs" 10 | 11 | [output.html] 12 | mathjax-support = true 13 | google-analytics = "UA-157596444-1" 14 | -------------------------------------------------------------------------------- /md/data_structures/bbst/avl_tree_array.md: -------------------------------------------------------------------------------- 1 | # AVL Tree Array 2 | 3 | 列を管理するAVL Tree 4 | 5 | ### Spec 6 | 7 | - `struct node` 8 | - AVL Treeに載せるノードの型 9 | - `fix`に操作を書く 10 | 11 | - `split(size_type i)` 12 | - `[0, i) / [i, ..)`に分けた木を返す 13 | 14 | - `merge(persistent_avl_array&& arr)` 15 | - mergeした木を返す. 16 | 17 | - `at(size_type i)` 18 | - `i`番目の要素にアクセスする. 19 | 20 | - `set(size_type i, value_type val)` 21 | - `i`番目の要素を`val`にする 22 | 23 | ### Code 24 | 25 | ```cpp 26 | {{#include ../../../src/data_structures/bbst/avl_tree_array.hpp}} 27 | ``` 28 | -------------------------------------------------------------------------------- /md/data_structures/bbst/avl_tree_array_tuned.md: -------------------------------------------------------------------------------- 1 | # AVL Tree Array Tuned 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/data_structures/bbst/avl_tree_array_tuned.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/data_structures/bbst/avl_tree_map.md: -------------------------------------------------------------------------------- 1 | # AVL Tree Map 2 | 3 | AVL TreeのMapバージョン 4 | 5 | ### Spec 6 | 7 | - `struct node` 8 | - AVL Treeに載せるノードの型 9 | - `fix`に操作を書く. 10 | 11 | - `at(key_value i)` 12 | - `i`の要素にアクセスする. 13 | 14 | - `insert(key_value key, value_type val)` 15 | - `key`の要素を`val`にする 16 | 17 | - `erase(key_value key)` 18 | - `key`の要素を消す 19 | 20 | - `lower_bound(key_value key)` 21 | - `lower_bound`をしたときの要素を返す. 22 | - `.first`が`false`であるときは`lower_bound`はない. 23 | 24 | - `nth_node(size_type i)` 25 | - `i`番目の要素を返す. 26 | 27 | ### Code 28 | 29 | ```cpp 30 | {{#include ../../../src/data_structures/bbst/avl_tree_array.hpp}} 31 | ``` 32 | -------------------------------------------------------------------------------- /md/data_structures/bbst/avl_tree_map_foldable.md: -------------------------------------------------------------------------------- 1 | # AVL Tree Map Foldable 2 | 3 | AVL TreeのMapバージョンでモノイドを処理できるようにした. 4 | 5 | ### Spec 6 | 7 | - `operation()` 8 | - モノイドの演算を決める 9 | 10 | - `identity()` 11 | - モノイドの単位元を決める 12 | 13 | - `struct node` 14 | - AVL Treeに載せるノードの型 15 | - `fix`に操作を書く. 16 | 17 | - `at(key_value i)` 18 | - `i`の要素にアクセスする. 19 | 20 | - `insert(key_value key, value_type val)` 21 | - `key`の要素を`val`にする 22 | 23 | - `erase(key_value key)` 24 | - `key`の要素を消す 25 | 26 | - `lower_bound(key_value key)` 27 | - `lower_bound`をしたときの要素を返す. 28 | - `.first`が`false`であるときは`lower_bound`はない. 29 | 30 | - `nth_node(size_type i)` 31 | - `i`番目の要素を返す. 32 | 33 | - `fold(key_value left, key_value right)` 34 | - `[left, right)`に対してfoldをする. 35 | 36 | ### Code 37 | 38 | ```cpp 39 | {{#include ../../../src/data_structures/bbst/avl_tree_foldable.hpp}} 40 | ``` 41 | -------------------------------------------------------------------------------- /md/data_structures/bbst/index.md: -------------------------------------------------------------------------------- 1 | # self-Balancing Binary Search Tree 2 | 3 | - [Splay Tree Array](./splay_tree_array.md) 4 | - [Splay Tree Map](./splay_tree_map.md) 5 | - [AVL Tree Array](./avl_tree_array.md) 6 | - [Persistent AVL Tree Array](./persistent_avl_tree_array.md) 7 | 8 | -------------------------------------------------------------------------------- /md/data_structures/bbst/persistent_avl_tree_array.md: -------------------------------------------------------------------------------- 1 | # Persistent AVL Tree Array 2 | 3 | 列を永続的に管理するAVL Tree 4 | 5 | ### Spec 6 | 7 | - `struct node` 8 | - Persistent AVL Treeに載せるノードの型 9 | 10 | - `node(value_ref rootval, node_ref a, node_ref b)` 11 | - 永続化ではノードを作るときだけ`fix`する 12 | - ここにfix操作を書く. 13 | 14 | - `split(size_type i)` 15 | - `[0, i) / [i, ..)`に分けた木を返す 16 | 17 | - `merge(persistent_avl_array&& arr)` 18 | - mergeした木を返す. 19 | 20 | - `at(size_type i)` 21 | - `i`番目の要素にアクセスする. 22 | 23 | - `push_back(val)` 24 | - 列の一番うしろに要素を追加する. 25 | 26 | ### Code 27 | 28 | ```cpp 29 | {{#include ../../../src/data_structures/bbst/persistent_avl_tree_array.hpp}} 30 | ``` 31 | -------------------------------------------------------------------------------- /md/data_structures/bbst/splay_tree_array.md: -------------------------------------------------------------------------------- 1 | # Splay Tree Array 2 | 3 | 列を管理するSplay Tree 4 | 5 | ### Spec 6 | 7 | - `struct node` 8 | - Splay Treeに載せるノードの型 9 | 10 | - `fold(node* x)` 11 | - `fold`したいやつを変えたときはここを変える 12 | 13 | - `fix(node* n)` 14 | - `fix`操作, foldの仕方をここで定義する 15 | 16 | - `reverse(node* n)` 17 | - 反転操作, foldを反転する必要がある場合はここに. 18 | 19 | - `push(node* x)` 20 | - 遅延伝搬させているときはここを変更 21 | 22 | - `split(i64 i)` 23 | - `[0, i) / [i, ..)`に分ける 24 | 25 | - `merge(splay_array&& arr)` 26 | - mergeする 27 | 28 | - `reverse()` 29 | - 列全体を反転させる 30 | 31 | - `update(i64 i, T t)` 32 | - `i`番目の要素を`t`に変更する. 33 | 34 | 35 | ### Code 36 | 37 | ```cpp 38 | {{#include ../../../src/data_structures/bbst/splay_tree_array.hpp}} 39 | ``` 40 | -------------------------------------------------------------------------------- /md/data_structures/bbst/splay_tree_map.md: -------------------------------------------------------------------------------- 1 | # Splay Tree Map 2 | 3 | map型のSplay Tree 4 | 5 | ### Spec 6 | 7 | - `struct node` 8 | - Splay Treeに載せるノードの型 9 | 10 | - `fold(node* x)` 11 | - `fold`したいやつを変えたときはここを変える 12 | 13 | - `fix(node* n)` 14 | - `fix`操作, foldの仕方をここで定義する 15 | 16 | - `reverse(node* n)` 17 | - 反転操作, foldを反転する必要がある場合はここに. 18 | 19 | - `push(node* x)` 20 | - 遅延伝搬させているときはここを変更 21 | 22 | - `insert(Key key, T t)` 23 | - `{key, t}`を入れる, すでに存在する場合はupdate 24 | 25 | - `erase(Key key)` 26 | - `{key, ..}のノードを削除する 27 | 28 | - `nth_node(i64 n)` 29 | - `n`番目の要素の`Key`を返す 30 | 31 | 32 | ### Code 33 | 34 | ```cpp 35 | {{#include ../../../src/data_structures/bbst/splay_tree_map.hpp}} 36 | ``` 37 | -------------------------------------------------------------------------------- /md/data_structures/container/fully_retroactive_stack.md: -------------------------------------------------------------------------------- 1 | # Fully Retroactive Stack 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/data_structures/container/fully_retroactive_stack.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/data_structures/container/hash_map.md: -------------------------------------------------------------------------------- 1 | # Hash Map 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/data_structures/container/hash_map.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/data_structures/container/index.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niuez/cp-cpp-library/edd5375c334cc2ed53b90b21cc7c42751d096d71/md/data_structures/container/index.md -------------------------------------------------------------------------------- /md/data_structures/heap/index.md: -------------------------------------------------------------------------------- 1 | # Heap 2 | -------------------------------------------------------------------------------- /md/data_structures/heap/pairing_heap.md: -------------------------------------------------------------------------------- 1 | # Pairing Heap 2 | 3 | マージ可能で高速なHeap 4 | 5 | ### Spec 6 | 7 | - `top()` 8 | - 最小値を返す 9 | - \\( O(1) \\) 10 | 11 | - `pop()` 12 | - 最小値の要素を削除する 13 | - \\( O(\log n) \\) 14 | 15 | - `push(const T& x)` 16 | - 要素`x`を追加する 17 | - \\( O(1) \\) 18 | 19 | - `meld(h)` 20 | - ヒープ`h`とマージする 21 | - \\( O(1) \\) 22 | 23 | ### Code 24 | 25 | ```cpp 26 | {{#include ../../../src/data_structures/heap/pairing_heap.hpp}} 27 | ``` 28 | -------------------------------------------------------------------------------- /md/data_structures/index.md: -------------------------------------------------------------------------------- 1 | # Data Structures 2 | 3 | いろいろ, あるよね 4 | -------------------------------------------------------------------------------- /md/data_structures/other/fenwick_tree.md: -------------------------------------------------------------------------------- 1 | # Fenwick Tree 2 | ### Spec 3 | 4 | ### Code 5 | 6 | ```cpp 7 | {{#include ../../../src/data_structures/fenwick_tree.hpp}} 8 | ``` 9 | -------------------------------------------------------------------------------- /md/data_structures/other/index.md: -------------------------------------------------------------------------------- 1 | # Data Structures Other 2 | 3 | うまく分類できなかったもの 4 | -------------------------------------------------------------------------------- /md/data_structures/other/online_dicon.md: -------------------------------------------------------------------------------- 1 | # Online Dynamic Connectivity 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/data_structures/online_dynamic_connectivity.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/data_structures/other/range_valued_array.md: -------------------------------------------------------------------------------- 1 | # Range Valued Array 2 | 3 | `[, r)`のmapとして管理する範囲set可能な配列 4 | 5 | ### Spec 6 | 7 | - `(constructor)(value_type init_value)` 8 | - `init_value`: 全域をこの値で初期化する 9 | - `iterator_type range_set_value(key_type l, ley_type r, const value_type& val)` 10 | - `[l, r)`を`val`で初期化する 11 | - `operator[](const key_type& k)` 12 | - インデックス`k`の値を返す 13 | 14 | 15 | ### Code 16 | 17 | ```cpp 18 | {{#include ../../../src/data_structures/range_valued_array.hpp}} 19 | ``` 20 | -------------------------------------------------------------------------------- /md/data_structures/other/swag.md: -------------------------------------------------------------------------------- 1 | # SWAG 2 | ### Spec 3 | 4 | ### Code 5 | 6 | ```cpp 7 | {{#include ../../../src/data_structures/swag.hpp}} 8 | ``` 9 | -------------------------------------------------------------------------------- /md/data_structures/segment_tree/beats_chmin_sum.md: -------------------------------------------------------------------------------- 1 | # Segment Tree Beats (chmin + sum) 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/data_structures/segment_tree/beats_chmin_sum.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/data_structures/segment_tree/beats_chminmax_sum.md: -------------------------------------------------------------------------------- 1 | # Segment Tree Beats (chmin + chmax + sum) 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/data_structures/segment_tree/beats_chminmax_sum.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/data_structures/segment_tree/beats_chminmaxadd_sum.md: -------------------------------------------------------------------------------- 1 | # Segment Tree Beats (chmin + chmax + add + sum) 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/data_structures/segment_tree/beats_chminmaxadd_sum.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/data_structures/segment_tree/dynamic_segment_tree.md: -------------------------------------------------------------------------------- 1 | # Dynamic Segment Tree 2 | ### Spec 3 | 4 | - `using T = ...` 5 | - Dynamic Segment Treeに載せる型 6 | 7 | - `T ope(const T& a, const T& b)` 8 | - Tの演算を指定する 9 | 10 | - `T ide()` 11 | - Tの単位元を返す 12 | 13 | - `dynamic_segment_tree(const i64 n)` 14 | - `[ide; n]`の列を扱うDynamic Segment Treeを構築する 15 | - \\( O(1) \\) 16 | 17 | - `update(i64 i, T x)` 18 | - `i`番目の要素を`x`にする 19 | - \\( O(\log n) \\) 20 | 21 | - `sum(i64 l, i64 r)` 22 | - `[l, r)`の総和を求める 23 | - \\( O(\log n) \\) 24 | 25 | ### Code 26 | 27 | ```cpp 28 | {{#include ../../../src/data_structures/segment_tree/dynamic_segment_tree.hpp}} 29 | ``` 30 | -------------------------------------------------------------------------------- /md/data_structures/segment_tree/index.md: -------------------------------------------------------------------------------- 1 | # Segment Trees 2 | 3 | - [Segment Tree](./segment_tree.md) 4 | 5 | - [Lazy Segment Tree](./lazy_segment_tree.md) 6 | 7 | - [Persistent Segment Tree](./persistent_segment_tree.md) 8 | 9 | - [Dynamic Segment Tree](./dynamic_segment_tree.md) 10 | 11 | - [Li-Chao Segment Tree](./li_chao.md) 12 | -------------------------------------------------------------------------------- /md/data_structures/segment_tree/lazy_segment_tree.md: -------------------------------------------------------------------------------- 1 | # Lazy Segment Tree 2 | ### Spec 3 | 4 | - `using T = ...` 5 | - Segment Treeに載せる型 6 | 7 | - `using L = ...` 8 | - 遅延伝搬させる作用素 9 | 10 | - `T t_ide()` 11 | - Tの単位元を返す 12 | 13 | - `L l_ide()` 14 | - Lの単位元を返す 15 | 16 | - `T ope(const T& a, const T& b)` 17 | - Tの演算を指定する 18 | 19 | - `L lazy_ope(const L& a, const L& b)` 20 | - Tの演算を指定する 21 | 22 | - `T effect(const T& t, const L& l, const i64 len)` 23 | - 長さ`len`の区間の総和`t`に作用`l`をする 24 | 25 | - `lazy_segment_tree(const vector& init)` 26 | - `init`からLazy Segment Treeを構築する 27 | - \\( O(n) \\) 28 | 29 | - `update(i64 a, i64 b, L lx)` 30 | - `[a, b)`番目の要素に作用`lx`をする 31 | - \\( O(\log n) \\) 32 | 33 | - `sum(i64 a, i64 b)` 34 | - `[a, b)`の総和を求める 35 | - \\( O(\log n) \\) 36 | 37 | ### Code 38 | 39 | ```cpp 40 | {{#include ../../../src/data_structures/segment_tree/lazy_segment_tree.hpp}} 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /md/data_structures/segment_tree/li_chao.md: -------------------------------------------------------------------------------- 1 | # Li-Chao Line Add Tree 2 | 3 | ### Spec 4 | 5 | - template argments 6 | - `class T` 7 | - Li-Chao Segment Treeで扱う型 8 | - `+, *, /`, 比較ができる必要がある 9 | - `const T ide` 10 | - Tの単位元(?) 11 | - 例えば, 最大値を返すLiChaoなら小さい数を入れておく 12 | - `class Compare = greater` 13 | - 最大値or最小値 14 | 15 | - `li_chao(T mi, T, ma)` 16 | - `[mi, ma]`の間の範囲を管理するLiChaoを構築する. 17 | 18 | - `void add_line(T a, T b)` 19 | - `a * x + b`の直線を追加する 20 | - \\( O(\log L) \\) 21 | 22 | - `T get(T x)` 23 | - `max{a_i * x + b_i}`を返す(Compareで`min`に変えられる) 24 | - \\( O(\log L) \\) 25 | 26 | ### Code 27 | 28 | ```cpp 29 | {{#include ../../../src/data_structures/segment_tree/li_chao.hpp}} 30 | ``` 31 | -------------------------------------------------------------------------------- /md/data_structures/segment_tree/li_chao_segment.md: -------------------------------------------------------------------------------- 1 | # Li-Chao Segment Add Tree 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/data_structures/segment_tree/li_chao_segment.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/data_structures/segment_tree/persistent_segment_tree.md: -------------------------------------------------------------------------------- 1 | # Persistent Segment Tree 2 | ### Spec 3 | 4 | - `using T = ...` 5 | - Segment Treeに載せる型 6 | 7 | - `T ope(const T& a, const T& b)` 8 | - Tの演算を指定する 9 | 10 | - `T ide()` 11 | - Tの単位元を返す 12 | 13 | - `persistent_segment_tree(vector init)` 14 | - `init`からPersistent Segment Treeを構築する 15 | - \\( O(n) \\) 16 | 17 | - `update(i64 i, T x)` 18 | - `i`番目の要素を`x`にしたSegment Treeを返す. 19 | - \\( O(\log n) \\) 20 | 21 | - `sum(i64 l, i64 r)` 22 | - `[l, r)`の総和を求める 23 | - \\( O(\log n) \\) 24 | 25 | ### Code 26 | 27 | ```cpp 28 | {{#include ../../../src/data_structures/segment_tree/persistent_segment_tree.hpp}} 29 | ``` 30 | -------------------------------------------------------------------------------- /md/data_structures/segment_tree/segment_tree.md: -------------------------------------------------------------------------------- 1 | # Segment Tree 2 | ### Spec 3 | 4 | - `using T = ...` 5 | - Segment Treeに載せる型 6 | 7 | - `segment_tree(vector init)` 8 | - `init`からSegment Treeを構築する 9 | - \\( O(n) \\) 10 | 11 | - `update(i64 i, T x)` 12 | - `i`番目の要素を`x`にする 13 | - \\( O(\log n) \\) 14 | 15 | - `sum(i64 l, i64 r)` 16 | - `[l, r)`の総和を求める 17 | - \\( O(\log n) \\) 18 | 19 | - `find_first(i64 l, F isok)` 20 | - isokを満たす`[l, x)`のsumの中でxが最小のもの 21 | - sumが区間の大きさについて単調である必要がある 22 | - ないなら-1を返す 23 | 24 | ### Code 25 | 26 | ```cpp 27 | {{#include ../../../src/data_structures/segment_tree/segment_tree.hpp}} 28 | ``` 29 | -------------------------------------------------------------------------------- /md/data_structures/sparse_table/sparse_table.md: -------------------------------------------------------------------------------- 1 | # Sparse Table 2 | 3 | ## Spec 4 | 5 | - `ope` 6 | - 束の演算を定義する. 7 | 8 | - `(constructor)` 9 | - Sparse Tableを構築する. \\( O(N \log N) \\) 10 | 11 | - `query(i64 s, i64 t)` 12 | - `[s, t)`に対してクエリを処理する. 13 | 14 | ## Code 15 | 16 | ```cpp 17 | {{#include ../../../src/data_structures/sparse_table/sparse_table.hpp }} 18 | ``` 19 | -------------------------------------------------------------------------------- /md/data_structures/trees/euler_tour_path.md: -------------------------------------------------------------------------------- 1 | # EulerTour Path 2 | 3 | EulerTourのパスを処理するバージョン 4 | パスとして求められるのは, 上から下に降りるようなパスだけなので, 任意のパスを扱うときはLCAをしないといけない. 5 | 扱える要素には, 可逆性, 可換性(?)が必要. 6 | 7 | ### Spec 8 | 9 | - `euler_tour_path(i64 n)` 10 | - `n`頂点の木を構築する準備 11 | 12 | - `add_edge(i64 u, i64 v)` 13 | - 頂点`u`と`v`を結ぶ辺を追加する 14 | 15 | - `start_tour(i64 r)` 16 | - `r`を根としてEulerTourを行う 17 | - \\( O(n) \\) 18 | 19 | - `edge_in(i64 v)` 20 | - 頂点`v`に入る辺のindexを返す 21 | - \\( O(1) \\) 22 | 23 | - `edge_out(i64 v)` 24 | - 頂点`v`に出る辺のindexを返す 25 | - \\( O(1) \\) 26 | 27 | - `path_range(i64 u, i64 v)` 28 | - 頂点`u`から降りて頂点`v`に辿るパスの範囲を返す. 29 | - \\( O(1) \\) 30 | 31 | ### Code 32 | 33 | ```cpp 34 | {{#include ../../../src/data_structures/trees/euler_tour_path.hpp}} 35 | ``` 36 | -------------------------------------------------------------------------------- /md/data_structures/trees/euler_tour_subtree.md: -------------------------------------------------------------------------------- 1 | # EulerTour Subtree 2 | 3 | EulerTourの部分木を処理するバージョン 4 | 木を列に落とし込んだときの部分木の範囲がわかるので, [Segment Tree](../segment_tree/segment_tree.md)と合わせて使うといい. 5 | 6 | LCAをET Subtree + RMQで求める場合はコメントアウトしてある部分を使う. 7 | 8 | ### Spec 9 | 10 | - `eulertour_subtree(i64 n)` 11 | - `n`頂点の木を構築する準備 12 | 13 | - `add_edge(i64 u, i64 v)` 14 | - 頂点`u`と`v`を結ぶ辺を追加する 15 | 16 | - `start_tour(i64 r)` 17 | - `r`を根としてEulerTourを行う 18 | - \\( O(n) \\) 19 | 20 | - `subtree_range(i64 v)` 21 | - 頂点`v`の部分木に対応する範囲を返す 22 | - \\( O(1) \\) 23 | 24 | - `vertex(i64 v)` 25 | - 頂点`v`に対応するindexを返す. 26 | - \\( O(1) \\) 27 | 28 | ### Code 29 | 30 | ```cpp 31 | {{#include ../../../src/data_structures/trees/euler_tour_subtree.hpp}} 32 | ``` 33 | -------------------------------------------------------------------------------- /md/data_structures/trees/heavy_light_decomposition.md: -------------------------------------------------------------------------------- 1 | # Heavy Light Decomposition 2 | 3 | 静的木 4 | 5 | 木のパスや部分木のクエリを処理できる. 6 | 7 | ### Spec 8 | 9 | - `HeavyLightDecomposition(i64 n)` 10 | - 頂点数`n`で初期化 11 | 12 | - `add_edge(i64 u, i64 v)` 13 | - 頂点`u`と`v`をつなぐ 14 | 15 | - `build(i64 r)` 16 | - `r`を根としてHLDecompを行う 17 | 18 | - `sequence()` 19 | - HLDecompしたときのオイラーツアーの配列. 20 | 21 | - `path(i64 a, i64 b, bool edge)` 22 | - パスの列を返す. 23 | - `edge = true`で辺に対するパスを返す. 24 | - \\( O(\log n) \\) 25 | 26 | - `subtree(i64 v, bool edge)` 27 | - 部分木の列を返す. 28 | - `edge = true`で辺に対するパスを返す. 29 | - \\( O(1) \\) 30 | 31 | ### Code 32 | 33 | ```cpp 34 | {{#include ../../../src/data_structures/trees/heavy_light_decomposition.hpp}} 35 | ``` 36 | -------------------------------------------------------------------------------- /md/data_structures/trees/index.md: -------------------------------------------------------------------------------- 1 | # Trees 2 | 3 | 木を処理するやつ 4 | 5 | - [EulerTour Subtree](./euler_tour_subtree.md) 6 | - [EulerTour Path](./euler_tour_path.md) 7 | - [Heavy Light Decomposition](./heavy_light_decomposition.md) 8 | - [Link Cut Tree](./link_cut_tree.md) 9 | - [Top Tree](./toptree.md) 10 | -------------------------------------------------------------------------------- /md/data_structures/trees/link_cut_tree.md: -------------------------------------------------------------------------------- 1 | # Link Cut Tree 2 | 3 | 動的木 4 | 5 | パスのsumを計算したり, パスに対する作用を遅延伝搬できる. 6 | 7 | ### Spec 8 | 9 | - `struct node` 10 | - link cut treeで扱うノードの構造体 11 | - この中に載せたいデータを載せる 12 | 13 | - `fix(node * n)` 14 | - ノードの情報の再計算をする 15 | 16 | - `reverse(node * n)` 17 | - 平衡二分木の反転 18 | - モノイドの演算順序が反転するのでその処理を書く 19 | - モノイドが可換であれば問題ない 20 | 21 | - `lazy(node * n, i64 l)` 22 | - 遅延伝搬するときの演算 23 | - `expose(n); lazy(n, x)`をすると, `[root, n]`のパスに`x`を作用させることになる 24 | 25 | - `push(node* n)` 26 | - 遅延伝搬 27 | - lazyを変えている場合はここも変更 28 | 29 | - `expose(node* n)` 30 | - `n`をLink Cut Treeの根として, その木が`[root, n]`のパスをあらわすようになる 31 | 32 | - `link(node* p, node* c)` 33 | - `p`を親, `c`を子として繋げる 34 | 35 | - `cut(node* c)` 36 | - `c`の親とつながっている辺を切る 37 | 38 | - `evert(node* t)` 39 | - `t`を親にする 40 | 41 | ### Code 42 | 43 | パス加算, パスsumを処理している 44 | 45 | ```cpp 46 | {{#include ../../../src/data_structures/trees/link_cut_tree.hpp}} 47 | ``` 48 | -------------------------------------------------------------------------------- /md/data_structures/trees/toptree.md: -------------------------------------------------------------------------------- 1 | # Top Tree 2 | 3 | なにこれ 4 | 5 | ### Spec 6 | 7 | え 8 | 9 | ### Code 10 | 11 | ```cpp 12 | {{#include ../../../src/data_structures/trees/toptree.hpp}} 13 | ``` 14 | -------------------------------------------------------------------------------- /md/data_structures/union_find/index.md: -------------------------------------------------------------------------------- 1 | # Union Find 2 | 3 | - [Union Find](./data_structures/union_find/union_find.md) 4 | - [Persistent Union Find](./data_structures/union_find/persistent_union_find.md) -------------------------------------------------------------------------------- /md/data_structures/union_find/persistent_union_find.md: -------------------------------------------------------------------------------- 1 | # Partially Persistent Union Find 2 | 3 | ## Spec 4 | 5 | - 時刻`t`は単調増加である必要がある. 6 | 7 | - `(constructor)` 8 | - `n`要素のPartially Persistent Union Findを構築する. 9 | 10 | - `unite(i64 t, i64 x, i64 y)` 11 | - 2要素を時刻`t`で結ぶ. 12 | - 戻り値は親となった根 13 | 14 | - `find(i64 t, i64 x)` 15 | - 時刻`t`のときの要素`x`の根を返す. 16 | 17 | - `size(i64 t, i64 x)` 18 | - 時刻`t`のときの要素`x`の属する集合の大きさを返す. 19 | 20 | ## Code 21 | 22 | ```cpp 23 | {{#include ../../../src/data_structures/union_find/persistent_union_find.hpp }} 24 | ``` 25 | -------------------------------------------------------------------------------- /md/data_structures/union_find/union_find.md: -------------------------------------------------------------------------------- 1 | # Union Find 2 | 3 | ## Spec 4 | 5 | - `(constructor)` 6 | - `n`要素のUnion Findを構築する. 7 | 8 | - `root` 9 | - 要素の根を返す. 10 | 11 | - `unite` 12 | - 2要素を結ぶ. 13 | - 戻り値は親となった根 14 | 15 | 16 | ## Code 17 | 18 | ```cpp 19 | {{#include ../../../src/data_structures/union_find/union_find.hpp }} 20 | ``` 21 | -------------------------------------------------------------------------------- /md/data_structures/wavelet_matrix/dynamic_wavelet_matrix.md: -------------------------------------------------------------------------------- 1 | # Dynamic Wavelet Matrix 2 | 3 | ## Spec 4 | 5 | ## Code 6 | 7 | ```cpp 8 | {{#include ../../../src/data_structures/wavelet_matrix/dynamic_wavelet_matrix.hpp }} 9 | ``` 10 | -------------------------------------------------------------------------------- /md/data_structures/wavelet_matrix/index.md: -------------------------------------------------------------------------------- 1 | # Wavelet Matrix 2 | -------------------------------------------------------------------------------- /md/data_structures/wavelet_matrix/wavelet_matrix.md: -------------------------------------------------------------------------------- 1 | # Wavelet Matrix 2 | 3 | ## Spec 4 | 5 | ## Code 6 | 7 | ```cpp 8 | {{#include ../../../src/data_structures/wavelet_matrix/wavelet_matrix.hpp }} 9 | ``` 10 | -------------------------------------------------------------------------------- /md/geometry/geometry.md: -------------------------------------------------------------------------------- 1 | # Geometry 2 | 3 | 昔作ったやつが残っていたのでとりあえず貼っておく 要整備 4 | 5 | ### Spec 6 | 7 | - `Convex_Hull` 8 | - 凸包 9 | 10 | ### Code 11 | 12 | ```cpp 13 | {{#include ../../src/geometry/geometry.hpp}} 14 | ``` 15 | -------------------------------------------------------------------------------- /md/graph/centroid_decomposition.md: -------------------------------------------------------------------------------- 1 | # Centroid Decomposition 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../src/graph/centroid_decomposition.hpp }} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/graph/gabow_e_algorithm.md: -------------------------------------------------------------------------------- 1 | # Gabow E Algorithm 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../src/graph/gabow_e_algorithm.hpp }} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/graph/incremental_bridge_connectivity.md: -------------------------------------------------------------------------------- 1 | # Incremental Bridge Connectivity 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../src/graph/incremental_bridge_connectivity.hpp }} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/graph/index.md: -------------------------------------------------------------------------------- 1 | # Graph 2 | 3 | - [Strongly Connected Components](./strongly_connected_components.md) \\ 4 | -------------------------------------------------------------------------------- /md/graph/lattice_graph.md: -------------------------------------------------------------------------------- 1 | # Lattice Graph 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../src/graph/lattice_graph.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/graph/max_flow/dinic.md: -------------------------------------------------------------------------------- 1 | # Dinic 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../../src/graph/max_flow/dinic.hpp }} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/graph/max_flow/goldberg_tarjan_tuned.md: -------------------------------------------------------------------------------- 1 | # GoldBerg Tarjan's Preflow Relabel 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/graph/max_flow/goldberg_tarjan_tuned.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/graph/mcf/primal_dual.md: -------------------------------------------------------------------------------- 1 | # Successive Shortest Path 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../../src/graph/mcf/primal_dual.hpp }} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/graph/sp/bfs.md: -------------------------------------------------------------------------------- 1 | # BFS 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/graph/sp/bfs.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/graph/sp/dial01.md: -------------------------------------------------------------------------------- 1 | # Dial 01 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/graph/sp/dial01.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/graph/sp/dijkstra.md: -------------------------------------------------------------------------------- 1 | # Dijkstra 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/graph/sp/dijkstra.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/graph/strongly_connected_components.md: -------------------------------------------------------------------------------- 1 | # Strongly Connected Components 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../src/graph/strongly_connected_components.hpp }} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | ここに競技プログラミング用のC++のライブラリをおいていきたい 4 | 5 | - Google Analyticsを使用しています 6 | -------------------------------------------------------------------------------- /md/math/adjucency_matrix_equation.md: -------------------------------------------------------------------------------- 1 | # Adjucency Matrix Equation 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../src/math/adjucency_matrix_equation.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/math/berlekamp_massey.md: -------------------------------------------------------------------------------- 1 | # Berlekamp-Massey 2 | 3 | 線形漸化式\\( a_i = c_0 * a_(i - 1) + c_1 * a_(i - 2) + ... \\)があって、数列\\(a\\)がわかっているときに、漸化式の係数\\(c\\)を\\(O(n^2)\\)で求める. 4 | 5 | ### Code 6 | 7 | ```cpp 8 | {{#include ../../src/math/berlekamp_massey.hpp}} 9 | ``` 10 | -------------------------------------------------------------------------------- /md/math/binfps.md: -------------------------------------------------------------------------------- 1 | # F2[[x]] 2 | 3 | ### Spec 4 | 5 | gcdとか, modとかができます. 6 | 7 | ### Code 8 | 9 | ```cpp 10 | {{#include ../../src/math/binfps.hpp}} 11 | ``` 12 | -------------------------------------------------------------------------------- /md/math/black_box_linear_algebra.md: -------------------------------------------------------------------------------- 1 | # Black Box Linear Algebra 2 | 3 | 4 | ベクトルと行列の掛け算に\\(T(n)\\)時間かかるとします. 5 | 6 | ### 最小多項式 7 | 8 | \\(O(n^2 + n T(n))\\) 9 | 10 | ```cpp 11 | {{#include ../../src/math/black_box_linear_algebra/minimal_polynomial.hpp}} 12 | ``` 13 | 14 | ### 行列式 15 | 16 | \\(O(n^2 + n T(n))\\) 17 | 18 | ```cpp 19 | {{#include ../../src/math/black_box_linear_algebra/fast_determinant.hpp}} 20 | ``` 21 | 22 | ### 行列累乗 23 | 24 | \\(A^k b\\)を求める. `fast_kitamasa`を用いて\\(O(N^3 + N \log N \log k)\\) 25 | 26 | ```cpp 27 | {{#include ../../src/math/black_box_linear_algebra/fast_matrix_pow.hpp}} 28 | ``` 29 | -------------------------------------------------------------------------------- /md/math/comvolution/zeta_mobius_transform.md: -------------------------------------------------------------------------------- 1 | # Zeta Mobius Transform 2 | -------------------------------------------------------------------------------- /md/math/convolution/divisor_transform.md: -------------------------------------------------------------------------------- 1 | # Divisor Transform 2 | 3 | 約数幇助と呼ばれる. [参考 - 高速ゼータ変換の約数版](http://noshi91.hatenablog.com/entry/2018/12/27/121649) 4 | 5 | ### Spec 6 | 7 | `i`について, `i`の約数である`j`(下位集合)について`a[j]`の総和を求める. \\( O(N \log{\log N}) \\). 8 | `inverse divisor transform`と共に使うと`lcm`に関する畳み込みができる. こんな感じ 9 | 10 | \\[ h(z) = \sum_{ \operatorname{lcm} (x, y) = z } { f(x) * g(y) } \\] 11 | 12 | 13 | ### Code 14 | 15 | ```cpp 16 | {{#include ../../../src/math/convolution/divisor_transform.hpp}} 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /md/math/convolution/fast_fourier_transform.md: -------------------------------------------------------------------------------- 1 | # Fast Fourier Transform 2 | 3 | ### Spec 4 | 5 | 離散フーリエ変換(discrete Fourier transformation)を\\( O(n \log n) \\)で行う. 6 | 7 | 誤差厳しい, 整数ならNTT使おう(誤差をなくすようにFFTするのもあるらしい) 8 | 9 | ### Code 10 | 11 | ```cpp 12 | {{#include ../../../src/math/convolution/fast_fourier_transform.hpp}} 13 | ``` 14 | -------------------------------------------------------------------------------- /md/math/convolution/index.md: -------------------------------------------------------------------------------- 1 | # Convolution 2 | 3 | 畳み込み [参考 - 約数集合でのゼータ変換・メビウス変換的なやつと畳み込み](http://kazuma8128.hatenablog.com/entry/2018/07/29/231819) 4 | 5 | ## 集合の畳み込みについて 6 | 7 | \\(A \subseteq B\\) のとき, \\( B \\)は\\( A \\)の上位集合という. また\\( A \\)は\\( B \\)の下位集合という. 8 | 9 | 上位集合について和を求める変換して互いをかけ合わせて逆変換をすると, 積集合(And)の個数が求められる. 10 | 下位集合について和を求める変換して互いをかけ合わせて逆変換をすると, 和集合(Or)の個数が求められる. 11 | 12 | 例) `multiple_transform`(`i`について, `i`を約数に持つ`j`の`a[j]`の総和を求める --> 上位集合)をして互いをかけ合わせて逆変換すると, 積集合(`gcd`についての畳み込み)がの個数が求められる. 13 | 14 | ## Transforms 15 | 16 | - [Multiple Transform](./multiple_transform.md) 17 | - [Divisor Transform](./divisor_transform.md) 18 | - [Fast Fourier Transform](./fast_fourier_transform.md) 19 | - [Number Theoretic Transform](./numeric_theoretic_transform.md) 20 | -------------------------------------------------------------------------------- /md/math/convolution/multiple_transform.md: -------------------------------------------------------------------------------- 1 | # Multiple Transform 2 | 3 | 約数幇助と呼ばれる. [参考 - 高速ゼータ変換の約数版](http://noshi91.hatenablog.com/entry/2018/12/27/121649) 4 | 5 | ### Spec 6 | 7 | `i`について, `i`を約数に持つ`j`(上位集合)の`a[j]`の総和を求める. \\( O(N \log{\log N}) \\). 8 | `inverse multiple transform`と共に使うと`gcd`に関する畳み込みができる. こんな感じ 9 | 10 | \\[ h(z) = \sum_{\gcd(x, y) = z} {f(x) * g(y)} \\] 11 | 12 | 13 | ### Code 14 | 15 | ```cpp 16 | {{#include ../../../src/math/convolution/multiple_transform.hpp}} 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /md/math/convolution/numeric_theoretic_transform.md: -------------------------------------------------------------------------------- 1 | # Numeric Theoretic Transform 2 | 3 | ### Spec 4 | 5 | 素数\\( m = 2^k + 1, 2^k >= n\\)として\\(F_m \\)剰余環上での離散フーリエ変換(discrete Fourier transformation)を\\( O(n \log n) \\)で行う 6 | `NTT_PRIMES`は[るまライブラリ](https://lumakernel.github.io/ecasdqina/math/FFT/NTT)からお借りしています 7 | 8 | ほとんど単体でNTTを使うことはなさそう(FPSで使うね) 9 | 10 | ### Code 11 | 12 | ```cpp 13 | {{#include ../../../src/math/convolution/number_theoretic_transform.hpp}} 14 | ``` 15 | 16 | ### 4基底NTT 17 | 18 | ```cpp 19 | {{#include ../../../src/math/convolution/ntt4.hpp}} 20 | ``` 21 | -------------------------------------------------------------------------------- /md/math/convolution/zeta_mobius_transform.md: -------------------------------------------------------------------------------- 1 | # Zeta Mobius Transfrom 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../../src/math/convolution/zeta_mobius_transform.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/math/crt.md: -------------------------------------------------------------------------------- 1 | # Chinese Remainder Theorem 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../src/math/chinese_remainder_theorem.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/math/factorial.md: -------------------------------------------------------------------------------- 1 | # factorial 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../src/math/factorial.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/math/fast_kitamasa.md: -------------------------------------------------------------------------------- 1 | # Fast Kitamasa 2 | 3 | 線形漸化式\\(a_i = c_1 * a_{i - 1} + \cdots + c_d * a_{i - d}\\)があるとき、\\(c_0 = -1\\)として`fast_kitamasa`にかけると、 4 | \\(a_n = b_0 * a_{d - 1} + \cdots + b_{d - 1} * a_0\\)となる\\(b\\)を\\(O(d \log d \log n)\\)で求める 5 | 6 | ```cpp 7 | {{#include ../../src/math/fast_kitamasa.hpp}} 8 | ``` 9 | -------------------------------------------------------------------------------- /md/math/formal_power_series.md: -------------------------------------------------------------------------------- 1 | # Formal Power Series 2 | 3 | ### FPS 4 | 5 | FPS 6 | - `resize`: リサイズ 7 | - `resized`: リサイズしたFPSを返す 8 | - `+=, -=, +, -`: 加減法、次数の大きい方にリサイズされる。 9 | - `*, *=`: 定数倍 10 | - `DFT dft(int n)`: 長さ`n`にリサイズして`dft` 11 | - `inv(int n)`: \\(f * g \equiv 1 \pmod{x^n}\\)となるような\\(g\\)を返す 12 | - `diff(int n)`: \\(f' \bmod{x^n}\\) 13 | - `integral(int n)`: \\(\int f dx \bmod{x^n}\\) 14 | - `log(int n)`: \\(\log f \bmod{x^n}\\) 15 | - `exp(int n)`: \\(\exp f \bmod{x^n}\\) 16 | 17 | DFT 18 | - `+=, -=, +, -`: 加減法 線形性より 19 | - `*, *=`: 定数倍 線形性より 20 | - `*`: 畳み込み 21 | - `idft(int n = -1)`: `idft`した後に長さ`n`でリサイズ 指定しなければそのまま 22 | 23 | ```cpp 24 | {{#include ../../src/math/formal_power_series.hpp}} 25 | ``` 26 | 27 | ### NTTをそのまま使うとき 28 | 29 | ```cpp 30 | {{#include ../../src/math/fps_ntt_multiply.hpp}} 31 | ``` 32 | 33 | ### 任意modで 34 | 35 | ```cpp 36 | {{#include ../../src/math/fps_multiply_arb.hpp}} 37 | ``` 38 | -------------------------------------------------------------------------------- /md/math/garner.md: -------------------------------------------------------------------------------- 1 | # Garner's Algorithm 2 | 3 | FPSで使う 4 | 5 | ### Spec 6 | 7 | \\(m_0, \cdots, m_{k-1} \\)が互いに素とする. 8 | \\( x < \prod{m_i} \\)を満たす\\( x \\)について, \\( x \mod m_i \\)がわかっている時, 9 | \\( O(k^2 + k \log m) \\)で \\( x \mod M \\) を求めることができる. 10 | 11 | ### Code 12 | 13 | ```cpp 14 | {{#include ../../src/math/garner.hpp}} 15 | ``` 16 | -------------------------------------------------------------------------------- /md/math/index.md: -------------------------------------------------------------------------------- 1 | # Math 2 | 3 | 数学系を 4 | 5 | - [modint](./modint.md) 6 | - [Matrix](./matrix.md) \\ 7 | - [Garner's Algorithm](./garner.md) 8 | - [Polynomial](./polynomial.md) \\ 9 | - [Runtime fp](./runtime_fp.md) \\ 10 | -------------------------------------------------------------------------------- /md/math/matrix.md: -------------------------------------------------------------------------------- 1 | # Matrix 2 | 3 | 行列演算 4 | 5 | ### Code 6 | 7 | ```cpp 8 | {{#include ../../src/math/matrix.hpp}} 9 | ``` 10 | -------------------------------------------------------------------------------- /md/math/modint.md: -------------------------------------------------------------------------------- 1 | # modint 2 | 3 | xxで割ったあまりを求めよで使える構造体 4 | 5 | ### Spec 6 | 7 | - template 8 | - `i64 M` 9 | - \\( \mod M \\)の剰余環 10 | 11 | - `modint(const i64 x = 0)` 12 | - \\( x \mod M \\)で初期化 13 | 14 | - `value()` 15 | - \\( x \mod M \\)を返す 16 | 17 | - `pow(i64 r)` 18 | - \\( x^r \mod M \\)を返す 19 | 20 | - `+, -, *, /` 21 | 22 | 23 | ### Code 24 | 25 | ```cpp 26 | {{#include ../../src/math/modint.hpp}} 27 | ``` 28 | -------------------------------------------------------------------------------- /md/math/montgomery_modint.md: -------------------------------------------------------------------------------- 1 | # montgomery modint 2 | 3 | 乗算がはやーいmodint 4 | 5 | ### Code 6 | 7 | ```cpp 8 | {{#include ../../src/math/montgomery_modint.hpp}} 9 | ``` 10 | -------------------------------------------------------------------------------- /md/math/mori_fps_division.md: -------------------------------------------------------------------------------- 1 | # Mori FPS Division 2 | 3 | 4 | # FPS Division 5 | 6 | - \\( P(x) / Q(x) \\) の \\( [x^N] \\)の係数を求める 7 | - 時間計算量は \\( O( k \log k \log N) \\) 8 | - \\( P(x) \\)は高々\\( k - 1 \\)次の多項式 9 | - \\( Q(x) \\)は\\( k \\)次の多項式 10 | 11 | 12 | ### Code 13 | 14 | 15 | 16 | ```cpp 17 | {{#include ../../src/math/mori_fps_division.hpp}} 18 | ``` 19 | -------------------------------------------------------------------------------- /md/math/newton_interpolation.md: -------------------------------------------------------------------------------- 1 | # modint 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../src/math/newton_interpolation.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/math/osa_k.md: -------------------------------------------------------------------------------- 1 | # osa\_k 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../src/math/osa_k.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/math/runtime_fp.md: -------------------------------------------------------------------------------- 1 | # Runtime fp 2 | 3 | ### Code 4 | 5 | ```cpp 6 | {{#include ../../src/math/runtime_fp.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/math/seidels_lp.md: -------------------------------------------------------------------------------- 1 | # Seidel's LP 2 | 3 | 4 | # Seidel's LP algorithm 5 | - LPを解くアルゴリズム 6 | - LP(線形計画問題)とは, 以下のように記述できる. 7 | 8 | \\[ 9 | \begin{align} 10 | \text{maximize} \ & c^T x \\\\ 11 | \text{subject to} \ & A x \leq b \\\\ 12 | \ & x \geq 0 13 | \end{align} 14 | \\] 15 | 16 | - この \\( x \\) を返す. 17 | - 計算量 \\( O(d! m) ( d \text{は次元数}, m \text{は条件数}) \\) 18 | 19 | ## Arguments 20 | 21 | `mat`は, \\( (A \ b) \\)である. 22 | 23 | `bounds`には, \\( x \\)のとる下界と上界を与える. 24 | 25 | ## Memo 26 | 27 | `eps`を変える必要があるかもしれない. 28 | 29 | 30 | ### Code 31 | 32 | ```cpp 33 | {{#include ../../src/math/seidels_lp.hpp}} 34 | ``` 35 | -------------------------------------------------------------------------------- /md/string/2_31rolling_hash.md: -------------------------------------------------------------------------------- 1 | # 2^31 Rolling Hash 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../src/string/2_61-1_rolling_hash.hpp }} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/string/Z-algorithm.md: -------------------------------------------------------------------------------- 1 | # Z-algorithm 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../src/string/z-algorithm.hpp }} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/string/burrows_wheeler.md: -------------------------------------------------------------------------------- 1 | # Burrows Wheeler 2 | ```cpp 3 | {{#include ../../src/string/burrows_wheeler.hpp }} 4 | ``` 5 | -------------------------------------------------------------------------------- /md/string/burrows_wheller.md: -------------------------------------------------------------------------------- 1 | # Burrows Wheeler 2 | ## Spec 3 | ## Code 4 | 5 | -------------------------------------------------------------------------------- /md/string/index.md: -------------------------------------------------------------------------------- 1 | # String 2 | 3 | [文字列の頭良い感じの線形アルゴリズムたち](https://snuke.hatenablog.com/entry/2014/12/01/235807) 4 | 5 | - [Manacher](./manacher.md) \\ 6 | - [MP (Morris Pratt)](./mp.md) 7 | - [Rolling Hash](./rolling_hash.md) \\ 8 | - [Suffix Array](./suffix_array.md) \\ 9 | - [Z-algorithm](./Z-algorithm.md) \\ 10 | -------------------------------------------------------------------------------- /md/string/manacher.md: -------------------------------------------------------------------------------- 1 | # Manacher 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../src/string/manacher.hpp }} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/string/mp.md: -------------------------------------------------------------------------------- 1 | # MP (Morris Pratt) 2 | 3 | [文字列の頭良い感じの線形アルゴリズムたち](https://snuke.hatenablog.com/entry/2014/12/01/235807) 4 | 5 | ### Spec 6 | 7 | 文字列S[0, i-1]のprefixとsuffixが最大何文字一致しているかを \\( O(|S|) \\)で求める. 8 | 9 | 10 | #### Example 11 | ``` 12 | aabaabaaa 13 | _010123452 14 | ``` 15 | 16 | ### Code 17 | 18 | ```cpp 19 | {{#include ../../src/string/mp.hpp}} 20 | ``` 21 | -------------------------------------------------------------------------------- /md/string/rolling_hash.md: -------------------------------------------------------------------------------- 1 | # Rolling Hash 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../src/string/rolling_hash.hpp }} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/string/suffix_array.md: -------------------------------------------------------------------------------- 1 | # Suffix Array 2 | 3 | ## Code 4 | 5 | ```cpp 6 | {{#include ../../src/string/suffix_array.hpp }} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/tech/compression.md: -------------------------------------------------------------------------------- 1 | # Compression 2 | 3 | 座標圧縮をする. 4 | 5 | ### Spec 6 | 7 | - `add(T x)` 8 | - 要素`x`を追加する 9 | 10 | - `build()` 11 | - 準備 12 | 13 | - `comp(T x)` 14 | - 座圧した結果を返す 15 | 16 | - `comp(vector x)` 17 | - まとめて座圧 18 | - `x = comp(std::move(x))`すると楽です. 19 | 20 | ### Code 21 | 22 | 23 | ```cpp 24 | {{#include ../../src/tech/compression.hpp}} 25 | ``` 26 | -------------------------------------------------------------------------------- /md/tech/fastio.md: -------------------------------------------------------------------------------- 1 | # FastIO 2 | ### Spec 3 | 4 | ### Code 5 | ```cpp 6 | {{#include ../../src/other/fastio.hpp}} 7 | ``` 8 | -------------------------------------------------------------------------------- /md/tech/grundy.md: -------------------------------------------------------------------------------- 1 | # Grundy Number 2 | 3 | ### Spec 4 | 5 | - `grn[(ゲームの状態)]`が`0` -> その状態での手番の人が負ける 6 | - `grn[(ゲームの状態)]`が`0`以外 -> その状態での手番の人が勝つ 7 | 8 | ### Code 9 | 10 | このコードでは, 取れる個数に制限がついているNimの勝敗を計算している. 11 | 12 | ```cpp 13 | {{#include ../../src/other/grundy.hpp}} 14 | ``` 15 | -------------------------------------------------------------------------------- /md/tech/index.md: -------------------------------------------------------------------------------- 1 | # Tech 2 | 3 | テクニック, 分類できなかったもの 4 | -------------------------------------------------------------------------------- /md/tech/mo.md: -------------------------------------------------------------------------------- 1 | # Mo's Algorithm 2 | 3 | もーもー 4 | 5 | ### Code 6 | 7 | ```cpp 8 | {{#include ../../src/tech/mo.hpp}} 9 | ``` 10 | -------------------------------------------------------------------------------- /md/tech/mongeDP.md: -------------------------------------------------------------------------------- 1 | # Monge DP 2 | -------------------------------------------------------------------------------- /md/tech/rerooting.md: -------------------------------------------------------------------------------- 1 | # Rerooting 2 | 3 | - `T` ... 答え 4 | - `E` ... 辺の型 5 | - `U` ... 辺から伸ばしたときの値, 可換モノイド 6 | - `To` ... `E -> V` 頂点番号の取得 7 | - `Adj` ... `T x E -> U` 辺から伸ばす 8 | - `Ope` ... `U x U -> U` モノイドの値 9 | - `Merge` ... `U x V -> T` モノイドと頂点から答えを導く 10 | 11 | ### Code 12 | 13 | ```cpp 14 | {{#include ../../src/tech/rerooting.hpp}} 15 | ``` 16 | -------------------------------------------------------------------------------- /md/tech/slide_min.md: -------------------------------------------------------------------------------- 1 | # Slide Min 2 | -------------------------------------------------------------------------------- /md/tech/y_combinator.md: -------------------------------------------------------------------------------- 1 | # Y Combinator 2 | ### Code 3 | ```cpp 4 | {{#include ../../src/other/y_combinator.hpp}} 5 | ``` 6 | -------------------------------------------------------------------------------- /src/data_structures/bbst/splay_tree_array.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | struct splay_array { 6 | using T = i64; 7 | 8 | struct node { 9 | node* ch[2]; 10 | node* par; 11 | T val; 12 | i64 sz; 13 | bool rev; 14 | 15 | /* option */ 16 | T fold; 17 | 18 | node(T v): val(v), par(nullptr), sz(1), rev(false), fold(v) { ch[0] = nullptr; ch[1] = nullptr; } 19 | }; 20 | 21 | private: 22 | 23 | i64 subsize(node* x) { 24 | if(x) return x->sz; 25 | else return 0; 26 | } 27 | T fold(node* x) { 28 | if(x) return x->fold; 29 | else return 0; 30 | } 31 | node* fix(node* n) { 32 | if(!n) return nullptr; 33 | n->sz = subsize(n->ch[0]) + subsize(n->ch[1]) + 1; 34 | /* option */ 35 | n->fold = fold(n->ch[0]) + n->val + fold(n->ch[1]); 36 | return n; 37 | } 38 | void reverse(node* n) { 39 | if(!n) return; 40 | n->rev ^= true; 41 | /* here reversing operation */ 42 | /* example swap(fold, revfold) */ 43 | } 44 | void push(node* x) { 45 | if(!x) return; 46 | if(x->rev) { 47 | swap(x->ch[0], x->ch[1]); 48 | reverse(x->ch[0]); 49 | reverse(x->ch[1]); 50 | } 51 | } 52 | int parent_dir(node* x) { 53 | node* p = x->par; 54 | if(!p) return -1; 55 | else if(p->ch[0] == x) return 0; 56 | else return 1; 57 | } 58 | void set(node* par, node* x, i64 dir) { 59 | if(par) par->ch[dir] = x; 60 | if(x) x->par = par; 61 | fix(par); 62 | } 63 | void rotate(node* x, i64 dir) { 64 | node* p = x->par; 65 | node* q = p->par; 66 | set(p, x->ch[dir], dir ^ 1); 67 | int p_dir = parent_dir(p); 68 | if(p_dir >= 0) { 69 | set(q, x, p_dir); 70 | } 71 | else x->par = nullptr; 72 | set(x, p, dir); 73 | } 74 | node* splay(node * x) { 75 | if(!x) return nullptr; 76 | while(x->par) { 77 | push(x->par->par); 78 | push(x->par); 79 | push(x); 80 | int dir = parent_dir(x); 81 | int eir = parent_dir(x->par); 82 | if(eir == -1) { 83 | rotate(x, dir ^ 1); 84 | } 85 | else if(dir == eir){ 86 | rotate(x->par, eir ^ 1); 87 | rotate(x, dir ^ 1); 88 | } 89 | else { 90 | rotate(x, dir ^ 1); 91 | rotate(x, eir ^ 1); 92 | } 93 | } 94 | return x; 95 | } 96 | 97 | node* find(node* r, i64 i) { 98 | push(r); 99 | assert(0 <= i); 100 | assert(i < subsize(r)); 101 | node* z = r; 102 | while(z) { 103 | push(z); 104 | if(subsize(z->ch[0]) == i) return splay(z); 105 | else if(subsize(z->ch[0]) < i) { 106 | i -= subsize(z->ch[0]) + 1; 107 | z = z->ch[1]; 108 | } 109 | else { 110 | z = z->ch[0]; 111 | } 112 | } 113 | assert(false); 114 | } 115 | 116 | pair split(node* r, size_t i) { 117 | push(r); 118 | assert(0 <= i); 119 | assert(i <= subsize(r)); 120 | if(i == 0) return { nullptr, r }; 121 | if(i == subsize(r)) return { r, nullptr }; 122 | r = find(r, i - 1); 123 | node* y = r->ch[1]; 124 | if(y) y->par = nullptr; 125 | r->ch[1] = nullptr; 126 | fix(r); 127 | push(y); 128 | return { r, y }; 129 | } 130 | 131 | node* merge(node* r1, node* r2) { 132 | push(r1); 133 | push(r2); 134 | if(!r1) r1 = r2; 135 | else if(!r2) {} 136 | else { 137 | r1 = find(r1, subsize(r1) - 1); 138 | set(r1, r2, 1); 139 | } 140 | return r1; 141 | } 142 | 143 | node* root; 144 | 145 | splay_array(node* r): root(r) {} 146 | 147 | public: 148 | 149 | using sarr = splay_array; 150 | 151 | splay_array(): root(nullptr) {} 152 | splay_array(T t): root(new node(t)) {} 153 | splay_array(splay_array&& arr): root(arr.root) { arr.root = nullptr; } 154 | splay_array& operator=(splay_array&& arr) { 155 | root = arr.root; 156 | arr.root = nullptr; 157 | return *this; 158 | } 159 | /* [0 ... i - 1] +/+ [i ...] */ 160 | pair split(i64 i) { 161 | auto p = split(root, i); 162 | root = nullptr; 163 | return { splay_array(p.first), splay_array(p.second) }; 164 | } 165 | /* [this] ++ [arr] */ 166 | void merge(splay_array&& arr) { 167 | root = merge(root, arr.root); 168 | arr.root = nullptr; 169 | } 170 | /* reverse array */ 171 | void reverse() { if(root) reverse(root); } 172 | i64 size() { return subsize(root); } 173 | 174 | /* option */ 175 | T fold() { return fold(root); } 176 | void update(i64 i, T t) { 177 | root = find(root, i); 178 | root->val += t; 179 | fix(root); 180 | } 181 | }; 182 | -------------------------------------------------------------------------------- /src/data_structures/bbst/splay_tree_map.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | struct splay_map { 6 | using T = i64; 7 | using Key = i64; 8 | 9 | struct node { 10 | node* ch[2]; 11 | node* par; 12 | T val; 13 | Key key; 14 | i64 sz; 15 | bool rev; 16 | 17 | /* option */ 18 | //T fold; 19 | 20 | node(Key key, T v): key(key), val(v), par(nullptr), sz(1), rev(false)/*, fold(v)*/ { ch[0] = nullptr; ch[1] = nullptr; } 21 | }; 22 | 23 | private: 24 | 25 | i64 subsize(node* x) { 26 | if(x) return x->sz; 27 | else return 0; 28 | } 29 | /* 30 | T fold(node* x) { 31 | if(x) return x->fold; 32 | else return 0; 33 | } 34 | */ 35 | node* fix(node* n) { 36 | if(!n) return nullptr; 37 | n->sz = subsize(n->ch[0]) + subsize(n->ch[1]) + 1; 38 | /* option */ 39 | //n->fold = fold(n->ch[0]) + n->val + fold(n->ch[1]); 40 | return n; 41 | } 42 | void reverse(node* n) { 43 | if(!n) return; 44 | n->rev ^= true; 45 | /* here reversing operation */ 46 | /* example swap(fold, revfold) */ 47 | } 48 | void push(node* x) { 49 | if(!x) return; 50 | if(x->rev) { 51 | swap(x->ch[0], x->ch[1]); 52 | reverse(x->ch[0]); 53 | reverse(x->ch[1]); 54 | } 55 | } 56 | int parent_dir(node* x) { 57 | node* p = x->par; 58 | if(!p) return -1; 59 | else if(p->ch[0] == x) return 0; 60 | else return 1; 61 | } 62 | void set(node* par, node* x, i64 dir) { 63 | if(par) par->ch[dir] = x; 64 | if(x) x->par = par; 65 | fix(par); 66 | } 67 | void rotate(node* x, i64 dir) { 68 | node* p = x->par; 69 | node* q = p->par; 70 | set(p, x->ch[dir], dir ^ 1); 71 | int p_dir = parent_dir(p); 72 | if(p_dir >= 0) { 73 | set(q, x, p_dir); 74 | } 75 | else x->par = nullptr; 76 | set(x, p, dir); 77 | } 78 | node* splay(node * x) { 79 | if(!x) return nullptr; 80 | while(x->par) { 81 | push(x->par->par); 82 | push(x->par); 83 | push(x); 84 | int dir = parent_dir(x); 85 | int eir = parent_dir(x->par); 86 | if(eir == -1) { 87 | rotate(x, dir ^ 1); 88 | } 89 | else if(dir == eir){ 90 | rotate(x->par, eir ^ 1); 91 | rotate(x, dir ^ 1); 92 | } 93 | else { 94 | rotate(x, dir ^ 1); 95 | rotate(x, eir ^ 1); 96 | } 97 | } 98 | return x; 99 | } 100 | 101 | node* root; 102 | 103 | public: 104 | 105 | splay_map(): root(nullptr) {} 106 | 107 | node* lower_bound(Key key) { 108 | node* z = root; 109 | node* x = nullptr; 110 | while(z) { 111 | if(key <= z->key) { 112 | x = z; 113 | z = z->ch[0]; 114 | } 115 | else { 116 | z = z->ch[1]; 117 | } 118 | } 119 | return x; 120 | } 121 | 122 | void insert(Key key, T t) { 123 | node* z = new node(key, t); 124 | node* x = lower_bound(key); 125 | if(!x) { 126 | set(z, root, 0); 127 | root = z; 128 | } 129 | else { 130 | root = splay(x); 131 | node* q = root->ch[0]; 132 | set(z, q, 0); 133 | set(root, z, 0); 134 | } 135 | } 136 | 137 | void erase(Key key) { 138 | node* x = lower_bound(key); 139 | if(x->key == key) { 140 | root = splay(x); 141 | node* p = root->ch[0]; 142 | node* q = root->ch[1]; 143 | root->ch[0] = nullptr; 144 | root->ch[1] = nullptr; 145 | if(p) p->par = nullptr; 146 | if(q) q->par = nullptr; 147 | if(!p) { 148 | root = q; 149 | } 150 | else { 151 | while(p->ch[1]) p = p->ch[1]; 152 | root = splay(p); 153 | set(root, q, 1); 154 | } 155 | } 156 | } 157 | 158 | i64 size() { 159 | return subsize(root); 160 | } 161 | Key nth_node(i64 n) { 162 | node* z = root; 163 | while(z) { 164 | if(subsize(z->ch[0]) == n) { 165 | return z->key; 166 | } 167 | if(subsize(z->ch[0]) < n) { 168 | n -= subsize(z->ch[0]) + 1; 169 | z = z->ch[1]; 170 | } 171 | else { 172 | z = z->ch[0]; 173 | } 174 | } 175 | assert(false); 176 | } 177 | 178 | 179 | /* option */ 180 | //T fold() { return fold(root); } 181 | }; 182 | -------------------------------------------------------------------------------- /src/data_structures/fenwick_tree.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using i64 = long long; 3 | 4 | template 5 | struct fenwick_tree { 6 | using value_type = AbelianMonoid; 7 | 8 | i64 n; 9 | std::vector node; 10 | Ope ope; 11 | 12 | fenwick_tree(i64 n_): n(n_), node(n + 1, Ide) {} 13 | fenwick_tree(const std::vector& init): n(init.size()), node(n + 1, Ide) { 14 | for(i64 i = 0;i < init.size(); i++) node[i + 1] = init[i]; 15 | for(i64 i = 1;i < n;i++) node[i + (i & -i)] = ope(node[i + (i & -i)], node[i]); 16 | } 17 | void modify(i64 i, value_type x) { 18 | i++; 19 | while(i <= n) { 20 | node[i] = ope(node[i], x); 21 | i += (i & -i); 22 | } 23 | } 24 | // [0, i) 25 | value_type sum(i64 i) const { 26 | value_type ret = Ide; 27 | while(i > 0) { 28 | ret = ope(ret, node[i]); 29 | i -= i & (-i); 30 | } 31 | return ret; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/data_structures/heap/pairing_heap.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | template 5 | struct pairing_heap { 6 | struct node { 7 | T val; 8 | node* head; 9 | node* next; 10 | node(const T& v) : val(v), head(nullptr), next(nullptr) { } 11 | }; 12 | size_t sz; 13 | node* root; 14 | Compare comp; 15 | pairing_heap() : sz(0), root(nullptr) { } 16 | node* merge(node* x, node* y) { 17 | if(!y) return x; 18 | if(!x) return y; 19 | if(!comp(x->val, y->val)) swap(x,y); 20 | y->next = x->head; 21 | x->head = y; 22 | return x; 23 | } 24 | node* mergeList(node * x) { 25 | node* nn = nullptr; 26 | while(x) { 27 | node* a = x; 28 | node* b = nullptr; 29 | x = x->next; 30 | a->next = nullptr; 31 | if(x) { 32 | b = x; 33 | x = x->next; 34 | b->next = nullptr; 35 | } 36 | a = merge(a, b); 37 | a->next = nn; 38 | nn = a; 39 | } 40 | while(nn) { 41 | node* j = nn; 42 | nn = nn->next; 43 | x = merge(j,x); 44 | } 45 | return x; 46 | } 47 | 48 | /* return compest element */ 49 | T top() { 50 | return root->val; 51 | } 52 | 53 | /* pop compest element */ 54 | void pop() { 55 | --sz; 56 | node* te = root; 57 | root = mergeList(root->head); 58 | delete te, te = nullptr; 59 | } 60 | 61 | /* add element */ 62 | void push(const T& x) { 63 | ++sz; 64 | root = merge(new node(x), root); 65 | } 66 | 67 | /* size */ 68 | size_t size() { 69 | return sz; 70 | } 71 | 72 | /* merge heap */ 73 | void meld(pairing_heap& h) { 74 | root = merge(root, h.root); 75 | h.root = nullptr; 76 | h.sz = 0; 77 | } 78 | }; 79 | -------------------------------------------------------------------------------- /src/data_structures/heap/radix_heap.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | struct radix_heap { 7 | using key_type = unsigned; 8 | std::vector> bucket[33]; 9 | key_type size, last; 10 | 11 | radix_heap(): size(0), last(0) {} 12 | bool empty() const { return size == 0; } 13 | inline int getbit(int a) { 14 | return a ? 32 - __builtin_clz(a) : 0; 15 | } 16 | void push(key_type key, const T& value) { 17 | size++; 18 | bucket[getbit(key ^ last)].emplace_back(key, value); 19 | } 20 | std::pair pop() { 21 | if(bucket[0].empty()) { 22 | int idx = 1; 23 | while(bucket[idx].empty()) idx++; 24 | last = std::min_element(std::begin(bucket[idx]), end(bucket[idx]))->first; 25 | for(auto& p: bucket[idx]) bucket[getbit(p.first ^ last)].emplace_back(p); 26 | bucket[idx].clear(); 27 | } 28 | size--; 29 | auto ret = bucket[0].back(); 30 | bucket[0].pop_back(); 31 | return ret; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/data_structures/range_valued_array.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct range_valued_array { 5 | using key_type = int; 6 | using value_type = long long; 7 | using iterator_type = std::map::iterator; 8 | 9 | // [, r) 10 | std::map mp; 11 | key_type start; 12 | value_type init_value; 13 | 14 | 15 | range_valued_array(key_type start = key_type(), value_type init_value = value_type()): start(start), init_value(init_value) {} 16 | 17 | // key of return iterator is `pos` 18 | iterator_type inner_split(key_type pos) { 19 | if(pos == start) return mp.begin(); 20 | auto iter = mp.lower_bound(pos); 21 | if(iter->first == pos) return iter; 22 | mp[pos] = iter != mp.end() ? iter->second : init_value; 23 | return --iter; 24 | } 25 | 26 | iterator_type range_set_value(key_type l, key_type r, const value_type& val) { 27 | if(l == r) return mp.end(); 28 | auto liter = inner_split(l); 29 | auto riter = inner_split(r); 30 | std::cout << liter->first << " " << riter->first << std::endl; 31 | mp.erase(++liter, riter); 32 | riter->second = val; 33 | return riter; 34 | } 35 | 36 | iterator_type begin() { 37 | return mp.begin(); 38 | } 39 | iterator_type end() { 40 | return mp.end(); 41 | } 42 | 43 | value_type& operator[](const key_type& k) { 44 | auto iter = mp.upper_bound(k); 45 | return iter == mp.end() ? init_value : iter->second; 46 | } 47 | 48 | void debug_print() { 49 | std::cout << "["; 50 | for(auto p: mp) { 51 | std::cout << p.first << ": " << p.second << ", "; 52 | } 53 | std::cout << "]" << std::endl; 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /src/data_structures/segment_tree/beats_chmin_sum.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using i64 = long long; 3 | 4 | struct segment_tree_chmin_rsq { 5 | using T = i64; 6 | 7 | const T ide = 0; 8 | const T m_ide = -1e18; 9 | 10 | 11 | std::vector sum; 12 | std::vector m1, m2; 13 | std::vector mcnt; 14 | i64 n; 15 | i64 h; 16 | 17 | void fix(int k) { 18 | sum[k] = sum[k * 2 + 0] + sum[k * 2 + 1]; 19 | if(m1[k * 2 + 1] < m1[k * 2 + 0]) { 20 | m1[k] = m1[k * 2 + 0]; 21 | mcnt[k] = mcnt[k * 2 + 0]; 22 | m2[k] = std::max(m2[k * 2 + 0], m1[k * 2 + 1]); 23 | } 24 | else if(m1[k * 2 + 0] < m1[k * 2 + 1]) { 25 | m1[k] = m1[k * 2 + 1]; 26 | mcnt[k] = mcnt[k * 2 + 1]; 27 | m2[k] = std::max(m2[k * 2 + 1], m1[k * 2 + 0]); 28 | } 29 | else { 30 | m1[k] = m1[k * 2 + 0]; 31 | mcnt[k] = mcnt[k * 2 + 0] + mcnt[k * 2 + 1]; 32 | m2[k] = std::max(m2[k * 2 + 0], m2[k * 2 + 1]); 33 | } 34 | } 35 | 36 | segment_tree_chmin_rsq() {} 37 | segment_tree_chmin_rsq(const std::vector& vec) { 38 | n = 1; 39 | h = 1; 40 | while(n < vec.size()) n <<= 1, h++; 41 | sum.resize(2 * n); 42 | m1.resize(2 * n); 43 | m2.resize(2 * n, m_ide); 44 | mcnt.resize(2 * n, 0); 45 | for(i64 i = 0;i < vec.size();i++) { 46 | sum[i + n] = vec[i]; 47 | m1[i + n] = vec[i]; 48 | mcnt[i + n] = 1; 49 | } 50 | for(i64 i = n; i --> 1;) { 51 | fix(i); 52 | } 53 | } 54 | 55 | 56 | void eff(int k, T x) { 57 | sum[k] += (x - m1[k]) * mcnt[k]; 58 | m1[k] = x; 59 | } 60 | 61 | void push(int k) { 62 | if(m1[k] < m1[k * 2 + 0]) eff(k * 2 + 0, m1[k]); 63 | if(m1[k] < m1[k * 2 + 1]) eff(k * 2 + 1, m1[k]); 64 | } 65 | 66 | void infuse(int k) { 67 | k = k >> __builtin_ctz(k); 68 | while(k >>= 1) fix(k); 69 | } 70 | 71 | void infiltrate(int k) { 72 | if(k == n << 1) return; 73 | for(int i = h; i --> 1;) push(k >> i); 74 | } 75 | 76 | void subtree_chmin(int k, T x) { 77 | if(m1[k] <= x) return; 78 | if(m2[k] < x) { 79 | eff(k, x); 80 | return; 81 | } 82 | push(k); 83 | subtree_chmin(k * 2 + 0, x); 84 | subtree_chmin(k * 2 + 1, x); 85 | fix(k); 86 | } 87 | 88 | void range_chmin(int a, int b, T x) { 89 | infiltrate(a + n); 90 | infiltrate(b + n); 91 | int l = a + n; 92 | int r = b + n; 93 | while(l < r) { 94 | if(l & 1) subtree_chmin(l++, x); 95 | if(r & 1) subtree_chmin(--r, x); 96 | l >>= 1; 97 | r >>= 1; 98 | } 99 | infuse(a + n); 100 | infuse(b + n); 101 | } 102 | 103 | T range_sum(int l, int r) { 104 | l += n; 105 | r += n; 106 | infiltrate(l); 107 | infiltrate(r); 108 | T lx = ide; 109 | T rx = ide; 110 | while(l < r) { 111 | if(l & 1) lx = lx + sum[l++]; 112 | if(r & 1) rx = sum[--r] + rx; 113 | l >>= 1; 114 | r >>= 1; 115 | } 116 | return lx + rx; 117 | } 118 | }; 119 | 120 | #include 121 | using std::cout; 122 | using std::endl; 123 | 124 | int main() { 125 | segment_tree_chmin_rsq seg(std::vector{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }); 126 | 127 | cout << seg.range_sum(1, 5) << endl; 128 | cout << seg.range_sum(6, 10) << endl; 129 | seg.range_chmin(0, 16, 5); 130 | cout << seg.range_sum(5, 10) << endl; 131 | } 132 | -------------------------------------------------------------------------------- /src/data_structures/segment_tree/beats_chminmax_sum.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using i64 = long long; 4 | 5 | struct segment_tree_chminmax_rsq { 6 | using T = i64; 7 | 8 | const T ide = 0; 9 | const T INF = std::numeric_limits::max(); 10 | const T NINF = std::numeric_limits::min(); 11 | 12 | 13 | std::vector sum; 14 | std::vector gst1, gst2; 15 | std::vector lst1, lst2; 16 | std::vector mcnt; 17 | i64 n; 18 | i64 h; 19 | 20 | void fix(int k) { 21 | sum[k] = sum[k * 2 + 0] + sum[k * 2 + 1]; 22 | 23 | if(gst1[k * 2 + 1] < gst1[k * 2 + 0]) { 24 | gst1[k] = gst1[k * 2 + 0]; 25 | mcnt[k] = mcnt[k * 2 + 0]; 26 | gst2[k] = std::max(gst2[k * 2 + 0], gst1[k * 2 + 1]); 27 | } 28 | else if(gst1[k * 2 + 0] < gst1[k * 2 + 1]) { 29 | gst1[k] = gst1[k * 2 + 1]; 30 | mcnt[k] = mcnt[k * 2 + 1]; 31 | gst2[k] = std::max(gst2[k * 2 + 1], gst1[k * 2 + 0]); 32 | } 33 | else { 34 | gst1[k] = gst1[k * 2 + 0]; 35 | mcnt[k] = mcnt[k * 2 + 0] + mcnt[k * 2 + 1]; 36 | gst2[k] = std::max(gst2[k * 2 + 0], gst2[k * 2 + 1]); 37 | } 38 | 39 | if(lst1[k * 2 + 0] < lst1[k * 2 + 1]) { 40 | lst1[k] = lst1[k * 2 + 0]; 41 | mcnt[k] = mcnt[k * 2 + 0]; 42 | lst2[k] = std::min(lst2[k * 2 + 0], lst1[k * 2 + 1]); 43 | } 44 | else if(lst1[k * 2 + 1] < lst1[k * 2 + 0]) { 45 | lst1[k] = lst1[k * 2 + 1]; 46 | mcnt[k] = mcnt[k * 2 + 1]; 47 | lst2[k] = std::min(lst2[k * 2 + 1], lst1[k * 2 + 0]); 48 | } 49 | else { 50 | lst1[k] = lst1[k * 2 + 0]; 51 | mcnt[k] = mcnt[k * 2 + 0] + mcnt[k * 2 + 1]; 52 | lst2[k] = std::min(lst2[k * 2 + 0], lst2[k * 2 + 1]); 53 | } 54 | } 55 | 56 | segment_tree_chmin_rsq() {} 57 | segment_tree_chmin_rsq(const std::vector& vec) { 58 | n = 1; 59 | h = 1; 60 | while(n < vec.size()) n <<= 1, h++; 61 | sum.resize(2 * n); 62 | gst1.resize(2 * n); 63 | gst2.resize(2 * n, NINF); 64 | lst1.resize(2 * n); 65 | lst2.resize(2 * n, INF); 66 | mcnt.resize(2 * n, 0); 67 | for(i64 i = 0;i < vec.size();i++) { 68 | sum[i + n] = vec[i]; 69 | gst1[i + n] = vec[i]; 70 | lst1[i + n] = vec[i]; 71 | mcnt[i + n] = 1; 72 | } 73 | for(i64 i = n; i --> 1;) { 74 | fix(i); 75 | } 76 | } 77 | 78 | void eff_chmin(int k, T x) { 79 | sum[k] += (x - gst1[k]) * mcnt[k]; 80 | if(gst1[k] == lst1[k]) { 81 | gst1[k] = lst1[k] = x; 82 | } 83 | else if(gst1[k] == lst2[k]) { 84 | gst1[k] = lst2[k] = x; 85 | } 86 | else { 87 | gst1[k] = x; 88 | } 89 | } 90 | 91 | void eff_chmax(int k, T x) { 92 | sum[k] += (x - lst1[k]) * mcnt[k]; 93 | if(lst1[k] == gst1[k]) { 94 | lst1[k] = gst1[k] = x; 95 | } 96 | else if(lst1[k] == gst2[k]) { 97 | lst1[k] = gst2[k] = x; 98 | } 99 | else { 100 | lst1[k] = x; 101 | } 102 | } 103 | 104 | void push(int k) { 105 | if(gst1[k] < gst1[k * 2 + 0]) eff_chmin(k * 2 + 0, gst1[k]); 106 | if(gst1[k] < gst1[k * 2 + 1]) eff_chmin(k * 2 + 1, gst1[k]); 107 | 108 | if(lst1[k] > lst1[k * 2 + 0]) eff_chmax(k * 2 + 0, gst1[k]); 109 | if(lst1[k] > lst1[k * 2 + 1]) eff_chmax(k * 2 + 1, gst1[k]); 110 | } 111 | 112 | void infuse(int k) { 113 | k = k >> __builtin_ctz(k); 114 | while(k >>= 1) fix(k); 115 | } 116 | 117 | void infiltrate(int k) { 118 | if(k == n << 1) return; 119 | for(int i = h; i --> 1;) push(k >> i); 120 | } 121 | 122 | void subtree_chmin(int k, T x) { 123 | if(gst1[k] <= x) return; 124 | if(gst2[k] < x) { 125 | eff_chmin(k, x); 126 | return; 127 | } 128 | push(k); 129 | subtree_chmin(k * 2 + 0, x); 130 | subtree_chmin(k * 2 + 1, x); 131 | fix(k); 132 | } 133 | 134 | void subtree_chmax(int k, T x) { 135 | if(x <= lst1[k]) return; 136 | if(x < lst2[k]) { 137 | eff_chmax(k, x); 138 | return; 139 | } 140 | push(k); 141 | subtree_chmax(k * 2 + 0, x); 142 | subtree_chmax(k * 2 + 1, x); 143 | fix(k); 144 | } 145 | 146 | void range_chmin(int a, int b, T x) { 147 | infiltrate(a + n); 148 | infiltrate(b + n); 149 | int l = a + n; 150 | int r = b + n; 151 | while(l < r) { 152 | if(l & 1) subtree_chmin(l++, x); 153 | if(r & 1) subtree_chmin(--r, x); 154 | l >>= 1; 155 | r >>= 1; 156 | } 157 | infuse(a + n); 158 | infuse(b + n); 159 | } 160 | 161 | void range_chmax(int a, int b, T x) { 162 | infiltrate(a + n); 163 | infiltrate(b + n); 164 | int l = a + n; 165 | int r = b + n; 166 | while(l < r) { 167 | if(l & 1) subtree_chmax(l++, x); 168 | if(r & 1) subtree_chmax(--r, x); 169 | l >>= 1; 170 | r >>= 1; 171 | } 172 | infuse(a + n); 173 | infuse(b + n); 174 | } 175 | 176 | T range_sum(int l, int r) { 177 | l += n; 178 | r += n; 179 | infiltrate(l); 180 | infiltrate(r); 181 | T lx = ide; 182 | T rx = ide; 183 | while(l < r) { 184 | if(l & 1) lx = lx + sum[l++]; 185 | if(r & 1) rx = sum[--r] + rx; 186 | l >>= 1; 187 | r >>= 1; 188 | } 189 | return lx + rx; 190 | } 191 | }; 192 | 193 | #include 194 | using std::cout; 195 | using std::endl; 196 | 197 | int main() { 198 | segment_tree_chmin_rsq seg(std::vector{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }); 199 | 200 | cout << seg.range_sum(1, 5) << endl; 201 | cout << seg.range_sum(6, 10) << endl; 202 | seg.range_chmax(0, 5, 2); 203 | seg.range_chmin(0, 5, 3); 204 | cout << seg.range_sum(0, 5) << endl; 205 | } 206 | -------------------------------------------------------------------------------- /src/data_structures/segment_tree/dynamic_segment_tree.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | struct dynamic_segment_tree { 6 | using T = i64; 7 | static T ide() { return 0ll; } 8 | static T ope(const T& a, const T& b) { return a + b; } 9 | 10 | struct node { 11 | node* left; 12 | node* right; 13 | T val; 14 | node(T v): val(v), left(nullptr), right(nullptr) {} 15 | }; 16 | 17 | i64 n; 18 | node* root; 19 | dynamic_segment_tree(const i64 sz): root(new node(ide())) { 20 | n = 1; 21 | while(n < sz) n *= 2; 22 | } 23 | T value(node* n) { 24 | if(n) return n->val; 25 | else return ide(); 26 | } 27 | void update(node* n, i64 i, T x, i64 l, i64 r) { 28 | if(l + 1 == r) { 29 | n->val = x; 30 | } 31 | else { 32 | i64 m = (l + r) / 2; 33 | if(i < m) { 34 | if(!n->left) { 35 | n->left = new node(ide()); 36 | } 37 | update(n->left, i, x, l, m); 38 | } 39 | else { 40 | if(!n->right) { 41 | n->right = new node(ide()); 42 | } 43 | update(n->right, i, x, m, r); 44 | } 45 | n->val = ope(value(n->left), value(n->right)); 46 | } 47 | } 48 | 49 | T get(node* n, i64 a, i64 b, i64 l, i64 r) { 50 | if(!n) return ide(); 51 | if(a <= l && r <= b) return value(n); 52 | else if(r <= a || b <= l) return ide(); 53 | else return ope(get(n->left, a, b, l, (l + r) / 2), get(n->right, a, b, (l + r) / 2, r)); 54 | } 55 | 56 | void update(i64 i, T x) { 57 | update(root, i, x, 0, n); 58 | } 59 | 60 | T sum(i64 a, i64 b) { 61 | return get(root, a, b, 0, n); 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /src/data_structures/segment_tree/lazy_segment_tree.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using i64 = long long; 5 | 6 | struct lazy_segment_tree { 7 | using T = i64; 8 | using L = i64; 9 | static inline T t_ide() { return (1LL << 31) - 1; } 10 | static inline L l_ide() { return (1LL << 31) - 1; } 11 | static inline T ope(const T& a, const T& b) { return std::min(a, b); } 12 | static inline L lazy_ope(const L& a, const L& b) { return b; } 13 | static inline T effect(const T& t, const L& l) { return l; } 14 | 15 | int n, h; 16 | std::vector node; 17 | std::vector lazy; 18 | std::vector flag; 19 | 20 | lazy_segment_tree(int N) { 21 | n = 1; 22 | h = 1; 23 | while(n < N) n <<= 1, h++; 24 | node.resize(n << 1, t_ide()); 25 | lazy.resize(n << 1, l_ide()); 26 | flag.resize(n << 1, false); 27 | } 28 | lazy_segment_tree(const std::vector& init) { 29 | n = 1; 30 | h = 1; 31 | while(n < init.size()) n <<= 1, h++; 32 | node.resize(n << 1, t_ide()); 33 | lazy.resize(n << 1, l_ide()); 34 | flag.resize(n << 1, false); 35 | for(int i = 0;i < init.size();i++) node[i + n] = init[i]; 36 | for(int i = n; i --> 1;) node[i] = ope(node[(i << 1)], node[(i << 1) + 1]); 37 | } 38 | 39 | inline void eff(int k, L x) { 40 | if(k < n << 1) { 41 | lazy[k] = lazy_ope(lazy[k], x); 42 | flag[k] = true; 43 | } 44 | } 45 | inline T eval(int k) const { return flag[k] ? effect(node[k], lazy[k]) : node[k]; } 46 | 47 | inline void push(int k) { 48 | if(flag[k]) { 49 | node[k] = eval(k); 50 | eff(k << 1, lazy[k]); 51 | eff((k << 1) | 1, lazy[k]); 52 | lazy[k] = l_ide(); 53 | flag[k] = false; 54 | } 55 | } 56 | 57 | inline void infuse(int k) { 58 | k = k >> __builtin_ctz(k); 59 | while((k >>= 1)) node[k] = ope(eval(k << 1), eval((k << 1) + 1)); 60 | } 61 | 62 | inline void infiltrate(int k) { 63 | if(k == n << 1) return; 64 | int kc = __builtin_ctz(k); 65 | for(int i = h; i --> kc;) push(k >> i); 66 | } 67 | 68 | inline void infiltrate(int l, int r) { 69 | if(r == n << 1) infiltrate(l); 70 | else { 71 | int hh = h; 72 | int x = l ^ r; 73 | for(; !(x >> --hh);) push(l >> hh); 74 | int lc = __builtin_ctz(l); 75 | for(int i = hh + 1; i --> lc;) push(l >> i); 76 | int rc = __builtin_ctz(r); 77 | for(int i = hh + 1; i --> rc;) push(r >> i); 78 | } 79 | } 80 | 81 | void update(int a, int b, L x) { 82 | int l = a + n; 83 | int r = b + n; 84 | infiltrate(l, r); 85 | while(l < r) { 86 | if(l & 1) eff(l++, x); 87 | if(r & 1) eff(--r, x); 88 | l >>= 1; 89 | r >>= 1; 90 | } 91 | infuse(a + n); 92 | infuse(b + n); 93 | } 94 | 95 | T sum(int l, int r) { 96 | l += n; 97 | r += n; 98 | infiltrate(l, r); 99 | T lx = t_ide(); 100 | T rx = t_ide(); 101 | while(l < r) { 102 | if(l & 1) lx = ope(lx, eval(l++)); 103 | if(r & 1) rx = ope(eval(--r), rx); 104 | l >>= 1; 105 | r >>= 1; 106 | } 107 | return ope(lx, rx); 108 | } 109 | }; 110 | -------------------------------------------------------------------------------- /src/data_structures/segment_tree/li_chao.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // doubleのときは, midを変える 5 | template> 6 | struct li_chao{ 7 | struct Line{ 8 | T a,b; 9 | Line(T a = 0,T b = 0) : a(a) , b(b) {} 10 | T get(T x){return a * x + b;} 11 | }; 12 | 13 | struct Node{ 14 | Line line; 15 | Node *lhs,*rhs; 16 | Node(Line l) : line(l) , lhs(nullptr) , rhs(nullptr){} 17 | }; 18 | 19 | const T MI,MA; 20 | 21 | Node * root; 22 | 23 | Compare comp; 24 | 25 | T comp_get(const T & x,const T & y){ 26 | if(comp(x , y)) return x; 27 | else return y; 28 | } 29 | 30 | li_chao(T mi , T ma) : MI(mi), MA(ma) , root(nullptr){} 31 | 32 | Node * insert(Node * p,T l,T r,Line & line){ 33 | if(l > r) { 34 | return p; 35 | } 36 | if(!p) return new Node(line); 37 | if(comp(p->line.get(l) , line.get(l)) && comp(p->line.get(r) ,line.get(r))){ 38 | return p; 39 | } 40 | if(!comp(p->line.get(l) , line.get(l)) && !comp(p->line.get(r) ,line.get(r))){ 41 | p->line = line; 42 | return p; 43 | } 44 | T mid = (l + r) / 2; 45 | if(comp(line.get(mid) , p->line.get(mid))) swap(p->line , line); 46 | if(comp(line.get(l) , p->line.get(l))){ 47 | p->lhs = insert(p->lhs , l , mid , line); 48 | } 49 | else{ 50 | p->rhs = insert(p->rhs , mid + 1, r , line); 51 | } 52 | return p; 53 | } 54 | 55 | void add_line(T a,T b){ 56 | Line l(a , b); 57 | root = insert(root,MI,MA,l); 58 | } 59 | 60 | T get(Node * p,T l,T r,T t){ 61 | if(!p) return ide; 62 | T mid = (l + r) / 2; 63 | if(t <= mid) return comp_get(p->line.get(t) , get(p->lhs , l, mid,t)); 64 | else return comp_get(p->line.get(t),get(p->rhs,mid + 1 ,r , t)); 65 | } 66 | 67 | T get(T x){ 68 | return get(root,MI,MA,x); 69 | } 70 | }; 71 | -------------------------------------------------------------------------------- /src/data_structures/segment_tree/li_chao_segment.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // doubleのときは, midを変える 6 | template> 7 | struct li_chao{ 8 | struct Line{ 9 | T a,b; 10 | bool OK; 11 | Line(): a(0), b(0), OK(false) {} 12 | Line(T a,T b) : a(a) , b(b), OK(true) {} 13 | T get(T x){ 14 | if(OK) { 15 | return a * x + b; 16 | } 17 | else { 18 | return ide; 19 | } 20 | } 21 | }; 22 | 23 | struct Node{ 24 | Line line; 25 | Node *lhs,*rhs; 26 | Node() : line(), lhs(nullptr), rhs(nullptr) {} 27 | Node(Line l) : line(l) , lhs(nullptr) , rhs(nullptr){} 28 | }; 29 | 30 | const T MI,MA; 31 | 32 | Node * root; 33 | 34 | Compare comp; 35 | 36 | T comp_get(const T & x,const T & y){ 37 | if(comp(x , y)) return x; 38 | else return y; 39 | } 40 | 41 | li_chao(T mi , T ma) : MI(mi), MA(ma) , root(nullptr){} 42 | 43 | Node * insert(Node * p,T l,T r,Line & line){ 44 | if(l > r) { 45 | return p; 46 | } 47 | if(!p) return new Node(line); 48 | if(comp(p->line.get(l) , line.get(l)) && comp(p->line.get(r) ,line.get(r))){ 49 | return p; 50 | } 51 | if(!comp(p->line.get(l) , line.get(l)) && !comp(p->line.get(r) ,line.get(r))){ 52 | p->line = line; 53 | return p; 54 | } 55 | T mid = (l + r) / 2; 56 | if(r - l == 1) { 57 | mid = l; 58 | } 59 | if(comp(line.get(mid) , p->line.get(mid))) swap(p->line , line); 60 | if(comp(line.get(l) , p->line.get(l))){ 61 | p->lhs = insert(p->lhs , l , mid , line); 62 | } 63 | else{ 64 | p->rhs = insert(p->rhs , mid + 1, r , line); 65 | } 66 | return p; 67 | } 68 | 69 | Node* insert_rec(Node* p, T l, T r, Line line, T a, T b) { 70 | if(r < a || b < l) { 71 | return p; 72 | } 73 | if(a <= l && r <= b) { 74 | return insert(p, l, r, line); 75 | } 76 | T mid = (l + r) / 2; 77 | if(r - l == 1) { 78 | mid = l; 79 | } 80 | if(!p) { 81 | p = new Node(); 82 | } 83 | p->lhs = insert_rec(p->lhs, l, mid, line, a, b); 84 | p->rhs = insert_rec(p->rhs, mid + 1, r, line, a, b); 85 | return p; 86 | } 87 | 88 | void add_line(T a,T b){ 89 | Line l(a , b); 90 | root = insert(root,MI,MA,l); 91 | } 92 | 93 | void add_line_range(T a, T b, T l, T r) { 94 | Line line(a, b); 95 | root = insert_rec(root, MI, MA, line, l, r); 96 | } 97 | 98 | T get(Node * p,T l,T r,T t){ 99 | if(!p) return ide; 100 | T mid = (l + r) / 2; 101 | if(r - l == 1) { 102 | mid = l; 103 | } 104 | if(t <= mid) return comp_get(p->line.get(t) , get(p->lhs , l, mid,t)); 105 | else return comp_get(p->line.get(t),get(p->rhs,mid + 1 ,r , t)); 106 | } 107 | 108 | T get_rec(Node* p, T l, T r, T t, T a, T b) { 109 | if(!p) return ide; 110 | if(r <= a || b <= l) { 111 | return ide; 112 | } 113 | if(a <= l && r <= b) { 114 | return get(p, l, r, t); 115 | } 116 | T mid = (l + r) / 2; 117 | return comp_get(get_rec(p, l, mid, t, a, b), get_rec(p, mid + 1, r, t, a, b)); 118 | } 119 | 120 | T get(T x){ 121 | return get(root,MI,MA,x); 122 | } 123 | 124 | T get_range(T x, T l, T r) { 125 | return get_rec(root, MI, MA, l, r); 126 | } 127 | }; 128 | 129 | #include 130 | using namespace std; 131 | using i64 = long long; 132 | #define rep(i,s,e) for(i64 (i) = (s);(i) < (e);(i)++) 133 | #define all(x) x.begin(),x.end() 134 | 135 | template 136 | static inline std::vector ndvec(size_t&& n, T val) noexcept { 137 | return std::vector(n, std::forward(val)); 138 | } 139 | 140 | template 141 | static inline auto ndvec(size_t&& n, Tail&&... tail) noexcept { 142 | return std::vector(tail)...))>(n, ndvec(std::forward(tail)...)); 143 | } 144 | 145 | int main() { 146 | cin.tie(nullptr); 147 | std::ios::sync_with_stdio(false); 148 | i64 N, Q; 149 | cin >> N >> Q; 150 | li_chao> seg(i64(-1e9 - 1), i64(1e9 + 1)); 151 | while(N--) { 152 | i64 l, r, a, b; 153 | cin >> l >> r >> a >> b; 154 | seg.add_line_range(a, b, l, r - 1); 155 | } 156 | while(Q--) { 157 | i64 t; 158 | cin >> t; 159 | if(t == 0) { 160 | i64 l, r, a, b; 161 | cin >> l >> r >> a >> b; 162 | seg.add_line_range(a, b, l, r - 1); 163 | } 164 | else { 165 | i64 p; 166 | cin >> p; 167 | i64 ans = seg.get(p); 168 | if(ans == LLONG_MAX) { 169 | cout << "INFINITY" << "\n"; 170 | } 171 | else { 172 | cout << ans << "\n"; 173 | } 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/data_structures/segment_tree/persistent_segment_tree.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | using i64 = long long; 6 | 7 | struct persistent_segment_tree { 8 | using T = pair; 9 | struct node { 10 | using Ptr = node*; 11 | T data; 12 | Ptr left; 13 | Ptr right; 14 | 15 | node(T data): data(data), left(), right() {} 16 | node(T data, Ptr left, Ptr right) 17 | : data(data), left(left), right(right) {} 18 | }; 19 | 20 | using Ptr = node*; 21 | 22 | static T ope(const T& a, const T& b) { return std::min(a, b); } 23 | static T ide() { return {(i64)(1e18), (i64)(1e18)}; } 24 | 25 | Ptr root; 26 | i64 N; 27 | 28 | static Ptr build(i64 l, i64 r, const vector& init) { 29 | if(l + 1 >= r) return new node(init[l]); 30 | else { 31 | Ptr le = build(l , (l + r) / 2, init); 32 | Ptr ri = build((l + r) / 2, r, init); 33 | T da = ope(le->data, ri->data); 34 | return new node(da, le, ri); 35 | } 36 | } 37 | 38 | static Ptr update(Ptr node, i64 i, T val, i64 l, i64 r) { 39 | if(i == l && i + 1 == r) return new struct node(val); 40 | Ptr left = nullptr; 41 | Ptr right = nullptr; 42 | if(l <= i && i < ((l + r) >> 1)) { 43 | left = update(node->left, i, val, l, (l + r) >> 1); 44 | right = node->right; 45 | } 46 | else { 47 | left = node->left; 48 | right = update(node->right, i, val, (l + r) >> 1, r); 49 | } 50 | return new struct node(ope(left->data, right->data), left, right); 51 | } 52 | 53 | static T sum(Ptr node, i64 a, i64 b, i64 l, i64 r) { 54 | if(b <= l || r <= a) return ide(); 55 | else if(a <= l && r <= b) return node->data; 56 | else return ope( 57 | sum(node->left, a, b, l, (l + r) >> 1), 58 | sum(node->right, a, b, (l + r) >> 1, r) 59 | ); 60 | } 61 | 62 | persistent_segment_tree(const vector& init) 63 | : root(build(0, init.size(), init)), N(init.size()) {} 64 | persistent_segment_tree(Ptr root, i64 N): root(root), N(N) {} 65 | persistent_segment_tree update(i64 i, T x) const { 66 | return persistent_segment_tree(update(root, i, x, 0, N), N); 67 | } 68 | T sum(i64 l, i64 r) { return sum(root, l, r, 0, N); } 69 | }; 70 | -------------------------------------------------------------------------------- /src/data_structures/segment_tree/segment_tree.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using i64 = long long; 3 | 4 | template 5 | struct segment_tree { 6 | i64 n; 7 | std::vector node; 8 | 9 | segment_tree() {} 10 | segment_tree(const std::vector& init) { 11 | n = 1; 12 | while(n < init.size()) n *= 2; 13 | node.resize(2 * n, ide()); 14 | for(int i = 0;i < init.size();i++) node[i + n] = init[i]; 15 | for(int i = n; i --> 1;) node[i] = ope(node[i * 2], node[i * 2 + 1]); 16 | } 17 | 18 | void update(i64 i, T x) { 19 | i += n; 20 | node[i] = x; 21 | while(i > 1) { 22 | i >>= 1; 23 | node[i] = ope(node[i * 2], node[i * 2 + 1]); 24 | } 25 | } 26 | 27 | T sum(i64 l, i64 r) const { 28 | T lx = ide(); 29 | T rx = ide(); 30 | l += n; 31 | r += n; 32 | while(l < r) { 33 | if(l & 1) { lx = ope(lx, node[l++]); } 34 | if(r & 1) { rx = ope(node[--r], rx); } 35 | l >>= 1; 36 | r >>= 1; 37 | } 38 | return ope(lx, rx); 39 | } 40 | 41 | const T& at(i64 i) const { 42 | return node[i + n]; 43 | } 44 | 45 | template 46 | i64 subtree_down_first(i64 i, T lx, F isok) const { 47 | while(i < n) { 48 | T next = ope(lx, node[i * 2]); 49 | if(isok(next)) i = i * 2; 50 | else { 51 | lx = next; 52 | i = i * 2 + 1; 53 | } 54 | } 55 | return i - n + 1; 56 | } 57 | 58 | template 59 | i64 find_first(i64 l, F isok) const { 60 | if(isok(ide())) { 61 | return l; 62 | } 63 | if(l == 0) { 64 | if(isok(node[1])) return subtree_down_first(1, ide(), isok); 65 | return -1; 66 | } 67 | T lx = ide(); 68 | i64 r = n << 1; 69 | l += n; 70 | while(l < r) { 71 | if(l & 1) { 72 | T next = ope(lx, node[l]); 73 | if(isok(next)) return subtree_down_first(l, lx, isok); 74 | lx = next; 75 | l++; 76 | } 77 | l >>= 1; 78 | r >>= 1; 79 | } 80 | return -1; 81 | } 82 | }; 83 | -------------------------------------------------------------------------------- /src/data_structures/sparse_table/sparse_table.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | struct sparse_table { 6 | using Band = int; 7 | inline Band ope(const Band& a, const Band b) { return min(a, b); } 8 | 9 | i64 N; 10 | vector> table; 11 | 12 | sparse_table(vector arr) : N(arr.size()) { 13 | table.resize(__lg(N) + 1); 14 | 15 | table[0].resize(N); 16 | for(int i = 0;i < N;i++) { 17 | table[0][i] = arr[i]; 18 | } 19 | 20 | for(int k = 1;(1 << k) <= N;k++) { 21 | table[k].resize(N); 22 | for(int i = 0;i + (1 << k) <= N;i++) { 23 | table[k][i] = ope(table[k - 1][i], table[k - 1][i + (1 << (k - 1))]); 24 | } 25 | } 26 | } 27 | /* [s, t) */ 28 | Band query(i64 s, i64 t) { 29 | int k = __lg(t - s); 30 | return ope(table[k][s], table[k][t - (1 << k)]); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /src/data_structures/swag.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct swag { 4 | 5 | using T = int; 6 | static T ide() { 7 | return 0; 8 | } 9 | static T ope(const T& a, const T& b) { 10 | return a + b; 11 | } 12 | 13 | std::stack left_v, right_v, left_f, right_f; 14 | 15 | swag() { 16 | left_f.push(ide()); 17 | right_f.push(ide()); 18 | } 19 | 20 | void push(T val) { 21 | left_f.push(ope(left_f.top(), val)); 22 | left_v.push(std::move(val)); 23 | } 24 | 25 | T fold() { 26 | return ope(right_f.top(), left_f.top()); 27 | } 28 | 29 | void pop() { 30 | if(right_f.size() == 1) { 31 | while(left_f.size() > 1) { 32 | right_f.push(ope(left_v.top(), right_f.top())); 33 | right_v.push(left_v.top()); 34 | left_f.pop(); 35 | left_v.pop(); 36 | } 37 | } 38 | right_f.pop(); 39 | right_v.pop(); 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /src/data_structures/trees/euler_tour_path.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | struct eulartour_path { 6 | vector> G; 7 | vector in, out; 8 | i64 cnt; 9 | eulartour_path(i64 n): G(n), in(n), out(n) {} 10 | void add_edge(i64 u, i64 v) { 11 | G[u].push_back(v); 12 | G[v].push_back(u); 13 | } 14 | 15 | void dfs(i64 v, i64 f) { 16 | for(auto to: G[v]) { 17 | if(to == f) continue; 18 | in[to] = cnt; 19 | cnt++; 20 | dfs(to, v); 21 | out[to] = cnt; 22 | cnt++; 23 | } 24 | } 25 | 26 | void start_tour(i64 r) { 27 | in[r] = cnt; 28 | cnt++; 29 | dfs(r, -1); 30 | } 31 | 32 | i64 edge_in(i64 v) { return in[v]; } 33 | i64 edge_out(i64 v) { return out[v]; } 34 | pair path_range(i64 u, i64 v) { 35 | return { in[u] + 1, in[v] + 1 }; 36 | } 37 | }; 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/data_structures/trees/euler_tour_subtree.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | struct eulertour_subtree { 6 | vector> G; 7 | vector tour; 8 | vector L, R; 9 | vector depth; 10 | eulertour_subtree(i64 n): G(n), L(n), R(n), depth(n) {} 11 | void add_edge(i64 u, i64 v) { 12 | G[u].push_back(v); 13 | G[v].push_back(u); 14 | } 15 | 16 | void dfs(i64 v, i64 f, i64 d) { 17 | tour.push_back(v); 18 | L[v] = tour.size() - 1; 19 | depth[v] = d; 20 | for(auto to: G[v]) { 21 | if(to == f) continue; 22 | dfs(to, v, d + 1); 23 | //tour.push_back(v); 24 | } 25 | R[v] = tour.size() - 1; 26 | } 27 | 28 | void start_tour(i64 r) { 29 | dfs(r, -1, 0); 30 | } 31 | 32 | //[L[v], R[v]) 33 | pair subtree_range(i64 v) { 34 | return pair(L[v], R[v]); 35 | } 36 | 37 | i64 vertex(i64 v) { 38 | return L[v]; 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /src/data_structures/trees/euler_tour_tree.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct euler_tour_tree { 7 | using size_type = std::size_t; 8 | using node_index = std::int_least32_t; 9 | using vertex_index = std::int_least32_t; 10 | 11 | struct node; 12 | static struct node n[2020]; 13 | static node_index ni; 14 | 15 | struct node { 16 | vertex_index s, d; 17 | node_index c[3]; 18 | int sz; 19 | node(): sz(1) {} 20 | inline node& operator[](size_type d) { return n[c[d]]; } 21 | }; 22 | 23 | node_index new_edge(int s, int d) { 24 | int i = ni++; 25 | int ri = ni++; 26 | n[i].s = n[ri].d = s; 27 | n[i].d = n[ri].s = d; 28 | return i; 29 | } 30 | 31 | static void fix(node_index i) { 32 | n[i].sz = (n[i].s == n[i].d) ? 1 : 0; 33 | if(n[i].c[0]) n[i].sz += n[i][0].sz; 34 | if(n[i].c[1]) n[i].sz += n[i][1].sz; 35 | } 36 | 37 | static int child_dir(node_index i) { 38 | if(n[i].c[2]) { 39 | if(n[i][2].c[0] == i) { return 0; } 40 | else if(n[i][2].c[1] == i) { return 1; } 41 | } 42 | return 2; 43 | } 44 | 45 | static void rotate(node_index x, size_type dir) { 46 | node_index p = n[x].c[2]; 47 | int x_dir = child_dir(x); 48 | node_index y = n[x].c[dir ^ 1]; 49 | if(n[y].c[dir]) n[y][dir].c[2] = x; 50 | n[x].c[dir ^ 1] = n[y].c[dir]; 51 | n[n[x].c[2] = y].c[dir] = x; 52 | n[y].c[2] = p; 53 | if(x_dir < 2) n[p].c[x_dir] = y; 54 | if(n[x].c[dir ^ 1]) fix(n[x].c[dir ^ 1]); 55 | fix(x); 56 | } 57 | 58 | static void splay(node_index i) { 59 | int i_dir; 60 | int j_dir; 61 | while((i_dir = child_dir(i)) < 2) { 62 | node_index j = n[i].c[2]; 63 | if((j_dir = child_dir(j)) < 2) { 64 | node_index k = n[j].c[2]; 65 | if(i_dir == j_dir) rotate(k, j_dir ^ 1), rotate(j, i_dir ^ 1); 66 | else rotate(j, i_dir ^ 1), rotate(k, j_dir ^ 1); 67 | } 68 | else rotate(j, i_dir ^ 1); 69 | } 70 | fix(i); 71 | } 72 | 73 | static node_index merge_back(node_index l, node_index r) { 74 | if(!l) return r; 75 | if(!r) return l; 76 | while(n[l].c[1]) l = n[l].c[1]; 77 | splay(l); 78 | n[n[r].c[2] = l].c[1] = r; 79 | fix(l); 80 | return l; 81 | } 82 | 83 | static std::pair split(node_index i) { 84 | splay(i); 85 | node_index l = n[i].c[0]; 86 | n[i].c[0] = n[l].c[2] = 0; 87 | fix(i); 88 | return { l, i }; 89 | } 90 | 91 | static void reroot(node_index v) { 92 | auto p = split(v); 93 | merge_back(p.second, p.first); 94 | splay(v); 95 | } 96 | 97 | static bool same_root(node_index i, node_index j) { 98 | if(i) splay(i); 99 | if(j) splay(j); 100 | while(n[i].c[2]) i = n[i].c[2]; 101 | while(n[j].c[2]) j = n[j].c[2]; 102 | return i == j; 103 | } 104 | 105 | node_index n_start; 106 | euler_tour_tree(int N): n_start(ni) { 107 | ni += N; 108 | for(int i = 0; i < N; i++) { 109 | n[i + n_start].s = n[i + n_start].d = i; 110 | } 111 | } 112 | 113 | 114 | node_index link(vertex_index x, vertex_index y) { 115 | int ei = new_edge(x, y); 116 | x += n_start; 117 | y += n_start; 118 | reroot(x); 119 | reroot(y); 120 | n[n[x].c[2] = ei].c[0] = x; 121 | n[n[y].c[2] = ei].c[1] = y; 122 | fix(ei); 123 | merge_back(ei, ei + 1); 124 | return ei; 125 | } 126 | 127 | void cut(node_index ei) { 128 | int rei = ei + 1; 129 | auto p = split(ei); 130 | if(same_root(p.first, rei)) { 131 | auto q = split(rei); 132 | node_index left = q.first; 133 | node_index center = n[q.second].c[1]; 134 | node_index right = n[p.second].c[1]; 135 | n[center].c[2] = 0; 136 | n[right].c[2] = 0; 137 | merge_back(left, right); 138 | } 139 | else { 140 | splay(ei); 141 | ei = n[ei].c[1]; 142 | n[ei].c[2] = 0; 143 | auto q = split(rei); 144 | splay(p.first); 145 | node_index left = p.first; 146 | node_index center = q.first; 147 | node_index right = n[q.second].c[1]; 148 | n[right].c[2] = 0; 149 | merge_back(left, right); 150 | } 151 | } 152 | 153 | void debug_tree(node_index i, std::string indent) { 154 | if(n[i].c[0]) { 155 | debug_tree(n[i].c[0], indent + "l"); 156 | } 157 | std::cout << " " << i << " = (" << n[i].s << " " << n[i].d << ")" << " p " << n[i].c[2] << std::endl; 158 | if(n[i].c[1]) { 159 | debug_tree(n[i].c[1], indent + "r"); 160 | } 161 | } 162 | }; 163 | 164 | euler_tour_tree::node_index euler_tour_tree::ni = 1; 165 | euler_tour_tree::node euler_tour_tree::n[2020]; 166 | 167 | 168 | int main() { 169 | euler_tour_tree ett(10); 170 | 171 | ett.link(0, 1); 172 | ett.link(1, 2); 173 | int ei = ett.link(1, 3); 174 | ett.link(0, 4); 175 | std::cout << "cut" << std::endl; 176 | euler_tour_tree::reroot(4); 177 | ett.cut(ei); 178 | euler_tour_tree::reroot(1); 179 | std::cout << "result" << std::endl; 180 | ett.debug_tree(1, ""); 181 | std::cout << "result3" << std::endl; 182 | euler_tour_tree::reroot(4); 183 | ett.debug_tree(4, ""); 184 | } 185 | -------------------------------------------------------------------------------- /src/data_structures/trees/heavy_light_decomposition.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | struct HeavyLightDecomposition { 6 | vector> G; 7 | vector in, out; 8 | vector sz; 9 | vector seq; 10 | vector next; 11 | vector par; 12 | 13 | 14 | HeavyLightDecomposition(i64 n) 15 | : G(n), in(n), out(n), sz(n), next(n, -1), par(n, -1) {} 16 | 17 | void add_edge(i64 u, i64 v) { 18 | G[u].push_back(v); 19 | G[v].push_back(u); 20 | } 21 | 22 | void dfs_sz(i64 v, i64 f) { 23 | sz[v] = 1; 24 | for(i64 i = 0;i < G[v].size();i++) { 25 | i64 x = G[v][i]; 26 | if(x == f) continue; 27 | dfs_sz(x, v); 28 | par[x] = v; 29 | sz[v] += sz[x]; 30 | if(sz[G[v][0]] < sz[G[v][i]]) { swap(G[v][0], G[v][i]); } 31 | } 32 | } 33 | 34 | i64 dfs_eul(i64 v, i64 f, i64 t) { 35 | in[v] = t++; 36 | seq.push_back(v); 37 | for(i64 i = 0;i < G[v].size();i++) { 38 | i64 x = G[v][i]; 39 | if(x == f) continue; 40 | next[x] = (i == 0) ? next[v] : x; 41 | t = dfs_eul(x, v, t); 42 | } 43 | return out[v] = t; 44 | } 45 | 46 | void build(i64 r) { 47 | dfs_sz(r, -1); 48 | dfs_eul(r, -1, 0); 49 | } 50 | 51 | const vector& sequence() const { return seq; } 52 | i64 lca(i64 a, i64 b) const { 53 | while(true) { 54 | if(in[b] > in[a]) swap(a, b); 55 | if(next[b] == next[a]) return b; 56 | a = par[next[a]]; 57 | } 58 | } 59 | 60 | pair>, vector>> path(i64 a, i64 b, bool edge) const { 61 | vector> l, r; 62 | while(true) { 63 | if(in[b] > in[a]) { swap(a, b); swap(l, r); } 64 | if(next[b] == next[a]) { 65 | l.push_back({ in[b] + !!edge, in[a] + 1 }); 66 | break; 67 | } 68 | l.push_back({ in[next[a]], in[a] + 1 }); 69 | a = par[next[a]]; 70 | } 71 | return { std::move(l), std::move(r) }; 72 | } 73 | 74 | pair subtree(i64 v, bool edge) { return { in[v] + !!edge, out[v] }; } 75 | }; 76 | -------------------------------------------------------------------------------- /src/data_structures/union_find/persistent_union_find.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | struct partially_persistent_union_find { 6 | vector data; 7 | vector last; 8 | vector>> add; 9 | 10 | partially_persistent_union_find(int sz) : data(sz, -1), last(sz, 1e9), add(sz) { 11 | for(auto & vs: add) vs.push_back({ -1, -1 }); 12 | } 13 | 14 | i64 unite(i64 t, i64 x, i64 y) { 15 | x = find(t, x); 16 | y = find(t, y); 17 | if(x == y) return -1; 18 | if(data[x] > data[y]) swap(x, y); 19 | data[x] += data[y]; 20 | add[x].push_back({t, data[x]}); 21 | data[y] = x; 22 | last[y] = t; 23 | return x; 24 | } 25 | 26 | i64 find(i64 t, i64 x) { 27 | if(t < last[x]) return x; 28 | return find(t, data[x]); 29 | } 30 | 31 | i64 size(i64 t, i64 x) { 32 | x = find(t, x); 33 | return -prev(lower_bound(begin(add[x]), end(add[x]), make_pair(t, 0ll)))->second; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /src/data_structures/union_find/union_find.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct union_find { 5 | std::vector par; 6 | union_find(int N): par(N, -1) {} 7 | int root(int x) { 8 | return par[x] < 0 ? x : par[x] = root(par[x]); 9 | } 10 | std::tuple unite(int x, int y) { 11 | x = root(x); 12 | y = root(y); 13 | if(x == y) return { -1, -1 }; 14 | if(par[x] > par[y]) std::swap(x, y); 15 | par[x] += par[y]; 16 | par[y] = x; 17 | return { x, y }; 18 | } 19 | int size(int x) { 20 | return -par[root(x)]; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/data_structures/wavelet_matrix/plane_to_line.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct Compression { 6 | using size_type = std::size_t; 7 | 8 | std::vector v; 9 | 10 | Compression(){} 11 | void add(const T& t) { v.push_back(t); } 12 | void build() { 13 | sort(begin(v), end(v)); 14 | v.erase(unique(begin(v), end(v)), end(v)); 15 | } 16 | size_type comp(const T& x) const { 17 | return lower_bound(begin(v), end(v), x) - begin(v); 18 | } 19 | size_type size() const { return v.size(); } 20 | }; 21 | 22 | template 23 | struct plane_to_line { 24 | using size_type = std::size_t; 25 | using coord_type = std::pair; 26 | using value_type = T; 27 | 28 | std::vector> elems; 29 | std::vector yarray; 30 | std::vector xstart; 31 | Compression X, Y; 32 | 33 | plane_to_line(const std::vector& a): elems(a.size()) { 34 | for(size_type i = 0;i < a.size();i++) { 35 | elems[i] = { a[i], i }; 36 | X.add(a[i].first); 37 | Y.add(a[i].second); 38 | } 39 | sort(std::begin(elems), std::end(elems)); 40 | X.build(); 41 | Y.build(); 42 | 43 | xstart.resize(X.size() + 1); 44 | yarray.resize(elems.size()); 45 | size_type x = 0; 46 | for(size_type i = 0;i < elems.size();i++) { 47 | if(!i || elems[i - 1].first.first < elems[i].first.first) { 48 | xstart[x++] = i; 49 | } 50 | yarray[i] = Y.comp(elems[i].first.second); 51 | } 52 | xstart[X.size()] = elems.size(); 53 | } 54 | 55 | struct rangefreq_arg { 56 | size_type left; 57 | size_type right; 58 | size_type x; 59 | size_type y; 60 | }; 61 | 62 | rangefreq_arg to_rangefreq(value_type xl, value_type xr, value_type yl, value_type yr) const { 63 | size_type cxl = xstart[X.comp(xl)]; 64 | size_type cxr = xstart[X.comp(xr)]; 65 | size_type cyl = Y.comp(yl); 66 | size_type cyr = Y.comp(yr); 67 | return rangefreq_arg { cxl, cxr, cyl, cyr }; 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /src/data_structures/wavelet_matrix/wavelet_matrix.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using i64 = long long; 7 | 8 | class bitvector { 9 | using bit_type = std::uint_least64_t; 10 | using size_type = std::size_t; 11 | static constexpr size_type wordsize = 64; 12 | 13 | std::vector bit; 14 | std::vector sum; 15 | 16 | public: 17 | 18 | bitvector() : bit(), sum() {} 19 | bitvector(const size_type size) 20 | : bit(size / wordsize + 1, 0), sum(size / wordsize + 1, 0) {} 21 | 22 | void set(const size_type i) { 23 | bit[i / wordsize] |= static_cast(1) << (i % wordsize); 24 | } 25 | void build() { 26 | for (size_type i = 1; i < bit.size(); i++) { 27 | sum[i] = sum[i - 1] + __builtin_popcountll(bit[i - 1]); 28 | } 29 | } 30 | 31 | size_type at(const size_type i) const { 32 | return bit[i / wordsize] >> (i % wordsize); 33 | } 34 | 35 | // count of ones in [0, i) 36 | size_type rank(const size_type i) const { 37 | return sum[i / wordsize] 38 | + __builtin_popcountll(bit[i / wordsize] & (static_cast(1) << (i % wordsize)) - 1); 39 | } 40 | 41 | // count of ones in [0, i) 42 | size_type rank(const size_type i, const size_type b) const { 43 | size_type ans = sum[i / wordsize] 44 | + __builtin_popcountll(bit[i / wordsize] & (static_cast(1) << (i % wordsize)) - 1); 45 | if(b) return ans; 46 | else return i - ans; 47 | } 48 | }; 49 | 50 | class wavelet_matrix { 51 | using Integer = i64; 52 | using integer_type = Integer; 53 | using size_type = std::size_t; 54 | 55 | 56 | const size_type depth; 57 | const size_type len; 58 | std::vector mat; 59 | std::vector spl; 60 | 61 | public: 62 | 63 | wavelet_matrix(const std::vector& arr, size_type de) 64 | : depth(de), 65 | len(arr.size()), 66 | mat(std::vector(depth, bitvector(arr.size()))), 67 | spl(std::vector(depth, 0)) { 68 | std::vector idx(len); 69 | std::vector left(len), right(len); 70 | for(size_type i = 0;i < len;i++) idx[i] = i; 71 | for(size_type d = depth; d-- > 0;) { 72 | size_type l = 0, r = 0; 73 | 74 | for(size_type i = 0; i < len; i++) { 75 | size_type k = (arr[idx[i]] >> d) & 1; 76 | if(k) right[r++] = idx[i], mat[d].set(i); 77 | else left[l++] = idx[i]; 78 | } 79 | mat[d].build(); 80 | spl[d] = l; 81 | swap(idx, left); 82 | for(size_type i = 0; i < r; i++) idx[i + l] = right[i]; 83 | } 84 | } 85 | 86 | integer_type at(size_type i) const { 87 | integer_type x = static_cast(0); 88 | for(size_type d = depth; d-- > 0;) { 89 | size_type k = mat[d].at(i); 90 | x |= (static_cast(k) << d); 91 | i = mat[d].rank(i, k) + spl[d] * k; 92 | } 93 | return x; 94 | } 95 | 96 | // counting elements that equal to x in range [left, right) 97 | size_type rank_x(size_type left, size_type right, integer_type x) const { 98 | for(size_type d = depth; d-- > 0;) { 99 | size_type k = ((x >> d) & 1); 100 | left = mat[d].rank(left, k) + spl[d] * k; 101 | right = mat[d].rank(right, k) + spl[d] * k; 102 | } 103 | return right - left; 104 | } 105 | 106 | // sorted(arr[left..right])[i] 107 | integer_type quantile(size_type left, size_type right, size_type i) const { 108 | integer_type x = static_cast(0); 109 | for(size_type d = depth; d-- > 0;) { 110 | size_type cnt = mat[d].rank(right, 0) - mat[d].rank(left, 0); 111 | size_type k = (i < cnt) ? 0 : 1; 112 | if(k == 1) { 113 | i -= cnt; 114 | x |= (1 << d); 115 | } 116 | left = mat[d].rank(left, k) + spl[d] * k; 117 | right = mat[d].rank(right, k) + spl[d] * k; 118 | } 119 | return x; 120 | } 121 | 122 | struct rank_result { 123 | size_type le; 124 | size_type eq; 125 | size_type mo; 126 | }; 127 | 128 | // couting elements that less than x, equal to x, and more than x in range [left, right) 129 | rank_result rank_less_eq_more(size_type left, size_type right, integer_type x) const { 130 | size_type le = 0, mo = 0; 131 | for(size_type d = depth; d --> 0;) { 132 | size_type k = (x >> d) & 1; 133 | size_type l = mat[d].rank(left, 1); 134 | size_type r = mat[d].rank(right, 1); 135 | if(k == 0) { 136 | mo += r - l; 137 | left -= l; 138 | right -= r; 139 | } 140 | else { 141 | le += (right - left) - (r - l); 142 | left = l + spl[d]; 143 | right = r + spl[d]; 144 | } 145 | } 146 | return rank_result { le, right - left, mo }; 147 | } 148 | 149 | size_type rangefreq(size_type left, size_type right, integer_type x, integer_type y, integer_type l, size_type d) const { 150 | integer_type r = l + (1 << d); 151 | if(x <= l && r <= y) { 152 | return right - left; 153 | } 154 | else if(y <= l || r <= x) { 155 | return 0; 156 | } 157 | else { 158 | d--; 159 | size_type lr = mat[d].rank(left, 1); 160 | size_type rr = mat[d].rank(right, 1); 161 | return 162 | rangefreq(left - lr, right - rr, x, y, l, d) + 163 | rangefreq(lr + spl[d], rr + spl[d], x, y, l + (1 << d), d); 164 | } 165 | } 166 | 167 | size_type rangefreq(size_type left, size_type right, integer_type x, integer_type y) const { 168 | return rangefreq(left, right, x, y, 0, depth); 169 | } 170 | }; 171 | -------------------------------------------------------------------------------- /src/easydoc4lib.toml: -------------------------------------------------------------------------------- 1 | regex = "[.]*.hpp" 2 | out_dir = "../md2" 3 | -------------------------------------------------------------------------------- /src/geometry/geometry.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | using ld = long double; 8 | 9 | const ld EPS = 1e-8; 10 | inline bool eq(ld a, ld b) { return abs(a - b) < EPS; } 11 | const ld PI = acos(-1); 12 | 13 | namespace Geometory { 14 | struct Point { 15 | ld x, y; 16 | Point(ld x = 0, ld y = 0) : x(x), y(y) {} 17 | Point operator+(const Point& b) const { return Point(x + b.x, y + b.y); } 18 | Point operator-(const Point& b) const { return Point(x - b.x, y - b.y); } 19 | Point operator*(const ld b) const { return Point(x * b, y * b); } 20 | Point operator/(const ld b) const { return Point(x / b, y / b); } 21 | bool operator<(const Point& b) const { 22 | if (x != b.x) 23 | return x < b.x; 24 | else 25 | return y < b.y; 26 | } 27 | bool operator==(const Point& b) const { return eq(x, b.x) && eq(y, b.y); } 28 | ld norm() const { return x * x + y * y; } 29 | ld abs() const { return sqrt(norm()); } 30 | ld arg() const { return atan2(x, y); } 31 | Point rotate(const ld theta) const { 32 | ld co = cos(theta); 33 | ld si = sin(theta); 34 | return Point(co * x - si * y, si * x + y * co); 35 | } 36 | Point rotate90() const { return Point(-y, x); } 37 | }; 38 | 39 | ld dot(const Point& a, const Point& b) { return a.x * b.x + a.y * b.y; } 40 | ld cross(const Point& a, const Point b) { return a.x * b.y - a.y * b.x; } 41 | 42 | struct Line { 43 | Point from, to; 44 | Line(Point from = Point(), Point to = Point()) : from(from), to(to) {} 45 | }; 46 | 47 | struct Segment { 48 | Point from, to; 49 | Segment(Point from = Point(), Point to = Point()) : from(from), to(to) {} 50 | }; 51 | 52 | bool is_orthogonal(const Line& la, const Line& lb) { 53 | return eq(0.0, dot(la.from - la.to, lb.from - lb.from)); 54 | } 55 | bool is_parallel(const Line& la, const Line& lb) { 56 | return eq(0.0, cross(la.from - la.to, lb.from - lb.from)); 57 | } 58 | bool is_Point_on(const Line& l, const Point& p) { 59 | return eq(0.0, cross(l.to - l.from, p - l.from)); 60 | } 61 | bool is_Point_on(const Segment& s, const Point& p) { 62 | return (s.from - p).abs() + (p - s.to).abs() < (s.from - s.to).abs() + EPS; 63 | } 64 | ld distance(const Line& l, const Point& p) { 65 | return abs(cross(l.to - l.from, p - l.from)) / (l.to - l.from).abs(); 66 | } 67 | ld distance(const Segment& s, const Point& p) { 68 | if (dot(s.to - s.from, p - s.from) < EPS) return (p - s.from).abs(); 69 | if (dot(s.from - s.to, p - s.to) < EPS) return (p - s.to).abs(); 70 | return abs(cross(s.to - s.from, p - s.from)) / (s.to - s.from).abs(); 71 | } 72 | ld is_intersected(const Segment& a, const Segment& b) { 73 | return (cross(a.to - a.from, b.from - a.from) * 74 | cross(a.to - a.from, b.to - a.from) < 75 | EPS) && 76 | (cross(b.to - b.from, a.from - b.from) * 77 | cross(b.to - b.from, a.to - b.from) < 78 | EPS); 79 | } 80 | 81 | ld is_intersected(const Segment& s, const Line& l) { 82 | // line -> ax + by + c = 0 83 | ld a = l.to.y - l.from.y; 84 | ld b = l.from.x - l.to.x; 85 | ld c = -a * l.from.x - b * l.from.y; 86 | ld t1 = a * s.from.x + b * s.from.y + c; 87 | ld t2 = a * s.to.x + b * s.to.y + c; 88 | return t1 * t2 <= 0; 89 | } 90 | 91 | Point intersection_point(const Segment& a, const Segment& b) { 92 | Point bp = b.to - b.from; 93 | ld d1 = abs(cross(bp, a.from - b.from)); 94 | ld d2 = abs(cross(bp, a.to - b.from)); 95 | ld t = d1 / (d1 + d2); 96 | return a.from + (a.to - a.from) * t; 97 | } 98 | 99 | Point intersection_point(const Line& a, const Line& b) { 100 | Point ap = a.to - a.from; 101 | Point bp = b.to - b.from; 102 | return a.from + ap * cross(bp, b.from - a.from) / cross(bp, ap); 103 | } 104 | // counterclockwise 105 | int ccw(const Point& a, const Point& b, const Point& c) { 106 | Point ba = b - a; 107 | Point ca = c - a; 108 | if (cross(ba, ca) > EPS) return 1; // a - b --/ c 109 | if (cross(ba, ca) < EPS) return -1; // a - b --| c 110 | if (dot(ba, ca) < 0) return 2; // b - a - c 111 | if (b.norm() < c.norm()) return -2; // a - b - c 112 | return 0; // a -- c -- b 113 | } 114 | 115 | vector Convex_Hull(vector& p) { 116 | int n = p.size(); 117 | int k = 0; 118 | if (n >= 3) { 119 | sort(p.begin(), p.end()); 120 | vector ch(2 * n); 121 | for (int i = 0; i < n; ch[k++] = p[i++]) { 122 | while (k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) <= 0) 123 | k--; 124 | } 125 | for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) { 126 | while (k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) <= 0) 127 | k--; 128 | } 129 | ch.resize(k - 1); 130 | return ch; 131 | } else { 132 | return p; 133 | } 134 | } 135 | }; 136 | -------------------------------------------------------------------------------- /src/graph/centroid_decomposition.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | struct CentroidDecomposition { 5 | const G& g; 6 | std::vector deleted; 7 | std::vector sz; 8 | std::vector par; 9 | CentroidDecomposition(int N, const G& g): g(g), deleted(N, false), sz(N), par(N) {} 10 | int calc_size(int v, int p) { 11 | sz[v] = 1; 12 | for(int u: g[v]) { 13 | if(deleted[u] || u == p) continue; 14 | sz[v] += calc_size(u, v); 15 | } 16 | return sz[v]; 17 | } 18 | 19 | void centroid_build(int v, int p) { 20 | int tot = calc_size(v, -1); 21 | bool ok = false; 22 | int pp = -1; 23 | while(!ok) { 24 | ok = true; 25 | for(int u: g[v]) { 26 | if(!deleted[u] && u != pp && 2 * sz[u] > tot) { 27 | pp = v; 28 | v = u; 29 | ok = false; 30 | break; 31 | } 32 | } 33 | } 34 | par[v] = p; 35 | // operation 36 | deleted[v] = true; 37 | for(int u: g[v]) { 38 | if(!deleted[u]) { 39 | centroid_build(u, v); 40 | } 41 | } 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /src/graph/gabow_e_algorithm.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct edge { 9 | int to; 10 | int label; 11 | }; 12 | 13 | 14 | ::std::vector<::std::pair> gabow_edmonds(const ::std::vector<::std::vector>& gra){ 15 | // E0 - 初期化 16 | int N = gra.size(); 17 | ::std::vector<::std::vector> g(N + 1); 18 | ::std::vector<::std::pair> edges; 19 | { 20 | int cnt = N + 1; 21 | for(int i = 0;i < N;i++){ 22 | for(auto to : gra[i]){ 23 | if(i < to){ 24 | g[to + 1].push_back({i + 1, cnt}); 25 | g[i + 1].push_back({to + 1, cnt++}); 26 | edges.push_back({i + 1, to + 1}); 27 | } 28 | } 29 | } 30 | } 31 | ::std::vector mate(N + 1 , 0); 32 | ::std::vector label(N + 1 , -1); 33 | ::std::vector first(N + 1 , 0); 34 | ::std::queue que; 35 | 36 | // firstの遅延評価 37 | ::std::function eval_first = [&](int x){ 38 | if(label[first[x]] < 0) return first[x]; 39 | first[x] = eval_first(first[x]); 40 | return first[x]; 41 | }; 42 | 43 | // サブルーチンR 44 | ::std::function rematch = [&](int v, int w){ 45 | // R1 46 | int t = mate[v]; 47 | mate[v] = w; 48 | if(mate[t] != v) return; 49 | // R2 50 | if(label[v] <= N){ 51 | mate[t] = label[v]; 52 | rematch(label[v] , t); 53 | } 54 | // R3 55 | else{ 56 | int x = edges[label[v] - N - 1].first; 57 | int y = edges[label[v] - N - 1].second; 58 | rematch(x , y); 59 | rematch(y , x); 60 | } 61 | }; 62 | 63 | ::std::function assignLabel = [&](int x, int y, int num){ 64 | // L0 65 | int r = eval_first(x); 66 | int s = eval_first(y); 67 | int join = 0; 68 | if(r == s) return; 69 | // -numがフラグ 70 | label[r] = -num; 71 | label[s] = -num; 72 | while(true){ 73 | // L1 74 | if(s != 0) ::std::swap(r , s); 75 | // L2 76 | r = eval_first(label[mate[r]]); 77 | if(label[r] == -num){ 78 | join = r; 79 | break; 80 | } 81 | label[r] = -num; 82 | } 83 | // L3 84 | int v = first[x]; 85 | // L4 86 | while(v != join){ 87 | que.push(v); 88 | label[v] = num; 89 | first[v] = join; 90 | v = first[label[mate[v]]]; 91 | } 92 | // L3 93 | v = first[y]; 94 | // L4 95 | while(v != join){ 96 | que.push(v); 97 | label[v] = num; 98 | first[v] = join; 99 | v = first[label[mate[v]]]; 100 | } 101 | // L5は遅延評価しているため不要 102 | // L6 103 | return; 104 | }; 105 | 106 | ::std::function augment_check = [&](int u){ 107 | // E1 後半 108 | first[u] = 0; 109 | label[u] = 0; 110 | que.push(u); 111 | while(!que.empty()){ 112 | // E2 113 | int x = que.front(); 114 | que.pop(); 115 | for(auto e : g[x]){ 116 | int y = e.to; 117 | // E3 118 | if(mate[y] == 0 && y != u){ 119 | mate[y] = x; 120 | rematch(x , y); 121 | return true; 122 | } 123 | // E4 124 | else if(label[y] >= 0){ 125 | assignLabel(x , y , e.label); 126 | } 127 | // E5 128 | else if(label[mate[y]] < 0){ 129 | label[mate[y]] = x; 130 | first[mate[y]] = y; 131 | que.push(mate[y]); 132 | } 133 | // E6 134 | } 135 | } 136 | return false; 137 | }; 138 | 139 | for(int i = 1;i <= N;i++){ 140 | // E1 141 | que = ::std::queue(); 142 | if(mate[i] != 0) continue; 143 | if(augment_check(i)){ 144 | // E7 145 | ::std::fill(label.begin(), label.end(), -1); 146 | } 147 | } 148 | 149 | ::std::vector<::std::pair> ans; 150 | for(int i = 1;i <= N;i++){ 151 | if(i < mate[i]){ 152 | ans.push_back({i , mate[i]}); 153 | } 154 | } 155 | return ans; 156 | } 157 | -------------------------------------------------------------------------------- /src/graph/incremental_bridge_connectivity.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | struct union_find { 8 | std::vector par; 9 | union_find(int N): par(N, -1) {} 10 | int root(int x) { 11 | return par[x] < 0 ? x : par[x] = root(par[x]); 12 | } 13 | std::tuple unite(int x, int y) { 14 | x = root(x); 15 | y = root(y); 16 | if(x == y) return std::make_tuple(x, y); 17 | if(par[x] > par[y]) std::swap(x, y); 18 | par[x] += par[y]; 19 | par[y] = x; 20 | return std::make_tuple(x, y); 21 | } 22 | int size(int x) { 23 | return -par[root(x)]; 24 | } 25 | }; 26 | 27 | 28 | struct incremental_bridge_connectivity { 29 | static const int MAX_N = 202020; 30 | static const int MAX_E = 202020; 31 | std::vector par; 32 | std::vector> edge; 33 | std::bitset bit; 34 | std::bitset bridge; 35 | union_find cg; 36 | union_find bcg; 37 | 38 | incremental_bridge_connectivity(int N) 39 | : par(N, -1), cg(N), bcg(N) { 40 | } 41 | 42 | int lca(int u, int v) { 43 | bit = 0; 44 | while(1) { 45 | if(u >= 0) { 46 | if(bit.test(u)) { 47 | return u; 48 | } 49 | bit.set(u); 50 | if(par[u] < 0) u = -1; 51 | else u = edge[par[u]].second; 52 | } 53 | std::swap(u, v); 54 | } 55 | } 56 | 57 | void compress_path(int v, int w) { 58 | while(v != w) { 59 | bcg.unite(v, w); 60 | bridge.reset(par[v]); 61 | v = edge[par[v]].second; 62 | } 63 | } 64 | 65 | void reverse_path(int v, int p) { 66 | while(true) { 67 | std::swap(edge[p].first, edge[p].second); 68 | std::swap(p, par[v]); 69 | if(p < 0) break; 70 | v = edge[p].second; 71 | } 72 | } 73 | 74 | int add_edge(int u, int v) { 75 | int ei = edge.size(); 76 | edge.emplace_back(u, v); 77 | if(bcg.root(u) == bcg.root(v)) { 78 | } 79 | else if(cg.root(u) == cg.root(v)) { 80 | int w = lca(u, v); 81 | compress_path(u, w); 82 | compress_path(v, w); 83 | } 84 | else { 85 | bridge.set(ei); 86 | if(cg.size(u) < cg.size(v)) { 87 | std::swap(u, v); 88 | std::swap(edge.back().first, edge.back().second); 89 | } 90 | reverse_path(v, ei); 91 | cg.unite(u, v); 92 | } 93 | return ei; 94 | } 95 | 96 | int size(int v) { 97 | return bcg.size(v); 98 | } 99 | 100 | bool is_bridge(int ei) { 101 | return bridge.test(ei); 102 | } 103 | }; 104 | 105 | -------------------------------------------------------------------------------- /src/graph/lattice_graph.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using i64 = long long; 4 | 5 | template 6 | struct lattice_delta { 7 | i64 H, W; 8 | F f; 9 | using P = std::pair; 10 | lattice_delta(i64 H, i64 W, F f): H(H), W(W), f(f) {} 11 | template 12 | void operator()(P v, Func func) { 13 | const static std::vector dx { 1, 0, -1, 0 }; 14 | i64 i = v.first; 15 | i64 j = v.second; 16 | for(i64 q = 0; q < 4; q++) { 17 | i64 x = i + dx[q]; 18 | i64 y = j + dx[q ^ 1]; 19 | if(0 <= x && x < H && 0 <= y && y < W) { 20 | f(P(i, j), P(x, y), func); 21 | } 22 | } 23 | } 24 | }; 25 | 26 | template 27 | lattice_delta make_lattice_delta(i64 H, i64 W, F f) { return lattice_delta(H, W, f); } 28 | 29 | struct lattice_index { 30 | i64 H, W; 31 | using P = std::pair; 32 | lattice_index(i64 H, i64 W): H(H), W(W) {} 33 | i64 operator()(P v) { 34 | return v.first * W + v.second; 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /src/graph/max_flow/dinic.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct dinic { 5 | using cap_type = int; 6 | const cap_type INF = 1e9; 7 | struct edge { 8 | int to; 9 | cap_type cap; 10 | int rev; 11 | }; 12 | int n; 13 | std::vector> g; 14 | 15 | dinic(int n): n(n), g(n) {} 16 | 17 | void add_edge(int from, int to, cap_type cap, cap_type rev_cap = 0) { 18 | g[from].push_back({ to, cap, (int)(g[to].size()) }); 19 | g[to].push_back({ from, rev_cap, (int)(g[from].size() - 1) }); 20 | } 21 | 22 | std::vector level; 23 | std::vector iter; 24 | cap_type dfs(const int s, const int v, cap_type mf) { 25 | if(s == v || mf == 0) return mf; 26 | for(int& i = iter[v]; i < g[v].size(); i++) { 27 | int t = g[v][i].to; 28 | edge& re = g[v][i]; 29 | edge& e = g[t][re.rev]; 30 | if(level[t] >= level[v] || e.cap == 0) continue; 31 | cap_type f = dfs(s, t, std::min(mf, e.cap)); 32 | if(f == 0) continue; 33 | e.cap -= f; 34 | re.cap += f; 35 | return f; 36 | } 37 | return 0; 38 | } 39 | 40 | cap_type max_flow(int s, int t) { 41 | std::vector que(n); 42 | cap_type flow = 0; 43 | while(true) { 44 | level.assign(n, -1); 45 | int qi = 0; 46 | int qr = 0; 47 | level[s] = 0; 48 | que[qr++] = s; 49 | while(qi < qr && level[t]) { 50 | int v = que[qi++]; 51 | for(const auto& e: g[v]) { 52 | if(e.cap > 0 && level[e.to] == -1) { 53 | level[e.to] = level[v] + 1; 54 | que[qr++] = e.to; 55 | } 56 | } 57 | } 58 | if(level[t] == -1) break; 59 | iter.assign(n, 0); 60 | cap_type tmp; 61 | while((tmp = dfs(s, t, INF)) > 0) { 62 | flow += tmp; 63 | } 64 | } 65 | return flow; 66 | } 67 | }; 68 | -------------------------------------------------------------------------------- /src/graph/max_flow/goldberg_tarjan_global_relabeling.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct goldberg_tarjan { 5 | using cap_type = long long; 6 | struct edge { 7 | int to; 8 | cap_type cap; 9 | int rev; 10 | edge(int t, cap_type c, int r): to(t), cap(c), rev(r) {} 11 | }; 12 | 13 | int N; 14 | std::vector> G; 15 | std::vector exc; 16 | std::vector h; 17 | std::vector> que; 18 | std::vector qi; 19 | std::vector ei; 20 | const cap_type INF = 1e18; 21 | 22 | goldberg_tarjan(int n): N(n), G(n) {} 23 | 24 | void add_edge(int from, int to, cap_type cap, cap_type rev_cap = 0) { 25 | G[from].emplace_back(to, cap, (int)(G[to].size())); 26 | G[to].emplace_back(from, rev_cap, (int)(G[from].size() - 1)); 27 | } 28 | 29 | void push(int from, edge& e) { 30 | cap_type fl = std::min(exc[from], e.cap); 31 | e.cap -= fl; 32 | G[e.to][e.rev].cap += fl; 33 | exc[from] -= fl; 34 | exc[e.to] += fl; 35 | } 36 | 37 | void relabel(int v) { 38 | h[v] = N; 39 | for(int i = 0; i < G[v].size(); i++) { 40 | auto& e = G[v][i]; 41 | if(e.cap > 0 && h[v] > h[e.to] + 1) { 42 | ei[v] = i; 43 | h[v] = h[e.to] + 1; 44 | } 45 | } 46 | } 47 | 48 | std::vector Q; 49 | int global_relabeling(int t) { 50 | for(int i = 0;i < N;i++) { 51 | que[i].clear(); 52 | qi[i] = 0; 53 | ei[i] = 0; 54 | } 55 | int i = 0, qr = 0; 56 | Q[qr++] = t; 57 | h.assign(N, N); 58 | h[t] = 0; 59 | int hi = 0; 60 | while(i < qr) { 61 | int v = Q[i++]; 62 | hi = h[v]; 63 | if(exc[v] > 0 && v != t) { 64 | que[h[v]].push_back(v); 65 | } 66 | for(const auto& e: G[v]) { 67 | if(G[e.to][e.rev].cap > 0 && h[v] + 1 < h[e.to]) { 68 | h[e.to] = h[v] + 1; 69 | Q[qr++] = e.to; 70 | } 71 | } 72 | } 73 | return hi; 74 | } 75 | 76 | cap_type max_flow(int s, int t) { 77 | exc.assign(N, 0); 78 | exc[s] = INF; 79 | h.assign(N, 0); 80 | Q.resize(N); 81 | int cnt = 0; 82 | 83 | que.assign(N, std::vector()); 84 | qi.assign(N, 0); 85 | ei.assign(N, 0); 86 | 87 | global_relabeling(t); 88 | 89 | if(h[s] == N) return 0; 90 | 91 | for(int di = h[s]; di >= 0;) { 92 | if(qi[di] == que[di].size()) { di--; continue; } 93 | int v = que[di][qi[di]++]; 94 | if(exc[v] == 0 || v == t) continue; 95 | for(int& i = ei[v]; i < G[v].size(); i++) { 96 | auto& e = G[v][i]; 97 | if(e.cap > 0 && h[v] == h[e.to] + 1) { 98 | push(v, e); 99 | if(exc[e.to] > 0 && e.to != t) { 100 | que[h[e.to]].push_back(e.to); 101 | } 102 | if(exc[v] == 0) break; 103 | } 104 | } 105 | if(exc[v] == 0) continue; 106 | relabel(v); 107 | if(h[v] < N) { 108 | di = h[v]; 109 | que[h[v]].push_back(v); 110 | } 111 | 112 | if(++cnt % N == 0) { 113 | di = global_relabeling(t); 114 | } 115 | } 116 | return exc[t]; 117 | } 118 | }; 119 | -------------------------------------------------------------------------------- /src/graph/mcf/primal_dual.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using i64 = long long; 5 | 6 | struct dinic { 7 | using capacity_type = i64; 8 | struct edge { 9 | i64 from; 10 | i64 to; 11 | capacity_type cap; 12 | capacity_type cost; 13 | i64 rev; 14 | }; 15 | i64 n; 16 | i64 s, t; 17 | std::vector> g; 18 | 19 | dinic(i64 n, i64 s, i64 t): n(n), s(s), t(t), g(n) {} 20 | void add_edge(i64 from, i64 to, i64 cap, i64 cost) { 21 | g[from].push_back({ from, to, cap, cost, (i64)(g[to].size()) }); 22 | g[to].push_back({ to, from, 0, -cost, (i64)(g[from].size() - 1) }); 23 | } 24 | std::vector level; 25 | std::vector iter; 26 | capacity_type dinic_dfs(int v, capacity_type f) { 27 | if(v == t) return f; 28 | else { 29 | capacity_type now = f; 30 | for(int& i = iter[v]; i < g[v].size(); i++) { 31 | auto& e = g[v][i]; 32 | if(e.cap > 0 && level[e.to] > level[e.from]) { 33 | capacity_type c = std::min(now , e.cap); 34 | capacity_type d = dinic_dfs(e.to, c); 35 | e.cap -= d; 36 | g[e.to][e.rev].cap += d; 37 | now -= d; 38 | if(now == 0) return f - now; 39 | } 40 | } 41 | return f - now; 42 | } 43 | } 44 | 45 | capacity_type min_cost_flow(capacity_type f) { 46 | std::vector po(n,0); 47 | capacity_type ans = 0; 48 | auto sel = [&](const edge& e) { 49 | return e.cost + po[e.from] - po[e.to]; 50 | }; 51 | while(f > 0) { 52 | std::vector dist(n,0); 53 | std::vector vis(n,false); 54 | std::vector p(n,-1); 55 | std::vector pe(n,-1); 56 | using P = std::pair; 57 | std::priority_queue,std::greater

> que; 58 | que.push({dist[s] ,s}); 59 | vis[s] = true; 60 | while(!que.empty()) { 61 | int v = que.top().second; 62 | capacity_type d = que.top().first; 63 | que.pop(); 64 | if(dist[v] < d) continue; 65 | for(int i = 0;i < g[v].size();i++) { 66 | auto& e = g[v][i]; 67 | int u = e.to; 68 | if(e.cap == 0) continue; 69 | if(!vis[u] || dist[u] > dist[v] + sel(e)) { 70 | vis[u] = true; 71 | dist[u] = dist[v] + sel(e); 72 | p[u] = v; 73 | pe[u] = i; 74 | que.push({dist[u] , u}); 75 | } 76 | } 77 | } 78 | if(p[t] == -1) break; 79 | 80 | capacity_type ff = f; 81 | for(int u = t;u != s;u = p[u]) 82 | ff = std::min(ff, g[p[u]][pe[u]].cap); 83 | for(int u = t;u != s;u = p[u]) { 84 | ans += ff * g[p[u]][pe[u]].cost; 85 | g[p[u]][pe[u]].cap -= ff; 86 | g[u][g[p[u]][pe[u]].rev].cap += ff; 87 | } 88 | f -= ff; 89 | for(int i = 0;i < n;i++) 90 | po[i] += dist[i]; 91 | } 92 | if(f != 0) return -1; 93 | return ans; 94 | } 95 | }; 96 | 97 | -------------------------------------------------------------------------------- /src/graph/range_k_wall_graph.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** 4 | * # Range-K Wall Graph 5 | * 6 | * [ABC170F - Pond Skater](https://atcoder.jp/contests/abc170/tasks/abc170_f)で使ったテク 7 | * 8 | * - 各頂点から区間\\( K \\)の中にある頂点に辺を貼る. 9 | * - 貼るために必要な空間量は\\( O(N) \\) 10 | * - `[start, end)`の頂点で作る 11 | * 12 | * 13 | * 14 | **/ 15 | 16 | struct range_k_wall_graph_builder { 17 | int N; 18 | int start; 19 | int end; 20 | int K; 21 | 22 | /** 23 | * ## (constructor) 24 | * 25 | * ```cpp 26 | * @0@ 27 | * ``` 28 | * 29 | * - `N`: 貼りたい頂点の数 30 | * - `offset`: 新たに作る頂点番号の始めの番号(`start')を指定する 31 | * - `K`: 区間 32 | **/ 33 | range_k_wall_graph_builder(int N, int offset, int K) 34 | 35 | : N(N), 36 | start(offset), 37 | end(offset + N * 2), 38 | K(K) { 39 | } 40 | 41 | range_k_wall_graph_builder(){} 42 | 43 | /** 44 | * ## init 45 | * 46 | * ```cpp 47 | * @0@ 48 | * ``` 49 | * 50 | * ハシゴを作る. 51 | * 52 | * - `wall(v) -> bool`: 頂点番号を受け取り, 壁であればtrueを返す 53 | * - `idx(i) -> V`: 貼りたい頂点の数`N`に対応した頂点の番号を返す 54 | * - `con(v, w)`: `(v, w)`の辺を貼るというコールバック 55 | **/ 56 | template 57 | void init(Wall wall, Idx idx, Connect con) { 58 | for(int i = 0; i < N; i++) { 59 | int v = idx(i); 60 | if(wall(v)) continue; 61 | con(start + i, v); 62 | con(start + N + i, v); 63 | if(i + 1 < N && (i + 1) % K != 0) { 64 | con(start + i, start + i + 1); 65 | con(start + N + i + 1, start + N + i); 66 | } 67 | } 68 | } 69 | 70 | /** 71 | * ## build_for_right 72 | * 73 | * 各頂点\\(i (0 \leq i \le N)\\)から, \\([i, i + K]\\)に辺を貼る. 74 | * 75 | **/ 76 | template 77 | void build_for_right(Wall wall, Idx idx, Connect con) { 78 | int wi = N; 79 | for(int i = N; i --> 0;) { 80 | int v = idx(i); 81 | if(wall(v)) wi = i; 82 | else { 83 | con(v, start + i); 84 | int ni = std::min(i + K, wi - 1); 85 | if(i / K != ni / K) { 86 | con(v, start + N + ni); 87 | } 88 | } 89 | } 90 | } 91 | 92 | /** 93 | * ## build_for_right 94 | * 95 | * 各頂点\\(i (0 \leq i \le N)\\)から, \\([i - K, i]\\)に辺を貼る. 96 | * 97 | **/ 98 | template 99 | void build_for_left(Wall wall, Idx idx, Connect con) { 100 | int wi = -1; 101 | for(int i = 0; i < N; i++) { 102 | int v = idx(i); 103 | if(wall(v)) wi = i; 104 | else { 105 | con(v, start + N + i); 106 | int ni = std::max(i - K, wi + 1); 107 | if(i / K != ni / K) { 108 | con(v, start + ni); 109 | } 110 | } 111 | } 112 | } 113 | }; 114 | -------------------------------------------------------------------------------- /src/graph/sp/bfs.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using i64 = long long; 4 | 5 | /* 6 | * delta(V v, fn (V t)) 7 | * index(V v) -> int 8 | */ 9 | template 10 | std::vector bfs(std::size_t N, V s, Delta delta, Index index) { 11 | std::vector dist(N, -1); 12 | std::queue que; 13 | dist[index(s)] = 0; 14 | que.push(s); 15 | while(!que.empty()) { 16 | V v = que.front(); 17 | que.pop(); 18 | delta(v, [&](V t) { 19 | if(dist[index(t)] == -1) { 20 | dist[index(t)] = dist[index(v)] + 1; 21 | que.push(t); 22 | } 23 | }); 24 | } 25 | return dist; 26 | } 27 | -------------------------------------------------------------------------------- /src/graph/sp/dial01.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using i64 = long long; 4 | 5 | /* 6 | * delta(V v, fn (V t, i64 weight)) 7 | * index(V v) -> int 8 | */ 9 | template 10 | std::vector dial01(std::size_t N, W inf, V s, Delta delta, Index index) { 11 | std::vector dist(N, inf); 12 | using P = std::pair; 13 | std::deque

que; 14 | dist[index(s)] = 0; 15 | que.push_back({ s, dist[index(s)]}); 16 | while(!que.empty()) { 17 | V v = que.front().first; 18 | W d = que.front().second; 19 | que.pop_front(); 20 | if(dist[index(v)] < d) continue; 21 | delta(v, [&](V t, i64 weight) { 22 | if(dist[index(t)] > dist[index(v)] + weight) { 23 | dist[index(t)] = dist[index(v)] + weight; 24 | if(weight == 0) que.push_front({ t, dist[index(t)] }); 25 | else que.push_back({ t, dist[index(t)] }); 26 | } 27 | }); 28 | } 29 | return dist; 30 | } 31 | -------------------------------------------------------------------------------- /src/graph/sp/dijkstra.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * delta(V v, fn (V t, W weight)) 6 | * index(V v) -> int 7 | */ 8 | template 9 | std::vector dijkstra(std::size_t N, W inf, V s, Delta delta, Index index) { 10 | std::vector dist(N, inf); 11 | using P = std::pair; 12 | std::priority_queue, std::greater

> que; 13 | que.push({ dist[index(s)] = W(), s }); 14 | while(!que.empty()) { 15 | W d = que.top().first; 16 | V v = que.top().second; 17 | que.pop(); 18 | if(dist[index(v)] < d) continue; 19 | delta(v, [&](V t, W weight) { 20 | if(dist[index(t)] > dist[index(v)] + weight) { 21 | que.push({ dist[index(t)] = dist[index(v)] + weight, t }); 22 | } 23 | }); 24 | } 25 | return dist; 26 | } 27 | -------------------------------------------------------------------------------- /src/graph/strongly_connected_components.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct strongly_connected_components { 5 | std::vector> g; 6 | std::vector> rg; 7 | std::vector vis; 8 | std::vector vs; 9 | 10 | std::vector group; 11 | std::vector> comps; 12 | int groups; 13 | 14 | strongly_connected_components(int N): g(N), rg(N), vis(N, 0), group(N, -1) {} 15 | 16 | void add_edge(int a, int b) { 17 | g[a].push_back(b); 18 | rg[b].push_back(a); 19 | } 20 | 21 | void dfs(int v) { 22 | vis[v] = 1; 23 | for(auto& t: g[v]) { 24 | if(!vis[t]) dfs(t); 25 | } 26 | vs.push_back(v); 27 | } 28 | 29 | void rdfs(int v, int k) { 30 | vis[v] = 1; 31 | group[v] = k; 32 | comps.back().push_back(k); 33 | for(auto to: rg[v]) { 34 | if(!vis[to]) rdfs(to, k); 35 | } 36 | } 37 | 38 | void build() { 39 | for(int i = 0; i < g.size(); i++) { 40 | if(!vis[i]) dfs(i); 41 | } 42 | vis.assign(g.size(), false); 43 | groups = 0; 44 | for(int i = g.size(); i --> 0; ) { 45 | if(!vis[vs[i]]) { 46 | comps.push_back(std::vector()); 47 | rdfs(vs[i], groups++); 48 | } 49 | } 50 | } 51 | 52 | std::vector> build_compressed_graph() { 53 | std::vector> cg(groups); 54 | for(int i = 0; i < g.size(); i++) { 55 | for(auto& j: g[i]) { 56 | cg[group[i]].push_back(group[j]); 57 | } 58 | } 59 | return cg; 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /src/math/adjucency_matrix_equation.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct adjucency_matrix_equation { 5 | int V; 6 | int E; 7 | std::vector>> G; 8 | adjucency_matrix_equation(int n): V(n), E(0), G(n) {} 9 | 10 | void add_edge(int v, int u) { 11 | G[v].emplace_back(u + V, E); 12 | G[u].emplace_back(v, E); 13 | E++; 14 | } 15 | 16 | template 17 | std::vector solve(const std::vector& c) const { 18 | std::vector vis(V, 0); 19 | std::vector ans(E, 0); 20 | 21 | auto dfs = [&](auto f, int v) -> T { 22 | vis[v] = 1; 23 | T r = c[v]; 24 | for(auto e: G[v]) { 25 | int t = e.first; 26 | int ei = e.second; 27 | if(vis[t < V ? t : t - V]) continue; 28 | T y; 29 | if(t < V) ans[ei] = (y = f(f, t)); 30 | else ans[ei] = T(0) - (y = f(f, t - V)); 31 | r = r + y; 32 | } 33 | return r; 34 | }; 35 | 36 | for(int v = 0; v < V; v++) { 37 | if(vis[v]) continue; 38 | T y = dfs(dfs, v); 39 | if(y != T(0)) return std::vector(); 40 | } 41 | return ans; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /src/math/berlekamp_massey.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | std::vector berlekamp_massey(const std::vector& s) { 5 | int n = s.size(); 6 | std::vector b { F(1) }; 7 | std::vector c { F(1) }; 8 | F y(1); 9 | int shift = 0; 10 | for(int len = 0; len < n; len++) { 11 | shift++; 12 | F x(0); 13 | for(int i = 0; i < c.size(); i++) { 14 | x += c[i] * s[len - i]; 15 | } 16 | if(x == F(0)) { continue; } 17 | std::vector old_c = c; 18 | F freq = x / y; c.resize(std::max(c.size(), b.size() + shift), F(0)); 19 | for(int i = 0; i < b.size(); i++) { 20 | c[i + shift] -= freq * b[i]; 21 | } 22 | if(old_c.size() < c.size()) { 23 | b = std::move(old_c); 24 | y = x; 25 | shift = 0; 26 | } 27 | } 28 | std::vector ans(c.size() - 1); 29 | for(int i = 1; i < c.size(); i++) { 30 | ans[i - 1] = -c[i]; 31 | } 32 | return ans; 33 | } 34 | -------------------------------------------------------------------------------- /src/math/bin_matrix.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | struct bit_matrix { 7 | std::array, H> m; 8 | 9 | bit_matrix(){} 10 | 11 | std::bitset& operator[](int i) { return m[i]; } 12 | const std::bitset& operator[](int i) const { return m[i]; } 13 | 14 | template 15 | bit_matrix operator*(const bit_matrix& r) const { 16 | bit_matrix ans; 17 | bit_matrix tr; 18 | for(int i = 0;i < W;i++) for(int j = 0;j < X;j++) { 19 | if(r[i][j]) tr[j].set(i); 20 | } 21 | for(int i = 0;i < H;i++) for(int j = 0;j < X;j++) { 22 | ans[i][j] = (m[i] & tr[j]).count() & 1; 23 | } 24 | return ans; 25 | } 26 | }; 27 | 28 | template 29 | std::vector gauss_jordan(bit_matrix& A, bool is_extended = false) { 30 | int rank = 0; 31 | std::vector fst; 32 | for(int j = 0; j < W; j++) { 33 | if(is_extended && j + 1 == W) break; 34 | int pivot = -1; 35 | for(int i = rank; i < H; i++) { 36 | if(A[i].test(j)) { 37 | pivot = i; 38 | break; 39 | } 40 | } 41 | if(pivot == -1) continue; 42 | std::swap(A[rank], A[pivot]); 43 | for(int i = 0;i < H; i++) { 44 | if(i != rank && A[i][j]) { 45 | A[i] ^= A[rank]; 46 | } 47 | } 48 | fst.push_back(j); 49 | rank++; 50 | } 51 | return fst; 52 | } 53 | 54 | const int N_MAX = 200; 55 | const int W_MAX = N_MAX * N_MAX; 56 | 57 | #include 58 | using namespace std; 59 | using i64 = long long; 60 | #define rep(i,s,e) for(i64 (i) = (s);(i) < (e);(i)++) 61 | #define all(x) x.begin(),x.end() 62 | 63 | template 64 | static inline std::vector ndvec(size_t&& n, T val) noexcept { 65 | return std::vector(n, std::forward(val)); 66 | } 67 | 68 | template 69 | static inline auto ndvec(size_t&& n, Tail&&... tail) noexcept { 70 | return std::vector(tail)...))>(n, ndvec(std::forward(tail)...)); 71 | } 72 | 73 | template 74 | struct chain { 75 | Cond cond; chain(Cond cond) : cond(cond) {} 76 | bool operator()(T& a, const T& b) const { 77 | if(cond(a, b)) { a = b; return true; } 78 | return false; 79 | } 80 | }; 81 | template 82 | chain make_chain(Cond cond) { return chain(cond); } 83 | 84 | int main() { 85 | std::cin.tie(nullptr); 86 | std::ios::sync_with_stdio(false); 87 | 88 | int N, M; 89 | std::cin >> N >> M; 90 | 91 | std::vector> A(M); 92 | 93 | rep(ai,0,M) { 94 | rep(i,0,N) { 95 | string s; 96 | cin >> s; 97 | rep(j,0,N) { 98 | if(s[j] == '#') { 99 | A[ai].set(i * N + j); 100 | } 101 | } 102 | } 103 | } 104 | 105 | bit_matrix trans; 106 | 107 | int cnt = 0; 108 | rep(s,0,N) { 109 | rep(i,0,N) { 110 | trans[cnt][s * N + i] = 1; 111 | } 112 | cnt++; 113 | } 114 | rep(s,0,N) { 115 | rep(i,0,N) { 116 | trans[cnt][i * N + s] = 1; 117 | } 118 | cnt++; 119 | } 120 | rep(k, 0, N + N - 1) { 121 | // k = i + j 122 | rep(i,0,N) { 123 | int j = k - i; 124 | if(j >= N || j < 0) continue; 125 | trans[cnt][i * N + j] = 1; 126 | } 127 | cnt++; 128 | } 129 | rep(k,-N + 1, N) { 130 | // k = i - j 131 | rep(i,0,N) { 132 | int j = - k + i; 133 | if(j >= N || j < 0) continue; 134 | trans[cnt][i * N + j] = 1; 135 | } 136 | cnt++; 137 | } 138 | 139 | auto fst = gauss_jordan(trans); 140 | 141 | for(int i = 0; i < fst.size(); i++) { 142 | int f = fst[i]; 143 | //std::cout << f << " = " << trans[i] << "\n"; 144 | rep(j,0,M) { 145 | if(A[j][f]) { 146 | A[j] ^= trans[i]; 147 | } 148 | } 149 | } 150 | rep(i,0,M - 1) { 151 | rep(j,i + 1,M) { 152 | std::cout << (A[i] == A[j]); 153 | } 154 | std::cout << '\n'; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/math/binomial.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using i64 = long long; 4 | 5 | template 6 | struct binomial { 7 | const std::vector& fact; 8 | const std::vector& finv; 9 | binomial(const std::vector& fact, const std::vector& finv): fact(fact), finv(finv) {} 10 | 11 | T operator()(i64 n, i64 r) const { 12 | if(0 <= r && r <= n) return fact[n] * finv[n - r] * finv[r]; 13 | else return T(0); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /src/math/black_box_linear_algebra/fast_determinant.hpp: -------------------------------------------------------------------------------- 1 | #include "minimal_polynomial.hpp" 2 | #include 3 | #include 4 | 5 | template 6 | F fast_determinant_dense(std::vector> a, NonZeroRandGen rng) { 7 | int n = a.size(); 8 | std::vector d(n); 9 | F d_det(1); 10 | for(int i = 0; i < n; i++) { 11 | d[i] = rng(); 12 | d_det *= d[i]; 13 | } 14 | for(int i = 0; i < n; i++) { 15 | for(int j = 0; j < n; j++) { 16 | a[i][j] = a[i][j] * d[j]; 17 | } 18 | } 19 | auto c = find_minimal_polynomial_from_dense_matrix_pow2(a, rng); 20 | F det = c.back() / c.front(); 21 | det = n & 1 ? -det : det; 22 | return det / d_det; 23 | } 24 | 25 | template 26 | F fast_determinant_sparse(std::vector> a, int n, NonZeroRandGen rng) { 27 | std::vector d(n); 28 | F d_det(1); 29 | for(int i = 0; i < n; i++) { 30 | d[i] = rng(); 31 | d_det *= d[i]; 32 | } 33 | for(auto& [i, j, v]: a) { 34 | v *= d[j]; 35 | } 36 | auto c = find_minimal_polynomial_from_sparse_matrix_pow2(a, n, rng); 37 | F det = c.back() / c.front(); 38 | det = n & 1 ? -det : det; 39 | return det / d_det; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/math/black_box_linear_algebra/fast_matrix_pow.hpp: -------------------------------------------------------------------------------- 1 | #include "../fast_kitamasa.hpp" 2 | #include 3 | #include 4 | template 5 | std::vector bbla_dense_matrix_pow(const std::vector>& a, std::vector b, long long r, NonZeroRandGen rnd) { 6 | int n = a.size(); 7 | auto c = find_minimal_polynomial_from_dense_matrix_pow_b(a, b, rnd); 8 | auto d = fast_kitamasa(std::move(c), r); 9 | std::vector ans(n); 10 | std::vector bf; 11 | for(int i = 0; i < d.size(); i++) { 12 | for(int j = 0; j < n; j++) { 13 | ans[j] += d[d.size() - 1 - i] * b[j]; 14 | } 15 | if(i + 1 < d.size()) { 16 | bf = b; 17 | for(int j = 0; j < n; j++) { 18 | b[j] = F(0); 19 | for(int k = 0; k < n; k++) { 20 | b[j] += a[j][k] * bf[k]; 21 | } 22 | } 23 | } 24 | } 25 | return ans; 26 | } 27 | 28 | template 29 | std::vector bbla_sparse_matrix_pow(const std::vector>& a, std::vector b, long long r, NonZeroRandGen rnd) { 30 | int n = b.size(); 31 | auto c = find_minimal_polynomial_from_sparse_matrix_pow_b(a, b, n, rnd); 32 | auto d = fast_kitamasa(std::move(c), r); 33 | std::vector ans(n); 34 | std::vector bf; 35 | for(int i = 0; i < d.size(); i++) { 36 | for(int j = 0; j < n; j++) { 37 | ans[j] += d[d.size() - 1 - i] * b[j]; 38 | } 39 | if(i + 1 < d.size()) { 40 | bf = b; 41 | for(int j = 0; j < n; j++) { 42 | b[j] = F(0); 43 | } 44 | for(auto& [j, k, v]: a) { 45 | b[j] += v * bf[k]; 46 | } 47 | } 48 | } 49 | return ans; 50 | } 51 | -------------------------------------------------------------------------------- /src/math/black_box_linear_algebra/minimal_polynomial.hpp: -------------------------------------------------------------------------------- 1 | #include "../berlekamp_massey.hpp" 2 | #include 3 | 4 | template 5 | std::vector find_minimal_polynomial(const std::vector& a) { 6 | std::vector c = berlekamp_massey(a); 7 | c.insert(c.begin(), -F(1)); 8 | return c; 9 | } 10 | 11 | template 12 | std::vector find_minimal_polynomial_from_vector(int n, const std::vector>& a, NonZeroRandGen rnd) { 13 | std::vector u(n); 14 | for(int i = 0; i < n; i++) u[i] = rnd(); 15 | std::vector b(a.size(), F(0)); 16 | for(int i = 0; i < a.size(); i++) { 17 | for(int j = 0; j < n; j++) { 18 | b[i] += a[i][j] * u[j]; 19 | } 20 | } 21 | return find_minimal_polynomial(b); 22 | } 23 | 24 | template 25 | std::vector find_minimal_polynomial_from_dense_matrix_pow_b(const std::vector>& a, std::vector b, NonZeroRandGen rnd) { 26 | int n = a.size(); 27 | std::vector bf; 28 | 29 | std::vector u(n); 30 | for(int i = 0; i < n; i++) u[i] = rnd(); 31 | 32 | std::vector c(n * 2); 33 | for(int i = 0; i < 2 * n; i++) { 34 | for(int j = 0; j < n; j++) { 35 | c[i] += b[j] * u[j]; 36 | } 37 | if(i + 1 < 2 * n) { 38 | bf = b; 39 | for(int j = 0; j < n; j++) { 40 | b[j] = F(0); 41 | for(int k = 0; k < n; k++) { 42 | b[j] += a[j][k] * bf[k]; 43 | } 44 | } 45 | } 46 | } 47 | return find_minimal_polynomial(c); 48 | } 49 | 50 | // fast for dense matrix 51 | template 52 | std::vector find_minimal_polynomial_from_dense_matrix_pow(const std::vector>& a, NonZeroRandGen rnd) { 53 | int n = a.size(); 54 | std::vector b(n); 55 | for(int i = 0; i < n; i++) b[i] = rnd(); 56 | return find_minimal_polynomial_from_dense_matrix_pow_b(a, std::move(b), rnd); 57 | } 58 | 59 | #include 60 | 61 | template 62 | std::vector find_minimal_polynomial_from_sparse_matrix_pow_b(const std::vector>& a, std::vector b, int n, NonZeroRandGen rnd) { 63 | std::vector bf; 64 | 65 | std::vector u(n); 66 | for(int i = 0; i < n; i++) u[i] = rnd(); 67 | 68 | std::vector c(n * 2); 69 | for(int i = 0; i < 2 * n; i++) { 70 | for(int j = 0; j < n; j++) { 71 | c[i] += b[j] * u[j]; 72 | } 73 | if(i + 1 < 2 * n) { 74 | bf = b; 75 | for(int j = 0; j < n; j++) { 76 | b[j] = F(0); 77 | } 78 | for(auto& [j, k, v]: a) { 79 | b[j] += v * bf[k]; 80 | } 81 | } 82 | } 83 | return find_minimal_polynomial(c); 84 | } 85 | 86 | template 87 | std::vector find_minimal_polynomial_from_sparse_matrix_pow(const std::vector>& a, int n, NonZeroRandGen rnd) { 88 | std::vector b(n); 89 | for(int i = 0; i < n; i++) b[i] = rnd(); 90 | return find_minimal_polynomial_from_sparse_matrix_pow_b(a, std::move(b), n, rnd); 91 | } 92 | -------------------------------------------------------------------------------- /src/math/chinese_remainder_theorem.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | std::tuple ext_gcd(long long a, long long b) { 4 | if(b == 0ll) { 5 | return std::tuple{ a, 1ll, 0ll }; 6 | } 7 | else { 8 | auto [g, q, p] = ext_gcd(b, a%b); 9 | return std::tuple{ g, p, q-a/b*p }; 10 | } 11 | ; 12 | } 13 | std::tuple chinese_remainder_theorem(std::vector> const& tms) { 14 | long long r = 0ll; 15 | long long M = 1ll; 16 | for(auto [t, m]: tms) { 17 | auto [g, p, q] = ext_gcd(M, m); 18 | if((t-r)%g != 0ll) { 19 | return std::tuple{ 0ll, -1ll }; 20 | } 21 | ; 22 | long long tmp = (t-r)/g*p%(m/g); 23 | r = r+M*tmp; 24 | M = M*(m/g); 25 | }; 26 | return std::tuple{ (r%M+M)%M, M }; 27 | } 28 | -------------------------------------------------------------------------------- /src/math/convolution/divisor_transform.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | template 6 | void divisor_transform(vector &a) { 7 | int n = a.size(); 8 | vector sieve(n, true); 9 | for (int p = 2; p < n; ++p) { 10 | if (sieve[p]) { 11 | for (int k = 1; k * p < n; ++k) { 12 | sieve[k * p] = false; 13 | a[k * p] += a[k]; 14 | } 15 | } 16 | } 17 | for (int i = 0; ++i != n;) { 18 | a[i] += a[0]; 19 | } 20 | } 21 | 22 | template 23 | void inverse_divisor_transform(vector &a) { 24 | int n = a.size(); 25 | vector sieve(n, true); 26 | for (int i = 0; ++i != n;) { 27 | a[i] -= a[0]; 28 | } 29 | for (int p = 2; p < n; ++p) { 30 | if (sieve[p]) { 31 | for (int k = (n - 1) / p; k != 0; --k) { 32 | sieve[k * p] = false; 33 | a[k * p] -= a[k]; 34 | } 35 | } 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/math/convolution/fast_fourier_transform.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | using i64 = long long; 6 | 7 | const double pi = std::acos(-1); 8 | 9 | vector> fast_fourier_transform(vector> a) { 10 | i64 n = a.size(); 11 | for(i64 s = n >> 1; s >= 1; s >>= 1) { 12 | complex zeta = std::polar(1.0, 2 * pi / (double)(s << 1)); 13 | for(i64 i = 0;i < n;i += (s << 1)) { 14 | complex zi = 1.0; 15 | for(i64 j = 0;j < s;j++) { 16 | complex t = a[i + j] - a[s + i + j]; 17 | a[i + j] = a[i + j] + a[s + i + j]; 18 | a[s + i + j] = t * zi; 19 | zi = zi * zeta; 20 | } 21 | } 22 | } 23 | return a; 24 | } 25 | 26 | vector> inverse_fast_fourier_transform(vector> a) { 27 | i64 n = a.size(); 28 | for(i64 s = 1; s < n; s <<= 1) { 29 | complex zeta = std::polar(1.0, -1 * 2 * pi / (double)(s << 1)); 30 | for(i64 i = 0; i < n; i += (s << 1)) { 31 | complex zi = 1; 32 | for(i64 j = 0;j < s;j++) { 33 | complex t = a[s + i + j] * zi; 34 | a[s + i + j] = a[i + j] - t; 35 | a[i + j] = a[i + j] + t; 36 | zi = zi * zeta; 37 | } 38 | } 39 | } 40 | i64 inv_n = 1 / (double)n; 41 | for(int i = 0;i < n;i++) a[i] *= inv_n; 42 | return a; 43 | } 44 | -------------------------------------------------------------------------------- /src/math/convolution/multiple_transform.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | template 6 | void multiple_transform(vector &a) { 7 | int n = a.size(); 8 | vector sieve(n, true); 9 | for (int p = 2; p < n; ++p) { 10 | if (sieve[p]) { 11 | for (int k = (n - 1) / p; k != 0; --k) { 12 | sieve[k * p] = false; 13 | a[k] += a[k * p]; 14 | } 15 | } 16 | } 17 | for (int i = 0; ++i != n;) { 18 | a[i] += a[0]; 19 | } 20 | } 21 | 22 | template 23 | void inverse_multiple_transform(vector &a) { 24 | int n = a.size(); 25 | vector sieve(n, true); 26 | for (int i = 0; ++i != n;) { 27 | a[i] -= a[0]; 28 | } 29 | for (int p = 2; p < n; ++p) { 30 | if (sieve[p]) { 31 | for (int k = 1; k * p < n; ++k) { 32 | sieve[k * p] = false; 33 | a[k] -= a[k * p]; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/math/convolution/ntt4.hpp: -------------------------------------------------------------------------------- 1 | #include "../modint.hpp" 2 | #include 3 | using namespace std; 4 | using i64 = long long; 5 | 6 | 7 | constexpr i64 NTT_PRIMES[][2] = { 8 | {1224736769, 3}, // 2^24 * 73 + 1, 9 | {1053818881, 7}, // 2^20 * 3 * 5 * 67 + 1 10 | {1051721729, 6}, // 2^20 * 17 * 59 + 1 11 | {1045430273, 3}, // 2^20 * 997 + 1 12 | {1012924417, 5}, // 2^21 * 3 * 7 * 23 + 1 13 | {1007681537, 3}, // 2^20 * 31^2 + 1 14 | {1004535809, 3}, // 2^21 * 479 + 1 15 | {998244353, 3}, // 2^23 * 7 * 17 + 1 16 | {985661441, 3}, // 2^22 * 5 * 47 + 1 17 | {976224257, 3}, // 2^20 * 7^2 * 19 + 1 18 | {975175681, 17}, // 2^21 * 3 * 5 * 31 + 1 19 | {962592769, 7}, // 2^21 * 3^3 * 17 + 1 20 | {950009857, 7}, // 2^21 * 4 * 151 + 1 21 | {943718401, 7}, // 2^22 * 3^2 * 5^2 + 1 22 | {935329793, 3}, // 2^22 * 223 + 1 23 | {924844033, 5}, // 2^21 * 3^2 * 7^2 + 1 24 | {469762049, 3}, // 2^26 * 7 + 1 25 | {167772161, 3}, // 2^25 * 5 + 1 26 | }; 27 | 28 | template 29 | vector> number_theoretic_transform4(vector> a) { 30 | i64 n = a.size(); 31 | vector> b(a.size()); 32 | auto unit_i = modint(primitive).pow((mod - 1) / 4); 33 | for(i64 s = 1, m = n; s < n; s <<= 1, m >>= 1) { 34 | if(m == 2) { 35 | for(i64 j = 0;j < s;j++) { 36 | auto x = a[j + 0]; 37 | auto y = a[j + s]; 38 | b[j + 0] = x + y; 39 | b[j + s] = x - y; 40 | } 41 | } 42 | else { 43 | modint zi1 = 1; 44 | modint zi2 = 1; 45 | modint zi3 = 1; 46 | i64 m1 = m >> 2; 47 | i64 m2 = m >> 1; 48 | i64 m3 = m1 | m2; 49 | modint zeta = modint(primitive).pow((mod - 1) / m); 50 | for(i64 i = 0;i < m1;i++) { 51 | for(i64 j = 0;j < s;j++) { 52 | auto w = a[j + s * (i + 0)]; 53 | auto x = a[j + s * (i + m1)]; 54 | auto y = a[j + s * (i + m2)]; 55 | auto z = a[j + s * (i + m3)]; 56 | auto wy1 = w + y; 57 | auto wy2 = w - y; 58 | auto xz1 = x + z; 59 | auto xz2 = (x - z) * unit_i; 60 | b[j + s * (4 * i + 0)] = wy1 + xz1; 61 | b[j + s * (4 * i + 1)] = (wy2 + xz2) * zi1; 62 | b[j + s * (4 * i + 2)] = (wy1 - xz1) * zi2; 63 | b[j + s * (4 * i + 3)] = (wy2 - xz2) * zi3; 64 | } 65 | zi1 = zi1 * zeta; 66 | zi2 = zi1 * zi1; 67 | zi3 = zi1 * zi2; 68 | } 69 | s <<= 1; 70 | m >>= 1; 71 | } 72 | swap(a, b); 73 | } 74 | return a; 75 | } 76 | 77 | template 78 | vector> inverse_number_theoretic_transform4(vector> a) { 79 | i64 n = a.size(); 80 | vector> b(a.size()); 81 | auto unit_i = modint(primitive).pow((mod - 1) / 4).inv(); 82 | i64 s = n; 83 | i64 m = 1; 84 | if(__builtin_ctzll(n) & 1) { 85 | s >>= 1; 86 | m <<= 1; 87 | for(i64 j = 0;j < s;j++) { 88 | auto x = a[j + 0]; 89 | auto y = a[j + s]; 90 | b[j + 0] = x + y; 91 | b[j + s] = x - y; 92 | } 93 | swap(a, b); 94 | } 95 | for(; s >>= 2, m <<= 2, s >= 1;) { 96 | { 97 | modint zi1 = 1; 98 | modint zi2 = 1; 99 | modint zi3 = 1; 100 | i64 m1 = m >> 2; 101 | i64 m2 = m >> 1; 102 | i64 m3 = m1 | m2; 103 | modint zeta = modint(primitive).pow((mod - 1) / m).inv(); 104 | for(i64 i = 0;i < m1;i++) { 105 | for(i64 j = 0;j < s;j++) { 106 | auto w = a[j + s * (4 * i + 0)]; 107 | auto x = a[j + s * (4 * i + 1)] * zi1; 108 | auto y = a[j + s * (4 * i + 2)] * zi2; 109 | auto z = a[j + s * (4 * i + 3)] * zi3; 110 | auto wy1 = w + y; 111 | auto wy2 = x + z; 112 | auto xz1 = w - y; 113 | auto xz2 = (x - z) * unit_i; 114 | b[j + s * (i + 0)] = wy1 + wy2; 115 | b[j + s * (i + m1)] = xz1 + xz2; 116 | b[j + s * (i + m2)] = wy1 - wy2; 117 | b[j + s * (i + m3)] = xz1 - xz2; 118 | } 119 | zi1 = zi1 * zeta; 120 | zi2 = zi1 * zi1; 121 | zi3 = zi1 * zi2; 122 | } 123 | } 124 | swap(a, b); 125 | } 126 | auto inv_n = modint(n).pow(mod - 2); 127 | for(int i = 0;i < n;i++) a[i] *= inv_n; 128 | return a; 129 | } 130 | -------------------------------------------------------------------------------- /src/math/convolution/ntt_stockham.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | template 6 | struct modint { 7 | i64 a; 8 | constexpr modint(const i64 x = 0) noexcept: a((x % M + M) % M) {} 9 | constexpr i64 value() const noexcept { return a; } 10 | constexpr modint pow(i64 r) const noexcept { 11 | modint ans(1); 12 | modint aa = *this; 13 | while(r) { 14 | if(r & 1) { 15 | ans *= aa; 16 | } 17 | aa *= aa; 18 | r >>= 1; 19 | } 20 | return ans; 21 | } 22 | constexpr modint& operator+=(const modint r) noexcept { 23 | a += r.a; 24 | if(a >= M) a -= M; 25 | return *this; 26 | } 27 | constexpr modint& operator=(const i64 r) { 28 | a = (r % M + M) % M; 29 | return *this; 30 | } 31 | constexpr modint& operator-=(const modint r) noexcept { 32 | a -= r.a; 33 | if(a < 0) a += M; 34 | return *this; 35 | } 36 | constexpr modint& operator*=(const modint r) noexcept { 37 | a = a * r.a % M; 38 | return *this; 39 | } 40 | constexpr modint& operator/=(modint r) noexcept { 41 | i64 ex = M - 2; 42 | while(ex) { 43 | if(ex & 1) { 44 | *this *= r; 45 | } 46 | r *= r; 47 | ex >>= 1; 48 | } 49 | return *this; 50 | } 51 | 52 | constexpr modint operator+(const modint r) const { 53 | return modint(*this) += r; 54 | } 55 | constexpr modint operator-(const modint r) const { 56 | return modint(*this) -= r; 57 | } 58 | constexpr modint operator*(const modint r) const { 59 | return modint(*this) *= r; 60 | } 61 | constexpr modint operator/(const modint r) const { 62 | return modint(*this) /= r; 63 | } 64 | 65 | constexpr bool operator!=(const modint r) const { 66 | return this->value() != r.value(); 67 | } 68 | 69 | }; 70 | 71 | constexpr i64 NTT_PRIMES[][2] = { 72 | {1224736769, 3}, // 2^24 * 73 + 1, 73 | {1053818881, 7}, // 2^20 * 3 * 5 * 67 + 1 74 | {1051721729, 6}, // 2^20 * 17 * 59 + 1 75 | {1045430273, 3}, // 2^20 * 997 + 1 76 | {1012924417, 5}, // 2^21 * 3 * 7 * 23 + 1 77 | {1007681537, 3}, // 2^20 * 31^2 + 1 78 | {1004535809, 3}, // 2^21 * 479 + 1 79 | {998244353, 3}, // 2^23 * 7 * 17 + 1 80 | {985661441, 3}, // 2^22 * 5 * 47 + 1 81 | {976224257, 3}, // 2^20 * 7^2 * 19 + 1 82 | {975175681, 17}, // 2^21 * 3 * 5 * 31 + 1 83 | {962592769, 7}, // 2^21 * 3^3 * 17 + 1 84 | {950009857, 7}, // 2^21 * 4 * 151 + 1 85 | {943718401, 7}, // 2^22 * 3^2 * 5^2 + 1 86 | {935329793, 3}, // 2^22 * 223 + 1 87 | {924844033, 5}, // 2^21 * 3^2 * 7^2 + 1 88 | {469762049, 3}, // 2^26 * 7 + 1 89 | {167772161, 3}, // 2^25 * 5 + 1 90 | }; 91 | 92 | template 93 | vector> number_theoretic_transform(vector> a) { 94 | i64 n = a.size(); 95 | vector> b(a.size()); 96 | for(i64 s = 1; s < n; s <<= 1) { 97 | i64 m = n / 2 / s; 98 | modint zeta = modint(primitive).pow((mod - 1) / (m << 1)); 99 | modint zi = 1; 100 | for(i64 i = 0;i < m;i++) { 101 | for(i64 j = 0;j < s;j++) { 102 | auto x = a[j + s * (i + 0)]; 103 | auto y = a[j + s * (i + m)]; 104 | b[j + s * (2 * i + 0)] = x + y; 105 | b[j + s * (2 * i + 1)] = (x - y) * zi; 106 | } 107 | zi = zi * zeta; 108 | } 109 | swap(a, b); 110 | } 111 | return a; 112 | } 113 | 114 | template 115 | vector> inverse_number_theoretic_transform(vector> a) { 116 | i64 n = a.size(); 117 | vector> b(a.size()); 118 | for(i64 s = n; s >>= 1, s >= 1;) { 119 | i64 m = n / 2 / s; 120 | modint zeta = modint(primitive).pow((mod - 1) / (m << 1)).pow(mod - 2); 121 | modint zi = 1; 122 | for(i64 i = 0;i < m;i++) { 123 | for(i64 j = 0;j < s;j++) { 124 | auto x = a[j + s * (2 * i + 0)]; 125 | auto y = a[j + s * (2 * i + 1)] * zi; 126 | b[j + s * (i + 0)] = x + y; 127 | b[j + s * (i + m)] = x - y; 128 | } 129 | zi = zi * zeta; 130 | } 131 | swap(a, b); 132 | } 133 | auto inv_n = modint(n).pow(mod - 2); 134 | for(int i = 0;i < n;i++) a[i] *= inv_n; 135 | return a; 136 | } 137 | -------------------------------------------------------------------------------- /src/math/convolution/number_theoretic_transform.hpp: -------------------------------------------------------------------------------- 1 | #include "../modint.hpp" 2 | #include 3 | using namespace std; 4 | constexpr i64 NTT_PRIMES[][2] = { 5 | {1224736769, 3}, // 2^24 * 73 + 1, 6 | {1053818881, 7}, // 2^20 * 3 * 5 * 67 + 1 7 | {1051721729, 6}, // 2^20 * 17 * 59 + 1 8 | {1045430273, 3}, // 2^20 * 997 + 1 9 | {1012924417, 5}, // 2^21 * 3 * 7 * 23 + 1 10 | {1007681537, 3}, // 2^20 * 31^2 + 1 11 | {1004535809, 3}, // 2^21 * 479 + 1 12 | {998244353, 3}, // 2^23 * 7 * 17 + 1 13 | {985661441, 3}, // 2^22 * 5 * 47 + 1 14 | {976224257, 3}, // 2^20 * 7^2 * 19 + 1 15 | {975175681, 17}, // 2^21 * 3 * 5 * 31 + 1 16 | {962592769, 7}, // 2^21 * 3^3 * 17 + 1 17 | {950009857, 7}, // 2^21 * 4 * 151 + 1 18 | {943718401, 7}, // 2^22 * 3^2 * 5^2 + 1 19 | {935329793, 3}, // 2^22 * 223 + 1 20 | {924844033, 5}, // 2^21 * 3^2 * 7^2 + 1 21 | {469762049, 3}, // 2^26 * 7 + 1 22 | {167772161, 3}, // 2^25 * 5 + 1 23 | }; 24 | 25 | template 26 | vector> number_theoretic_transform(vector> a) { 27 | i64 n = a.size(); 28 | for(i64 s = n >> 1; s >= 1; s >>= 1) { 29 | modint zeta = modint(primitive).pow((mod - 1) / (s << 1)); 30 | for(i64 i = 0; i < n; i += (s << 1)) { 31 | modint zi = 1; 32 | for(i64 j = 0;j < s;j++) { 33 | modint t = a[i + j] - a[s + i + j]; 34 | a[i + j] += a[s + i + j]; 35 | a[s + i + j] = t * zi; 36 | zi = zi * zeta; 37 | } 38 | } 39 | } 40 | return a; 41 | } 42 | 43 | template 44 | vector> inverse_number_theoretic_transform(vector> a) { 45 | i64 n = a.size(); 46 | for(i64 s = 1; s < n; s <<= 1) { 47 | modint zeta = modint(primitive).pow((mod - 1) / (s << 1)).pow(mod - 2); 48 | for(i64 i = 0; i < n; i += (s << 1)) { 49 | modint zi = 1; 50 | for(i64 j = 0;j < s;j++) { 51 | modint t = a[s + i + j] * zi; 52 | a[s + i + j] = a[i + j] - t; 53 | a[i + j] = a[i + j] + t; 54 | zi = zi * zeta; 55 | } 56 | } 57 | } 58 | auto inv_n = modint(n).pow(mod - 2); 59 | for(int i = 0;i < n;i++) a[i] *= inv_n; 60 | return a; 61 | } 62 | -------------------------------------------------------------------------------- /src/math/convolution/zeta_mobius_transform.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** 4 | * 5 | * # Zeta and Mobius Transform 6 | * 7 | * ## superset_zeta_transform 8 | * 9 | * 上位集合に対して累積するゼータ変換 10 | * 11 | * \\[ g(S) := \sum_{T \supseteq S} f(T) \\] 12 | * 13 | **/ 14 | template 15 | void superset_zeta_transform(int n, std::vector& a) { 16 | for (int k = 0; k < n; ++k) { 17 | for (int s = 0; s < (1 << n); ++s) { 18 | if (!((s >> k) & 1)) { 19 | a[s] += a[s ^ (1 << k)]; 20 | } 21 | } 22 | } 23 | } 24 | 25 | /** 26 | * ## subset_zeta_transform 27 | * 28 | * 下位集合に対して累積するゼータ変換 29 | * 30 | * \\[ g(S) := \sum_{T \subseteq S} f(T) \\] 31 | * 32 | **/ 33 | template 34 | void subset_zeta_transform(int n, std::vector& a) { 35 | for (int k = 0; k < n; ++k) { 36 | for (int s = 0; s < (1 << n); ++s) { 37 | if (((s >> k) & 1)) { 38 | a[s] += a[s ^ (1 << k)]; 39 | } 40 | } 41 | } 42 | } 43 | 44 | /** 45 | * ## superset_mobius_transform 46 | * 47 | * 上位集合に対してのメビウス変換 48 | * 49 | * \\[ g(S) := \sum_{T \supseteq S} (-1) ^ {|T| - |S|} f(T) \\] 50 | * 51 | **/ 52 | template 53 | void superset_mobius_transform(int n, std::vector& a) { 54 | for (int k = 0; k < n; ++k) { 55 | for (int s = 0; s < (1 << n); ++s) { 56 | if (!((s >> k) & 1)) { 57 | a[s] -= a[s ^ (1 << k)]; 58 | } 59 | } 60 | } 61 | } 62 | 63 | /** 64 | * ## subset_zeta_transform 65 | * 66 | * 下位集合に対してのメビウス変換 67 | * 68 | * \\[ g(S) := \sum_{T \subseteq S} (-1) ^ {|S| - |T|} f(T) \\] 69 | * 70 | **/ 71 | template 72 | void subset_mobius_transform(int n, std::vector& a) { 73 | for (int k = 0; k < n; ++k) { 74 | for (int s = 0; s < (1 << n); ++s) { 75 | if (((s >> k) & 1)) { 76 | a[s] -= a[s ^ (1 << k)]; 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/math/factorial.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using i64 = long long; 4 | 5 | template 6 | struct factorial { 7 | std::vector fact; 8 | std::vector finv; 9 | std::vector inv; 10 | 11 | void build(int N) { 12 | fact.resize(N); 13 | finv.resize(N); 14 | inv.resize(N); 15 | fact[0] = T(1); 16 | for(int i = 1;i < N;i++) { 17 | fact[i] = fact[i - 1] * T(i); 18 | } 19 | finv[N - 1] = T(1) / fact[N - 1]; 20 | for(int i = N - 1; i --> 0;) { 21 | finv[i] = finv[i + 1] * T(i + 1); 22 | } 23 | for(int i = 0;i < N;i++) { 24 | inv[i] = fact[i - 1] * finv[i]; 25 | } 26 | } 27 | 28 | T binom(int n, int r) const { 29 | if(0 <= r && r <= n) return fact[n] * finv[n - r] * finv[r]; 30 | else return T(0); 31 | } 32 | 33 | std::tuple&, const std::vector&, const std::vector&> get() const { 34 | return std::tuple&, const std::vector&, const std::vector&>(fact, finv, inv); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /src/math/fast_kitamasa.hpp: -------------------------------------------------------------------------------- 1 | #include "formal_power_series.hpp" 2 | #include 3 | using i64 = long long; 4 | 5 | template 6 | std::vector fast_kitamasa(std::vector c, i64 n) { 7 | using fps = FPS; 8 | i64 k = c.size() - 1; 9 | fps cf(std::move(c)); 10 | fps ic = cf.inv(k - 1); 11 | 12 | i64 c_len = bound_pow2(k - 1 + cf.size() - 1); 13 | i64 ic_len = bound_pow2(k - 1 + ic.size() - 1); 14 | auto dc = cf.resized(c_len).dft(c_len); 15 | auto dic = std::move(ic).dft(ic_len); 16 | 17 | i64 b_len = bound_pow2(k); 18 | fps b(std::vector(b_len, F(0))); 19 | b[k - 1] = F(1); 20 | i64 m = bound_pow2(n); 21 | while(m) { 22 | auto bt = std::move(b).dft(b_len * 2); 23 | bt *= bt; 24 | auto beta = std::move(bt).idft(); 25 | 26 | auto dbeta = beta.resized(k - 1).dft(ic_len); 27 | auto q = std::move(dbeta *= dic).idft(c_len); 28 | for(int i = k - 1; i < c_len; i++) q[i] = F(0); 29 | fps cfq = std::move(std::move(q).dft(c_len) *= dc).idft(k - 1 + cf.size() - 1); 30 | beta -= cfq; 31 | 32 | b = fps(std::vector(b_len * 2)); 33 | for(int i = k - 1; i < 2 * k - 1; i++) { 34 | b[i - (k - 1)] = beta[i]; 35 | } 36 | if(m & n) { 37 | F freq = b[0]; 38 | for(int i = 0; i < k - 1; i++) { 39 | b[i] = b[i + 1] + freq * cf[i + 1]; 40 | } 41 | b[k - 1] = freq * cf[k]; 42 | } 43 | m >>= 1; 44 | } 45 | b.resize(k); 46 | return std::move(b.coef); 47 | } 48 | -------------------------------------------------------------------------------- /src/math/formal_power_series.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using i64 = long long; 3 | 4 | std::size_t bound_pow2(std::size_t sz) { 5 | return 1ll << (std::__lg(sz - 1) + 1); 6 | } 7 | 8 | template 9 | struct FPS { 10 | struct DFT { 11 | using C = typename fps_multiply::conv_type; 12 | std::vector coef; 13 | DFT(std::vector c): coef(std::move(c)) {} 14 | DFT clone() const { 15 | return DFT(coef); 16 | } 17 | std::size_t size() const { 18 | return coef.size(); 19 | } 20 | C& operator[](int i) { 21 | return coef[i]; 22 | } 23 | const C& operator[](int i) const { 24 | return coef[i]; 25 | } 26 | DFT& operator+=(const DFT& r) { 27 | assert(coef.size() == r.size()); 28 | for(int i = 0;i < coef.size(); i++) { 29 | coef[i] += r[i]; 30 | } 31 | return (*this); 32 | } 33 | DFT& operator-=(const DFT& r) { 34 | assert(coef.size() == r.size()); 35 | for(int i = 0;i < coef.size(); i++) { 36 | coef[i] -= r[i]; 37 | } 38 | return (*this); 39 | } 40 | DFT& operator*=(const DFT& r) { 41 | assert(coef.size() == r.size()); 42 | for(int i = 0;i < coef.size(); i++) { 43 | coef[i] *= r[i]; 44 | } 45 | return (*this); 46 | } 47 | DFT& operator*=(const C& t) { 48 | for(int i = 0; i < coef.size(); i++) { 49 | coef[i] *= t; 50 | } 51 | return (*this); 52 | } 53 | DFT operator+(const DFT& r) const { return DFT(*this) += r; } 54 | DFT operator-(const DFT& r) const { return DFT(*this) -= r; } 55 | DFT operator*(const DFT& r) const { return DFT(*this) *= r; } 56 | DFT operator*(const C& r) const { return DFT(*this) *= r; } 57 | FPS idft(int n = -1) && { 58 | auto res = fps_multiply::idft(std::move(coef)); 59 | if(n > 0) { 60 | res.resize(n); 61 | } 62 | return FPS(std::move(res)); 63 | } 64 | }; 65 | using T = typename fps_multiply::fps_type; 66 | std::vector coef; 67 | FPS(std::vector f): coef(std::move(f)) {} 68 | void resize(int n) { coef.resize(n, T(0)); } 69 | FPS resized(int n) const { 70 | std::vector res(n); 71 | for(int i = 0;i < n && i < coef.size();i++) res[i] = coef[i]; 72 | return FPS(std::move(res)); 73 | } 74 | FPS clone() const { 75 | return FPS(coef); 76 | } 77 | std::size_t size() const { 78 | return coef.size(); 79 | } 80 | T& operator[](int i) { 81 | return coef[i]; 82 | } 83 | const T& operator[](int i) const { 84 | return coef[i]; 85 | } 86 | FPS& operator+=(const FPS& r) { 87 | if(coef.size() < r.size()) coef.resize(r.size()); 88 | for(int i = 0;i < coef.size() && i < r.size(); i++) { 89 | coef[i] += r[i]; 90 | } 91 | return (*this); 92 | } 93 | FPS& operator-=(const FPS& r) { 94 | if(coef.size() < r.size()) coef.resize(r.size()); 95 | for(int i = 0;i < coef.size() && i < r.size(); i++) { 96 | coef[i] -= r[i]; 97 | } 98 | return (*this); 99 | } 100 | FPS& operator*=(const T& t) { 101 | for(int i = 0; i < coef.size(); i++) { 102 | coef[i] *= t; 103 | } 104 | } 105 | FPS operator+(const FPS& r) const { return FPS(*this) += r; } 106 | FPS operator-(const FPS& r) const { return FPS(*this) -= r; } 107 | FPS operator*(const T& r) const { return FPS(*this) *= r; } 108 | DFT dft(int n) && { 109 | assert(!(n & (n - 1))); 110 | coef.resize(n); 111 | return DFT(fps_multiply::dft(std::move(coef))); 112 | } 113 | 114 | FPS inv(int n) const { 115 | FPS g = FPS(std::vector{ T(1) / (*this)[0] }); 116 | for(int i = 1;i < n;i <<= 1) { 117 | DFT gdft = g.resized(i << 1).dft(i << 1); 118 | FPS e = (gdft * this->resized(i << 1).dft(i << 1)).idft(); 119 | for(int j = 0;j < i;j++) { 120 | e[j] = T(0); 121 | e[j + i] = e[j + i] * T(-1); 122 | } 123 | FPS f = std::move(gdft *= std::move(e).dft(i << 1)).idft(); 124 | for(int j = 0;j < i;j++) { 125 | f[j] = g[j]; 126 | } 127 | g = std::move(f); 128 | } 129 | g.resize(n); 130 | return g; 131 | } 132 | 133 | FPS diff(int n) const { 134 | std::vector res(n); 135 | for(int i = 0; i + 1 < this->size() && i < n; i++) { 136 | res[i] = coef[i + 1] * T(i + 1); 137 | } 138 | return FPS(std::move(res)); 139 | } 140 | 141 | FPS integral(int n) const { 142 | std::vector res(n); 143 | int m = std::min(n, int(coef.size() + 1)); 144 | res[0] = T(1); 145 | for(int i = 1; i < m; i++) { 146 | res[i] = res[i - 1] * T(i); 147 | } 148 | T finv = T(1) / res[m - 1]; 149 | for(int i = m; i --> 1;) { 150 | res[i] = coef[i - 1] * finv * res[i - 1]; 151 | finv *= T(i); 152 | } 153 | res[0] = T(0); 154 | return FPS(std::move(res)); 155 | } 156 | 157 | // F(0) must not be 0 158 | FPS log(int n) const { 159 | FPS in = this->inv(n); 160 | FPS di = this->diff(n); 161 | int m = bound_pow2(n); 162 | return (std::move(di).dft(m * 2) * std::move(in).dft(m * 2)).idft().integral(n); 163 | } 164 | 165 | FPS exp(int n) const { 166 | FPS f(std::vector{ T(1) }); 167 | for(i64 i = 1;i < n;i <<= 1 ) { 168 | FPS flog = f.log(i << 1); 169 | for(int j = 0; j < (i << 1); j++) { 170 | flog[j] = (j < coef.size() ? coef[j] - flog[j] : -flog[j]); 171 | } 172 | flog[0] += T(1); 173 | f = (std::move(f).dft(i << 2) * std::move(flog).dft(i << 2)).idft(i << 1); 174 | } 175 | f.resize(n); 176 | return f; 177 | } 178 | }; 179 | -------------------------------------------------------------------------------- /src/math/fps_multiply_arb.hpp: -------------------------------------------------------------------------------- 1 | #include "modint.hpp" 2 | #include "convolution/number_theoretic_transform.hpp" 3 | #include "garner.hpp" 4 | #include 5 | #include 6 | 7 | template 8 | struct fps_multiply_arb { 9 | using fps_type = std::vector>; 10 | using conv_type = std::tuple>...>; 11 | const static std::size_t tsize = std::tuple_size::value; 12 | 13 | template 14 | static std::vector> dft_m2(const fps_type& arr) { 15 | std::vector> res(arr.size()); 16 | for(std::size_t i = 0; i < arr.size(); i++) 17 | res[i] = modint(arr[i].value()); 18 | return number_theoretic_transform(std::move(res)); 19 | } 20 | template 21 | static std::vector> idft_m2(std::vector> arr) { 22 | return inverse_number_theoretic_transform(std::move(arr)); 23 | } 24 | template 25 | static fps_type idft_func(std::index_sequence, conv_type arr) { 26 | arr = std::make_tuple(idft_m2(std::get(arr))...); 27 | std::size_t len = std::get<0>(arr).size(); 28 | static std::vector primes = { NTT_PRIMES[NTTis][0]... }; 29 | fps_type res(len); 30 | for(std::size_t i = 0; i < len; i++) { 31 | std::vector x = { std::get(arr)[i].value()... }; 32 | res[i] = modint(garner(x, primes, M)); 33 | } 34 | return std::move(res); 35 | } 36 | template 37 | static char mult_m2(std::vector>& a, const std::vector>& b) { 38 | for(int i = 0;i < a.size();i++) a[i] *= b[i]; 39 | return 0; 40 | } 41 | template 42 | static void mult_func(std::index_sequence, conv_type& a, const conv_type& b) { 43 | auto res = std::make_tuple(mult_m2(std::get(a), std::get(b))...); 44 | } 45 | static conv_type dft(fps_type arr) { 46 | return std::make_tuple(dft_m2(arr)...); 47 | } 48 | static fps_type idft(conv_type arr) { 49 | return idft_func(std::make_index_sequence(), std::move(arr)); 50 | } 51 | static conv_type multiply(conv_type a, const conv_type& b) { 52 | mult_func(std::make_index_sequence(), a, b); 53 | return a; 54 | } 55 | static conv_type self_multiply(conv_type a) { 56 | mult_func(std::make_index_sequence(), a, a); 57 | return a; 58 | } 59 | }; 60 | 61 | -------------------------------------------------------------------------------- /src/math/fps_ntt_multiply.hpp: -------------------------------------------------------------------------------- 1 | #include "modint.hpp" 2 | #include "convolution/number_theoretic_transform.hpp" 3 | 4 | template 5 | struct fps_ntt_multiply { 6 | using fps_type = modint; 7 | using conv_type = modint; 8 | static std::vector dft(std::vector arr) { 9 | return number_theoretic_transform(std::move(arr)); 10 | } 11 | static std::vector idft(std::vector arr) { 12 | return inverse_number_theoretic_transform(std::move(arr)); 13 | } 14 | static std::vector multiply(std::vector a, const std::vector& b) { 15 | for(int i = 0;i < a.size();i++) a[i] *= b[i]; 16 | return a; 17 | } 18 | static std::vector self_multiply(std::vector a) { 19 | for(int i = 0;i < a.size();i++) a[i] *= a[i]; 20 | return a; 21 | } 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /src/math/garner.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | i64 pow_mod(i64 x, i64 r, i64 mod) { 6 | i64 ans = 1; 7 | while(r) { 8 | if(r & 1) ans = (ans * x) % mod; 9 | r >>= 1; 10 | x = x * x % mod; 11 | } 12 | return ans; 13 | } 14 | 15 | i64 inv_mod(i64 x, i64 mod) { 16 | return pow_mod(x, mod - 2, mod); 17 | } 18 | 19 | i64 garner(const vector &x, vector mods, i64 mod) { 20 | mods.emplace_back(mod); 21 | vector coeffs(x.size() + 1, 1); 22 | vector constants(x.size() + 1, 0); 23 | for(i64 i = 0; i < x.size(); i++) { 24 | i64 v = (x[i] - constants[i]) * inv_mod(coeffs[i], mods[i]) % mods[i]; 25 | if(v < 0) v += mods[i]; 26 | for(i64 j = i + 1; j < x.size() + 1; j++) { 27 | constants[j] = (constants[j] + coeffs[j] * v) % mods[j]; 28 | coeffs[j] = (coeffs[j] * mods[i]) % mods[j]; 29 | } 30 | } 31 | return constants.back(); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/math/matrix.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | template 6 | struct matrix { 7 | int N, M; 8 | vector> mat; 9 | matrix(int N, int M, T init = T::zero()): N(N), M(M), mat(N, vector(M, init)) {} 10 | vector& operator[](i64 i) { return mat[i]; } 11 | const vector& operator[](i64 i) const { return mat[i]; } 12 | static matrix E(int N) { 13 | matrix mat(N, N, T::zero()); 14 | for(int i = 0; i < N; i++) { 15 | mat[i][i] = T::one(); 16 | } 17 | return mat; 18 | } 19 | }; 20 | 21 | template 22 | matrix operator+(const matrix& lm, const matrix& rm) { 23 | matrix ret(lm.N, lm.M); 24 | for(int i = 0; i < lm.N; i++) { 25 | for(int j = 0; j< lm.M; j++) { 26 | ret[i][j] = lm[i][j] + rm[i][j]; 27 | } 28 | } 29 | return ret; 30 | } 31 | template 32 | matrix operator*(const matrix& lm, const matrix& rm) { 33 | matrix ret(lm.N, rm.M); 34 | for(int i = 0; i < lm.N; i++) { 35 | for(int j = 0; j < lm.M; j++) { 36 | for(int k = 0; k < rm.M; k++) { 37 | ret[i][k] = ret[i][k] + lm[i][j] * rm[j][k]; 38 | } 39 | } 40 | } 41 | return ret; 42 | } 43 | 44 | template 45 | matrix operator*(const matrix& lm, const T& r) { 46 | matrix ret(lm.N, lm.M); 47 | for(int i = 0; i < lm.N; i++) { 48 | for(int j = 0; j< lm.M; j++) { 49 | ret[i][j] = lm[i][j] * r; 50 | } 51 | } 52 | return ret; 53 | } 54 | 55 | template 56 | matrix matrix_pow(matrix mat, i64 r) { 57 | matrix ret = matrix::E(mat.N); 58 | while(r > 0) { 59 | if(r & 1) ret = ret * mat; 60 | mat = mat * mat; 61 | r >>= 1; 62 | } 63 | return ret; 64 | } 65 | -------------------------------------------------------------------------------- /src/math/modint.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using i64 = long long; 3 | template struct modint { i64 a; 4 | constexpr modint(const i64 x = 0): a((x%M+M)%M){} 5 | constexpr i64 value() const { return a; } 6 | constexpr modint inv() const { return this->pow(M-2); } 7 | constexpr modint pow(i64 r) const { 8 | modint ans(1); modint aa = *this; 9 | while(r) { if(r & 1) ans *= aa; aa *= aa; r >>= 1; } 10 | return ans; 11 | } 12 | constexpr bool operator==(const modint& r) const { return a == r.a; } 13 | constexpr bool operator!=(const modint& r) const { return a != r.a; } 14 | constexpr modint& operator=(const i64 r) { a = (r % M + M) % M; return *this; } 15 | constexpr modint& operator+=(const modint r) { a += r.a; if(a >= M) a -= M; return *this; } 16 | constexpr modint& operator-=(const modint r) { a -= r.a; if(a < 0) a += M; return *this; } 17 | constexpr modint& operator*=(const modint r) { a = a * r.a % M; return *this; } 18 | constexpr modint& operator/=(const modint r) { (*this) *= r.inv(); return *this; } 19 | constexpr modint operator+(const modint r) const { return modint(*this) += r; } 20 | constexpr modint operator-(const modint r) const { return modint(*this) -= r; } 21 | constexpr modint operator-() const { return modint(0) - modint(*this); } 22 | constexpr modint operator*(const modint r) const { return modint(*this) *= r; } 23 | constexpr modint operator/(const modint r) const { return modint(*this) /= r; } 24 | constexpr bool operator!=(const modint r) const { return this->value() != r.value(); } 25 | }; 26 | 27 | template std::ostream& operator<<(std::ostream& os, const modint& m) { os << m.value(); return os; } 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/math/montgomery_modint.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | struct montgomery_modint { 5 | using Self = montgomery_modint; 6 | using i32 = int32_t; 7 | using u32 = uint32_t; 8 | using u64 = uint64_t; 9 | 10 | static constexpr u32 get_r() { 11 | u32 res = M; 12 | for(int i = 0; i < 4; i++) res *= 2 - M * res; 13 | return res; 14 | } 15 | static constexpr u32 reduce(u64 a) { 16 | return (a + u64(u32(a) * u32(-r)) * M) >> 32; 17 | } 18 | 19 | static constexpr u32 r = get_r(); 20 | static constexpr u32 n2 = -u64(M) % M; 21 | 22 | u32 a; 23 | 24 | constexpr montgomery_modint() : a(0) {} 25 | constexpr montgomery_modint(int64_t a) : a(reduce(u64(a % M + M) * n2)) {} 26 | 27 | constexpr u32 val() const { 28 | u32 res = reduce(a); 29 | return res >= M ? res - M : res; 30 | } 31 | constexpr Self pow(u64 r) const { 32 | Self ans(1); Self aa = *this; 33 | while(r) { if(r & 1) ans *= aa; aa *= aa; r >>= 1; } 34 | return ans; 35 | } 36 | constexpr Self inv() const { return this->pow(M - 2); } 37 | constexpr Self& operator+=(const Self& r) { 38 | if(i32(a += r.a - 2 * M) < 0) a += 2 * M; 39 | return *this; 40 | } 41 | constexpr Self& operator-=(const Self& r) { 42 | if(i32(a -= r.a) < 0) a += 2 * M; 43 | return *this; 44 | } 45 | constexpr Self& operator*=(const Self& r) { 46 | a = reduce(u64(a) * r.a); 47 | return *this; 48 | } 49 | constexpr Self& operator/=(const Self& r) { 50 | *this *= r.inv(); 51 | return *this; 52 | } 53 | constexpr Self operator+(const Self r) const { return Self(*this) += r; } 54 | constexpr Self operator-(const Self r) const { return Self(*this) -= r; } 55 | constexpr Self operator-() const { return Self() - Self(*this); } 56 | constexpr Self operator*(const Self r) const { return Self(*this) *= r; } 57 | constexpr Self operator/(const Self r) const { return Self(*this) /= r; } 58 | constexpr bool operator==(const Self& r) const { 59 | return (a >= M ? a - M : a) == (r.a >= M ? r.a - M : r.a); 60 | } 61 | constexpr bool operator!=(const Self& r) const { 62 | return (a >= M ? a - M : a) == (r.a >= M ? r.a - M : r.a); 63 | } 64 | }; 65 | 66 | template 67 | std::ostream& operator<<(std::ostream& os, const montgomery_modint& m) { 68 | return os << m.val(); 69 | } 70 | template 71 | std::istream& operator>>(std::istream& is, montgomery_modint& m) { 72 | int64_t t; 73 | is >> t; 74 | m = montgomery_modint(t); 75 | return is; 76 | } 77 | 78 | template 79 | using modint = montgomery_modint; 80 | -------------------------------------------------------------------------------- /src/math/mori_fps_division.hpp: -------------------------------------------------------------------------------- 1 | #include "formal_power_series.hpp" 2 | 3 | template 4 | typename fps_multiply::fps_type mori_fps_division(FPS P, FPS Q, std::size_t N) { 5 | using T = typename fps_multiply::fps_type; 6 | i64 k = bound_pow2(std::max(P.size(), Q.size())); 7 | P.resize(k * 2); 8 | Q.resize(k * 2); 9 | while(N > 0) { 10 | auto Qm = Q; 11 | for(std::size_t i = 1; i < Qm.size(); i += 2) { 12 | Qm[i] *= T(-1); 13 | } 14 | //auto Pd = fps_multiply::dft(std::move(P.coef)); 15 | //auto Qd = fps_multiply::dft(std::move(Q.coef)); 16 | //auto Qmd = fps_multiply::dft(std::move(Qm.coef)); 17 | auto Pd = std::move(P).dft(k * 2); 18 | auto Qd = std::move(Q).dft(k * 2); 19 | auto Qmd = std::move(Qm).dft(k * 2); 20 | //auto PQ = fps_multiply::idft( 21 | // fps_multiply::multiply(std::move(Pd), Qmd) 22 | // ); 23 | auto PQ = std::move(Pd *= Qmd).idft(); 24 | //auto QQ = fps_multiply::idft( 25 | // fps_multiply::multiply(std::move(Qd), std::move(Qmd)) 26 | // ); 27 | auto QQ = std::move(Qd *= Qmd).idft(); 28 | { 29 | std::size_t i = 0; 30 | for(std::size_t j = 0; j < QQ.size(); j += 2) { 31 | QQ[i++] = QQ[j]; 32 | } 33 | while(i < QQ.size()) QQ[i++] = T(0); 34 | } 35 | { 36 | std::size_t i = 0; 37 | for(std::size_t j = N % 2; j < PQ.size(); j += 2) { 38 | PQ[i++] = PQ[j]; 39 | } 40 | while(i < PQ.size()) PQ[i++] = T(0); 41 | } 42 | P = std::move(PQ); 43 | Q = std::move(QQ); 44 | N /= 2; 45 | } 46 | return P[0] / Q[0]; 47 | } 48 | 49 | #include "fps_ntt_multiply.hpp" 50 | #include 51 | 52 | int main() { 53 | std::cin.tie(nullptr); 54 | std::ios::sync_with_stdio(false); 55 | using fp = modint<998244353>; 56 | using mlt = fps_ntt_multiply<998244353, 3>; 57 | using fps = FPS; 58 | 59 | i64 D, K; 60 | std::cin >> D >> K; 61 | 62 | vector a(D); 63 | for(int i = 0;i < D;i++) std::cin >> a[i].a; 64 | vector c(D + 1); 65 | for(int i = 1; i <= D; i++) std::cin >> c[i].a; 66 | c[0] = fp(-1); 67 | 68 | fps A(std::move(a)); 69 | fps Q(std::move(c)); 70 | i64 d = bound_pow2(D + 1); 71 | fps P = std::move(Q.clone().dft(d) *= std::move(A).dft(d)).idft(D); 72 | std::cout << mori_fps_division(std::move(P), std::move(Q), K).a << std::endl; 73 | } 74 | -------------------------------------------------------------------------------- /src/math/newton_interpolation.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | std::vector newton_interpolation(std::vector> ps) { 5 | std::vector diff(ps.size()); 6 | diff[0] = ps[0].second; 7 | std::vector x(ps.size()), y(ps.size()); 8 | for(int i = 0;i < ps.size(); i++) { 9 | x[i] = ps[i].first, y[i] = ps[i].second; 10 | } 11 | for(int i = 1;i < ps.size();i++) { 12 | std::vector d(ps.size() - i); 13 | for(int j = 0;j + i < ps.size(); j++) { 14 | d[j] = (y[j + 1] - y[j]) / (x[j + i] - x[j]); 15 | } 16 | diff[i] = d[0]; 17 | swap(y, d); 18 | } 19 | 20 | std::vector ans(ps.size()); 21 | 22 | std::vector c(ps.size() + 1); 23 | c[0] = 1; 24 | 25 | 26 | for(int i = 0;i < ps.size();i++) { 27 | for(int j = 0;j < ps.size();j++) { 28 | ans[j] += diff[i] * c[j]; 29 | } 30 | if(i + 1 == ps.size()) break; 31 | 32 | std::vector next(ps.size() + 1); 33 | for(int j = 0;j < ps.size();j++) { 34 | next[j + 1] = c[j]; 35 | } 36 | for(int j = 0;j < ps.size();j++) { 37 | next[j] -= c[j] * ps[i].first; 38 | } 39 | swap(c, next); 40 | } 41 | return ans; 42 | } 43 | -------------------------------------------------------------------------------- /src/math/osa_k.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct osa_k { 6 | using int_type = int; 7 | std::vector min_fact; 8 | 9 | // O(NlogN) 10 | static std::vector min_prime_factor(int n) { 11 | std::vector res(n); 12 | std::iota(std::begin(res), std::end(res), 0); 13 | for(int i = 2; i * i < n; i++) { 14 | if(res[i] < i) continue; 15 | for(int j = i * i; j < n; j += i) { 16 | if(res[j] == j) res[j] = i; 17 | } 18 | } 19 | return res; 20 | } 21 | 22 | void build(int n) { 23 | min_fact = min_prime_factor(n); 24 | } 25 | 26 | // O(logN) 27 | std::vector> prime_factors(int n) const { 28 | std::vector> res; 29 | while(n > 1) { 30 | if(res.empty() || res.back().first != min_fact[n]) { 31 | res.push_back({ min_fact[n], 0 }); 32 | } 33 | res.back().second++; 34 | n /= min_fact[n]; 35 | } 36 | return res; 37 | } 38 | 39 | // The divisors are not sorted 40 | // O(logN + |divisors|) 41 | template 42 | void enumerate_divisors(int n, F f) const { 43 | std::vector> prime_facts = prime_factors(n); 44 | if(prime_facts.empty()) { 45 | f(1); 46 | return; 47 | } 48 | std::vector cnt(prime_facts.size()); 49 | std::vector acc(prime_facts.size(), 1); 50 | while(true){ 51 | f(acc.front()); 52 | int i = 0; 53 | for(; i < prime_facts.size(); i++) { 54 | if((cnt[i]++) == prime_facts[i].second) { 55 | cnt[i] = 0; 56 | } 57 | else { 58 | acc[i] *= prime_facts[i].first; 59 | break; 60 | } 61 | } 62 | if(i == prime_facts.size()) { 63 | break; 64 | } 65 | while(i --> 0) { 66 | acc[i] = acc[i + 1]; 67 | } 68 | } 69 | } 70 | }; 71 | -------------------------------------------------------------------------------- /src/math/runtime_fp.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | struct modint { 6 | i64 a; 7 | static i64& M() { 8 | static i64 mod_ = 2999; 9 | return mod_; 10 | } 11 | modint(const i64 x = 0) noexcept: a((x % M() + M()) % M()) {} 12 | i64 value() const noexcept { return a; } 13 | modint& operator=(const i64 r) { 14 | a = (r % M() + M()) % M(); 15 | return *this; 16 | } 17 | modint& operator+=(const modint r) noexcept { 18 | a += r.a; 19 | if(a >= M()) a -= M(); 20 | return *this; 21 | } 22 | modint& operator-=(const modint r) noexcept { 23 | a -= r.a; 24 | if(a < 0) a += M(); 25 | return *this; 26 | } 27 | modint& operator*=(const modint r) noexcept { 28 | a = a * r.a % M(); 29 | return *this; 30 | } 31 | modint& operator/=(modint r) noexcept { 32 | i64 ex = M() - 2; 33 | while(ex) { 34 | if(ex & 1) { 35 | *this *= r; 36 | } 37 | r *= r; 38 | ex >>= 1; 39 | } 40 | return *this; 41 | } 42 | 43 | modint operator+(const modint r) const { 44 | return modint(*this) += r; 45 | } 46 | modint operator-(const modint r) const { 47 | return modint(*this) -= r; 48 | } 49 | modint operator*(const modint r) const { 50 | return modint(*this) *= r; 51 | } 52 | modint operator/(const modint r) const { 53 | return modint(*this) /= r; 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /src/math/seidels_lp.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /** 9 | * # Seidel's LP algorithm 10 | * - LPを解くアルゴリズム 11 | * - LP(線形計画問題)とは, 以下のように記述できる. 12 | * 13 | * \\[ 14 | * \begin{align} 15 | * \text{maximize} \ & c^T x \\\\ 16 | * \text{subject to} \ & A x \leq b \\\\ 17 | * \ & x \geq 0 18 | * \end{align} 19 | * \\] 20 | * 21 | * - この \\( x \\) を返す. 22 | * - 計算量 \\( O(d! m) ( d \text{は次元数}, m \text{は条件数}) \\) 23 | * 24 | * ## Arguments 25 | * 26 | * ```cpp 27 | * @3@ 28 | * ``` 29 | * `mat`は, \\( (A \ b) \\)である. 30 | * 31 | * ```cpp 32 | * @4@ 33 | * ``` 34 | * `bounds`には, \\( x \\)のとる下界と上界を与える. 35 | * 36 | * ## Memo 37 | * 38 | * ```cpp 39 | * @5@ 40 | * ``` 41 | * `eps`を変える必要があるかもしれない. 42 | **/ 43 | template 44 | std::vector seidel_lp(R& rnd, std::size_t d, 45 | const std::vector& c, 46 | const std::vector>& mat, 47 | const std::vector>& bounds) { 48 | const static T eps = std::numeric_limits::epsilon(); 49 | const static auto eps_eq = [&](const T& a, const T& b) -> bool { 50 | return std::abs(a - b) <= eps; 51 | }; 52 | assert(d > 0); 53 | if(d == 1) { 54 | assert(c.size() == 1); 55 | T low = bounds[0].first; 56 | T high = bounds[0].second; 57 | T z = T(0); 58 | for(const auto& a: mat) { 59 | assert(a.size() == 2); 60 | if(eps_eq(a[0], T(0))) { 61 | // equal 62 | if(std::abs(a[1] - z) <= eps || a[1] < z) z = a[1]; 63 | } 64 | else if(a[0] > T(0)) { 65 | // greater 66 | T pa = a[1] / a[0]; 67 | if(eps_eq(pa, high) || pa < high) high = pa; 68 | } 69 | else { 70 | T pa = a[1] / a[0]; 71 | if(eps_eq(pa, low) || pa > low) low = pa; 72 | } 73 | } 74 | if(z < T(0) || high < low) return std::vector(); 75 | else if(eps_eq(c[0], T(0)) || c[0] > T(0)) return std::vector { high }; 76 | else return std::vector { low }; 77 | } 78 | else if(mat.empty()) { 79 | std::vector res(d); 80 | for(int i = 0; i < d; i++) { 81 | if(eps_eq(c[i], T(0)) || c[i] > T(0)) res[i] = bounds[i].second; 82 | else res[i] = bounds[i].first; 83 | } 84 | return res; 85 | } 86 | else { 87 | int rmi = rnd() % mat.size(); 88 | const auto& a = mat[rmi]; 89 | std::vector> next_mat(mat.size() - 1); 90 | { 91 | int ni = 0; 92 | for(int i = 0; i < mat.size(); i++) { 93 | if(i == rmi) continue; 94 | next_mat[ni++] = mat[i]; 95 | } 96 | } 97 | auto v = seidel_lp(rnd, d, c, next_mat, bounds); 98 | if(v.empty()) return v; 99 | { 100 | T value = T(0); 101 | for(int i = 0; i < d; i++) { 102 | value += a[i] * v[i]; 103 | } 104 | if(eps_eq(value, a[d]) || value < a[d]) return v; 105 | } 106 | int k = -1; 107 | for(int i = 0; i < d; i++) { 108 | if(!eps_eq(a[i], T(0))) k = i; 109 | } 110 | if(k == -1) return std::vector(); 111 | 112 | std::vector> next_bounds(d - 1); 113 | { 114 | int ni = 0; 115 | for(int i = 0;i < d; i++) { 116 | if(i == k) continue; 117 | next_bounds[ni++] = bounds[i]; 118 | } 119 | } 120 | std::vector> bar_mat(next_mat.size() + 2, std::vector(d)); 121 | for(int mi = 0; mi < next_mat.size(); mi++) { 122 | auto ratio = next_mat[mi][k] / a[k]; 123 | int ni = 0; 124 | for(int i = 0; i <= d; i++) { 125 | if(i == k) continue; 126 | bar_mat[mi][ni++] = next_mat[mi][i] - ratio * a[i]; 127 | } 128 | } 129 | std::vector bar_c(d - 1); 130 | { 131 | auto ratio = c[k] / a[k]; 132 | int ni = 0; 133 | for(int i = 0; i < d; i++) { 134 | if(i == k) continue; 135 | bar_c[ni++] = c[i] - ratio * a[i]; 136 | } 137 | } 138 | { 139 | int ni = 0; 140 | for(int i = 0; i < d; i++) { 141 | if(i == k) continue; 142 | bar_mat[next_mat.size()][ni] = - (T(1) / a[k]) * a[i]; 143 | bar_mat[next_mat.size() + 1][ni++] = - (T(1) / a[k]) * a[i]; 144 | } 145 | bar_mat[next_mat.size()][d - 1] = bounds[k].second; 146 | bar_mat[next_mat.size() + 1][d - 1] = bounds[k].first; 147 | } 148 | 149 | v = seidel_lp(rnd, d - 1, bar_c, bar_mat, next_bounds); 150 | if(v.empty()) { 151 | return v; 152 | } 153 | else { 154 | v.insert(std::begin(v) + k, T(0)); 155 | T s = 0; 156 | for(int i = 0; i < d; i++) s += a[i] * v[i]; 157 | v[k] = (a[d] - s) / a[k]; 158 | return v; 159 | } 160 | } 161 | } 162 | 163 | #include 164 | #include 165 | #include 166 | 167 | int main() { 168 | long double C, D; 169 | std::cin >> C >> D; 170 | auto r = std::mt19937(9982); 171 | std::vector c { 1.0, 2.0 }; 172 | std::vector> mat { 173 | { 3.0 / 4.0, 2.0 / 7.0, C }, 174 | { 1.0 / 4.0, 5.0 / 7.0, D }, 175 | { -1.0, 0.0, 0.0 }, 176 | { 0.0, -1.0, 0.0 } 177 | }; 178 | std::vector> bounds { 179 | { 0.0, 2000.0 }, 180 | { 0.0, 2000.0 } 181 | }; 182 | auto ans = seidel_lp(r, 2, c, mat, bounds); 183 | std::cout << std::fixed << std::setprecision(10) << ans[0] * 1000.0 + ans[1] * 2000.0 << std::endl; 184 | } 185 | -------------------------------------------------------------------------------- /src/other/cppfirst.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | #define rep(i,s,e) for(i64 (i) = (s);(i) < (e);(i)++) 5 | #define all(x) x.begin(),x.end() 6 | #define STRINGIFY(n) #n 7 | #define TOSTRING(n) STRINGIFY(n) 8 | #define PREFIX "#" TOSTRING(__LINE__) "| " 9 | #define debug(x) \ 10 | { \ 11 | std::cout << PREFIX << #x << " = " << x << std::endl; \ 12 | } 13 | 14 | std::ostream& output_indent(std::ostream& os, int ind) { 15 | for(int i = 0; i < ind; i++) os << " "; 16 | return os; 17 | } 18 | 19 | template std::ostream& operator<<(std::ostream& os, const std::pair& p); 20 | template std::ostream& operator<<(std::ostream& os, const std::vector& v); 21 | 22 | template std::ostream& operator<<(std::ostream& os, const std::pair& p) { 23 | return (os << "(" << p.first << ", " << p.second << ")"); 24 | } 25 | template std::ostream& operator<<(std::ostream& os, const std::vector& v) { 26 | os << "["; 27 | for(int i = 0;i < v.size();i++) os << v[i] << ", "; 28 | return (os << "]"); 29 | } 30 | 31 | template 32 | static inline std::vector ndvec(size_t&& n, T val) { return std::vector(n, std::forward(val)); } 33 | template 34 | static inline auto ndvec(size_t&& n, Tail&&... tail) { 35 | return std::vector(tail)...))>(n, ndvec(std::forward(tail)...)); 36 | } 37 | template struct chain { 38 | Cond cond; chain(Cond cond) : cond(cond) {} 39 | template bool operator()(T& a, const T& b) const { if(cond(a, b)) { a = b; return true; } return false; } 40 | }; 41 | template chain make_chain(Cond cond) { return chain(cond); } 42 | -------------------------------------------------------------------------------- /src/other/fastio.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace niu { 4 | 5 | struct fastin { 6 | static const int bufsize = 1 << 24; 7 | char buf[bufsize]; 8 | char* iter; 9 | fastin() { 10 | iter = buf; 11 | for(int t = 0, k; (k = read(STDIN_FILENO, buf + t, sizeof(buf)) - t) > 0; t += k); 12 | } 13 | fastin& operator>>(int& num) { 14 | num = 0; 15 | bool neg = false; 16 | while(*iter < '+') iter++; 17 | if(*iter == '-') { neg = true; iter++; } 18 | else if(*iter == '+') iter++; 19 | while(*iter >= '0') num = 10 * num + *(iter++) - '0'; 20 | if(neg) num = -num; 21 | return *this; 22 | } 23 | } fin; 24 | struct fastout { 25 | static const int bufsize = 1 << 24; 26 | char buf[bufsize]; 27 | char* iter; 28 | fastout() { 29 | iter = buf; 30 | } 31 | ~fastout() { 32 | for(int t = 0, k; (k = write(STDOUT_FILENO, buf + t, iter - buf - t)) > 0; t += k); 33 | } 34 | fastout& operator<<(int num) { 35 | static char tmp[20]; 36 | if(num == 0) { 37 | *(iter++) = '0'; 38 | return *this; 39 | } 40 | if(num < 0) { 41 | *(iter++) = '-'; 42 | num = -num; 43 | } 44 | int i = 0; 45 | while(num) { 46 | tmp[i++] = num % 10; 47 | num /= 10; 48 | } 49 | while(i--) { 50 | *(iter++) = tmp[i] + '0'; 51 | } 52 | return *this; 53 | } 54 | fastout& operator<<(char c) { 55 | *(iter++) = c; 56 | return *this; 57 | } 58 | } fout; 59 | } 60 | -------------------------------------------------------------------------------- /src/other/grundy.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | N個の正整数からなる集合 A={a1,a2,…,aN}があります。 太郎君と次郎君が次のゲームで勝負します。 3 | 4 | 最初に、K個の石からなる山を用意します。 二人は次の操作を交互に行います。 先手は太郎君です。 5 | Aの元 xをひとつ選び、山からちょうど x個の石を取り去る。 6 | 先に操作を行えなくなった人が負けです。 二人が最適に行動すると仮定したとき、どちらが勝つかを判定してください。 7 | */ 8 | 9 | #include 10 | using namespace std; 11 | using i64 = long long; 12 | 13 | vector grn(101010, -1); 14 | 15 | i64 N, K; 16 | vector a; 17 | 18 | int main() { 19 | cin >> N >> K; 20 | a.resize(N); 21 | for(int i = 0;i < N;i++) cin >> a[i]; 22 | for(i64 k = 0;k <= K;k++) { 23 | set st; 24 | for(auto x: a) { 25 | if(k - x >= 0) st.insert(grn[k - x]); 26 | } 27 | grn[k] = K + 1; 28 | for(int i = 0;i <= K + 1;i++) { 29 | if(!st.count(i)) { 30 | grn[k] = i; 31 | break; 32 | } 33 | } 34 | } 35 | if(grn[K]) { 36 | cout << "First" << endl; 37 | } 38 | else { 39 | cout << "Second" << endl; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/other/mongeDP.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | #define rep(i,s,e) for(int (i) = (s);(i) < (e);(i)++) 5 | #define all(x) x.begin(),x.end() 6 | #define let auto const 7 | 8 | /* 9 | ## calc dp[i][j] = min[i<=k= f(a) + f(b) 12 | ## MLI ...if a is partial of b , f(a) <= f(b) 13 | */ 14 | template 15 | i64 mongeDP(i64 N, F f) { 16 | vector> dp(N, vector(N, 1e18)); 17 | vector> k(N, vector(N)); 18 | rep(i, 0, N) { 19 | dp[i][i] = 0; 20 | k[i][i] = i; 21 | } 22 | 23 | rep(d, 1, N) { 24 | rep(i, 0, N - d) { 25 | i64 j = i + d; 26 | i64 l = k[i][j - 1]; 27 | i64 r = k[i + 1][j]; 28 | rep(s, l, r + 1) { 29 | if(s + 1 >= N) break; 30 | if(dp[i][s] + dp[s + 1][j] <= dp[i][j]) { 31 | dp[i][j] = dp[i][s] + dp[s + 1][j]; 32 | k[i][j] = s; 33 | } 34 | } 35 | dp[i][j] += f(i, j); 36 | } 37 | } 38 | return dp[0][N - 1]; 39 | } 40 | 41 | int main() { 42 | i64 N; 43 | cin >> N; 44 | 45 | vector W; 46 | W.push_back(0); 47 | rep(i,0, N) { 48 | i64 x; 49 | cin >> x; 50 | W.push_back(W.back() + x); 51 | } 52 | auto f = [&](i64 i, i64 j) { return W[j + 1] - W[i]; }; 53 | cout << mongeDP(N, f) << endl; 54 | } 55 | -------------------------------------------------------------------------------- /src/other/slide_min.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | template 6 | struct dynamic_slide_min { 7 | const i64 k; 8 | deque> que; 9 | i64 i; 10 | /* k := length of slide */ 11 | dynamic_slide_min(const i64 k): k(k), i(0) {} 12 | /* return min value in slide k after inserting x */ 13 | T next(T x) { 14 | while(!que.empty() && que.back().second >= x) que.pop_back(); 15 | que.push_back({i, x}); 16 | i64 min_i = que.front().second; 17 | i++; 18 | if(i == que.front().first + k) { 19 | que.pop_front(); 20 | } 21 | return min_i; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/other/y_combinator.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | auto result = [g = [](auto f, int n) -> int { 4 | return n < 2 ? n : (f(f, n - 1) + f(f, n - 2)); 5 | }](auto&&... args) { 6 | return g(g, std::forward(args)...); 7 | }(10); 8 | } 9 | -------------------------------------------------------------------------------- /src/string/2_61-1_rolling_hash.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using u64 = unsigned long long; 3 | 4 | struct hash_bases { 5 | static const u64 MOD = (1ull << 61) - 1; 6 | const int N; 7 | std::vector> bases; 8 | 9 | inline static u64 mod(u64 x) { 10 | x = (x >> 61) + (x & MOD); 11 | if(x >= MOD) { 12 | x -= MOD; 13 | } 14 | return x; 15 | } 16 | 17 | inline static u64 mul(u64 a, u64 b) { 18 | u64 ac = a >> 31; 19 | a = a & ((1ull << 31) - 1); 20 | u64 bc = b >> 31; 21 | b = b & ((1ull << 31) - 1); 22 | u64 x = ac * b + bc * a;; 23 | x = ac * bc * 2 + (x >> 30) + ((x & ((1ull << 30) - 1)) << 31) + a * b; 24 | return mod(x); 25 | } 26 | 27 | hash_bases(std::vector bs, int M) : N(bs.size()), bases(M, std::vector(N, 1)) { 28 | for(int i = 1; i < M; i++) { 29 | for(int j = 0;j < N; j++){ 30 | bases[i][j] = mul(bases[i - 1][j], bs[j]); 31 | } 32 | } 33 | } 34 | 35 | u64 operator()(int i, int r) { 36 | return bases[r][i]; 37 | } 38 | } bases(std::vector { 9973, 10007 }, 202020); 39 | 40 | struct rhash { 41 | static const u64 MOD = hash_bases::MOD; 42 | std::vector h; 43 | u64 len; 44 | 45 | rhash() : h(bases.N), len(0) {} 46 | rhash(u64 x): h(bases.N), len(1) { 47 | x = hash_bases::mod(x); 48 | for(int i = 0; i < bases.N; i++) { 49 | h[i] = x; 50 | } 51 | } 52 | 53 | rhash next(u64 r) const { 54 | rhash ans; 55 | for(int i = 0;i < bases.N; i++) { 56 | ans.h[i] = hash_bases::mul(h[i], bases(i, r)); 57 | } 58 | ans.len = len + r; 59 | return ans; 60 | } 61 | 62 | rhash& operator+=(const rhash& r) { 63 | for(int i = 0;i < bases.N; i++) { 64 | h[i] += r.h[i]; 65 | if(h[i] >= MOD) h[i] -= MOD; 66 | } 67 | len = std::max(len, r.len); 68 | return (*this); 69 | } 70 | 71 | rhash& operator-=(const rhash& r) { 72 | for(int i = 0;i < bases.N; i++) { 73 | if(h[i] < r.h[i]) { 74 | h[i] = h[i] + MOD - r.h[i]; 75 | } 76 | else { 77 | h[i] = h[i] - r.h[i]; 78 | } 79 | } 80 | return (*this); 81 | } 82 | 83 | rhash operator+(const rhash& r) const { return rhash(*this) += r; } 84 | rhash operator-(const rhash& r) const { return rhash(*this) -= r; } 85 | bool operator==(const rhash& r) const { 86 | bool OK = true; 87 | for(int i = 0;i < bases.N; i++){ 88 | OK &= h[i] == r.h[i]; 89 | } 90 | return OK; 91 | } 92 | }; 93 | -------------------------------------------------------------------------------- /src/string/manacher.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | /* 6 | * 文字 i を中心とする最長の回文の半径 = (全長 + 1) / 2 7 | */ 8 | 9 | vector manacher(string S) { 10 | vector R(S.size()); 11 | int i = 0, j = 0; 12 | while (i < S.size()) { 13 | while (i-j >= 0 && i+j < S.size() && S[i-j] == S[i+j]) ++j; 14 | R[i] = j; 15 | int k = 1; 16 | while (i-k >= 0 && i+k < S.size() && k+R[i-k] < j) R[i+k] = R[i-k], ++k; 17 | i += k; j -= k; 18 | } 19 | return R; 20 | } 21 | -------------------------------------------------------------------------------- /src/string/mp.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | /* 6 | * 文字列S[0, i-1]のprefixとsuffixが最大何文字一致しているか 7 | */ 8 | 9 | vector mp(string S) { 10 | vector A(S.size() + 1); 11 | A[0] = -1; 12 | int j = -1; 13 | for (int i = 0; i < S.size(); i++) { 14 | while (j >= 0 && S[i] != S[j]) j = A[j]; 15 | j++; 16 | A[i+1] = j; 17 | } 18 | return A; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/string/rolling_hash.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | const i64 rhmod = 1e9 + 7; 6 | const i64 BASE_C = 2; 7 | const i64 base[] = {9973, 10007}; 8 | 9 | struct rolling_hash { 10 | i64 n; 11 | vector hs[BASE_C], pw[BASE_C]; 12 | 13 | template 14 | rolling_hash(const Array& arr) { 15 | n = arr.size(); 16 | for(int i = 0;i < BASE_C;i++) { 17 | hs[i].assign(n + 1, 0); 18 | pw[i].assign(n + 1, 0); 19 | hs[i][0] = 0; 20 | pw[i][0] = 1; 21 | for(int j = 0;j < n;j++) { 22 | pw[i][j + 1] = pw[i][j] * base[i] % rhmod; 23 | hs[i][j + 1] = (hs[i][j] * base[i] + arr[j]) % rhmod; 24 | } 25 | } 26 | } 27 | 28 | pair hash(i64 l, i64 r) { 29 | return { 30 | ((hs[0][r + 1] - hs[0][l] * pw[0][r + 1 - l]) % rhmod + rhmod) % rhmod, 31 | ((hs[1][r + 1] - hs[1][l] * pw[1][r + 1 - l]) % rhmod + rhmod) % rhmod, 32 | }; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /src/string/suffix_array.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | const std::vector& sa_is(std::vector s, int k) { 6 | int N = s.size(); 7 | static std::vector sa; 8 | static std::vector cnt; 9 | sa.resize(N + 1); 10 | 11 | if(N == 0) return sa; 12 | 13 | for(auto& c: s) c++; 14 | s.push_back(0); 15 | k++; 16 | 17 | std::vector iss(N + 1); 18 | std::vector lms; 19 | std::vector is_lms(N + 1, -1); 20 | std::vector bin(k + 1); 21 | 22 | iss[N] = true; 23 | bin[1]++; 24 | for(int i = N; i --> 0; ) { 25 | if(s[i] == s[i + 1]) 26 | iss[i] = iss[i + 1]; 27 | else 28 | iss[i] = s[i] < s[i + 1]; 29 | if(!iss[i] && iss[i + 1]) { 30 | is_lms[i + 1] = lms.size(); 31 | lms.push_back(i + 1); 32 | } 33 | bin[s[i] + 1]++; 34 | } 35 | 36 | for(int i = 1;i <= k;i++) 37 | bin[i] += bin[i - 1]; 38 | 39 | auto induce = [&](const std::vector& lms) { 40 | sa.assign(N + 1, -1); 41 | cnt.assign(k, 0); 42 | 43 | for(int i = 0;i < lms.size();i++) { 44 | int x = lms[i]; 45 | sa[bin[s[x] + 1] - 1 - cnt[s[x]]] = x; 46 | cnt[s[x]]++; 47 | } 48 | 49 | cnt.assign(k, 0); 50 | for(int i = 0;i <= N;i++) { 51 | int x = sa[i] - 1; 52 | if(x >= 0 && !iss[x]) { 53 | sa[bin[s[x]] + cnt[s[x]]] = x; 54 | cnt[s[x]]++; 55 | } 56 | } 57 | 58 | cnt.assign(k, 0); 59 | for(int i = N + 1;i --> 0;) { 60 | int x = sa[i] - 1; 61 | if(x >= 0 && iss[x]) { 62 | sa[bin[s[x] + 1] - 1 - cnt[s[x]]] = x; 63 | cnt[s[x]]++; 64 | } 65 | } 66 | }; 67 | 68 | induce(lms); 69 | 70 | 71 | if(lms.size() >= 2) { 72 | int M = lms.size(); 73 | int li = 0; 74 | std::vector rec_lms(M); 75 | for(auto x: sa) { 76 | if(is_lms[x] != -1) rec_lms[li++] = x; 77 | } 78 | int rec_n = 1; 79 | std::vector rec_s(M); 80 | rec_s[M - 1 - is_lms[rec_lms[1]]] = 1; 81 | for(int i = 2;i < M;i++) { 82 | int xl = rec_lms[i]; 83 | int yl = rec_lms[i - 1]; 84 | int xr = lms[is_lms[xl] - 1]; 85 | int yr = lms[is_lms[yl] - 1]; 86 | if(xr - xl != yr - yl) 87 | rec_n++; 88 | else { 89 | while(xl <= xr) { 90 | if(s[xl] != s[yl]) { 91 | rec_n++; 92 | break; 93 | } 94 | xl++; 95 | yl++; 96 | } 97 | } 98 | rec_s[M - 1 - is_lms[rec_lms[i]]] = rec_n; 99 | } 100 | 101 | 102 | sa_is(std::move(rec_s), rec_n + 1); 103 | li = M; 104 | for(int i = 1;i < M + 1;i++) { 105 | rec_lms[--li] = lms[M - 1 - sa[i]]; 106 | } 107 | induce(rec_lms); 108 | } 109 | 110 | return sa; 111 | } 112 | -------------------------------------------------------------------------------- /src/string/suffix_array_search.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | const std::vector& sa_is(std::vector s, int k) { 6 | int N = s.size(); 7 | static std::vector sa; 8 | static std::vector cnt; 9 | sa.resize(N + 1); 10 | 11 | if(N == 0) return sa; 12 | 13 | for(auto& c: s) c++; 14 | s.push_back(0); 15 | k++; 16 | 17 | std::vector iss(N + 1); 18 | std::vector lms; 19 | std::vector is_lms(N + 1, -1); 20 | std::vector bin(k + 1); 21 | 22 | iss[N] = true; 23 | bin[1]++; 24 | for(int i = N; i --> 0; ) { 25 | if(s[i] == s[i + 1]) 26 | iss[i] = iss[i + 1]; 27 | else 28 | iss[i] = s[i] < s[i + 1]; 29 | if(!iss[i] && iss[i + 1]) { 30 | is_lms[i + 1] = lms.size(); 31 | lms.push_back(i + 1); 32 | } 33 | bin[s[i] + 1]++; 34 | } 35 | 36 | for(int i = 1;i <= k;i++) 37 | bin[i] += bin[i - 1]; 38 | 39 | auto induce = [&](const std::vector& lms) { 40 | sa.assign(N + 1, -1); 41 | cnt.assign(k, 0); 42 | 43 | for(int i = 0;i < lms.size();i++) { 44 | int x = lms[i]; 45 | sa[bin[s[x] + 1] - 1 - cnt[s[x]]] = x; 46 | cnt[s[x]]++; 47 | } 48 | 49 | cnt.assign(k, 0); 50 | for(int i = 0;i <= N;i++) { 51 | int x = sa[i] - 1; 52 | if(x >= 0 && !iss[x]) { 53 | sa[bin[s[x]] + cnt[s[x]]] = x; 54 | cnt[s[x]]++; 55 | } 56 | } 57 | 58 | cnt.assign(k, 0); 59 | for(int i = N + 1;i --> 0;) { 60 | int x = sa[i] - 1; 61 | if(x >= 0 && iss[x]) { 62 | sa[bin[s[x] + 1] - 1 - cnt[s[x]]] = x; 63 | cnt[s[x]]++; 64 | } 65 | } 66 | }; 67 | 68 | induce(lms); 69 | 70 | 71 | if(lms.size() >= 2) { 72 | int M = lms.size(); 73 | int li = 0; 74 | std::vector rec_lms(M); 75 | for(auto x: sa) { 76 | if(is_lms[x] != -1) rec_lms[li++] = x; 77 | } 78 | int rec_n = 1; 79 | std::vector rec_s(M); 80 | rec_s[M - 1 - is_lms[rec_lms[1]]] = 1; 81 | for(int i = 2;i < M;i++) { 82 | int xl = rec_lms[i]; 83 | int yl = rec_lms[i - 1]; 84 | int xr = lms[is_lms[xl] - 1]; 85 | int yr = lms[is_lms[yl] - 1]; 86 | if(xr - xl != yr - yl) 87 | rec_n++; 88 | else { 89 | while(xl <= xr) { 90 | if(s[xl] != s[yl]) { 91 | rec_n++; 92 | break; 93 | } 94 | xl++; 95 | yl++; 96 | } 97 | } 98 | rec_s[M - 1 - is_lms[rec_lms[i]]] = rec_n; 99 | } 100 | 101 | 102 | sa_is(std::move(rec_s), rec_n + 1); 103 | li = M; 104 | for(int i = 1;i < M + 1;i++) { 105 | rec_lms[--li] = lms[M - 1 - sa[i]]; 106 | } 107 | induce(rec_lms); 108 | } 109 | 110 | return sa; 111 | } 112 | 113 | template 114 | struct suffix_array_search { 115 | int N; 116 | std::vector str; 117 | std::vector rnk; 118 | std::vector sa; 119 | std::vector lcp; 120 | 121 | 122 | std::vector seg; 123 | int seg_n; 124 | 125 | //sparse_table st; 126 | 127 | template 128 | suffix_array_search(I b, I e, int k): str(b, e) { 129 | N = str.size(); 130 | sa = sa_is(str, k); 131 | rnk.resize(N + 1); 132 | lcp.resize(N + 1); 133 | 134 | for(int i = 0;i < N + 1;i++) { 135 | rnk[sa[i]] = i; 136 | } 137 | lcp[0] = 0; 138 | int h = 0; 139 | 140 | for(int i = 0;i < N + 1;i++) { 141 | if(rnk[i] + 1 < N + 1) { 142 | int j = sa[rnk[i] + 1]; 143 | for(; j + h < N + 1 && i + h < N + 1; h++) { 144 | if(str[j + h] != str[i + h]) break; 145 | } 146 | lcp[rnk[i] + 1] = h; 147 | if(h > 0) h--; 148 | } 149 | } 150 | } 151 | 152 | void build_segment() { 153 | seg_n = 1; 154 | while(seg_n < N + 1) seg_n <<= 1; 155 | seg.resize(seg_n * 2, 1e9); 156 | for(int i = 0;i + 1 < N + 1;i++) { 157 | seg[i + seg_n - 1] = lcp[i + 1]; 158 | } 159 | for(int i = seg_n - 1; i --> 0;) { 160 | seg[i] = std::min(seg[(i << 1) + 1], seg[(i << 1) + 2]); 161 | } 162 | } 163 | 164 | int compare(const std::vector& t, int pos) { 165 | int i = 0; 166 | while(pos + i < str.size() && i < t.size()) { 167 | if(str[pos + i] < t[i]) { 168 | return 1; 169 | } 170 | else if(str[pos + i] > t[i]) { 171 | return -1; 172 | } 173 | i++; 174 | } 175 | if(i == t.size()) return 0; 176 | else return 1; 177 | } 178 | 179 | 180 | // fast! 181 | bool contain(const std::vector& t) { 182 | int L = 0; 183 | int R = sa.size(); 184 | while(R - L > 1) { 185 | int M = (L + R) >> 1; 186 | if(compare(t, sa[M]) >= 0) { 187 | L = M; 188 | } 189 | else { 190 | R = M; 191 | } 192 | } 193 | return compare(t, sa[L]) == 0; 194 | } 195 | }; 196 | -------------------------------------------------------------------------------- /src/string/z-algorithm.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | 5 | vector z_algorithm(string S) { 6 | vector A(S.size()); 7 | A[0] = S.size(); 8 | int i = 1, j = 0; 9 | while (i < S.size()) { 10 | while (i+j < S.size() && S[j] == S[i+j]) ++j; 11 | A[i] = j; 12 | if (j == 0) { ++i; continue;} 13 | int k = 1; 14 | while (i+k < S.size() && k+A[k] < j) A[i+k] = A[k], ++k; 15 | i += k; j -= k; 16 | } 17 | return A; 18 | } 19 | -------------------------------------------------------------------------------- /src/tech/compression.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | struct Compression { 5 | using size_type = std::size_t; 6 | 7 | std::vector v; 8 | 9 | Compression(){} 10 | void add(const T& t) { v.push_back(t); } 11 | void build() { 12 | sort(begin(v), end(v)); 13 | v.erase(unique(begin(v), end(v)), end(v)); 14 | } 15 | size_type comp(const T& x) const { 16 | return lower_bound(begin(v), end(v), x) - begin(v); 17 | } 18 | size_type size() const { return v.size(); } 19 | }; 20 | -------------------------------------------------------------------------------- /src/tech/mo.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using i64 = long long; 4 | #define rep(i,s,e) for(i64 (i) = (s);(i) < (e);(i)++) 5 | #define rev(i,s,e) for(i64 (i) = (e); (i)-- > (s);) 6 | #define all(x) x.begin(),x.end() 7 | 8 | struct Mo { 9 | vector left, right, order; 10 | vector v; 11 | 12 | 13 | const i64 width; 14 | i64 nl, nr, ptr; 15 | 16 | vector a; 17 | vector cnt; 18 | i64 ans; 19 | 20 | Mo(i64 n, vector a) : v(n), width((i64)sqrt(n)), nl(0), nr(0), ptr(0), a(a), cnt(1010101), ans(0) {} 21 | 22 | void add_query(i64 l, i64 r) { 23 | left.push_back(l); 24 | right.push_back(r); 25 | } 26 | 27 | void build() { 28 | order.resize(left.size()); 29 | for(i64 i = 0;i < left.size();i++) order[i] = i; 30 | sort(begin(order), end(order), [&](i64 a, i64 b) { 31 | if(left[a] / width != left[b] / width) return left[a] < left[b]; 32 | else return right[a] < right[b]; 33 | }); 34 | } 35 | 36 | 37 | void add(i64 idx) { 38 | if(cnt[a[idx]]++ == 0) ans++; 39 | } 40 | void del(i64 idx) { 41 | if(--cnt[a[idx]] == 0) ans--; 42 | } 43 | 44 | inline void distribute(i64 idx) { 45 | v[idx].flip(); 46 | if(v[idx]) add(idx); 47 | else del(idx); 48 | } 49 | 50 | i64 process() { 51 | if(ptr == order.size()) return -1; 52 | const auto id = order[ptr]; 53 | while(nl > left[id]) distribute(--nl); 54 | while(nr < right[id]) distribute(nr++); 55 | while(nl < left[id]) distribute(nl++); 56 | while(nr > right[id]) distribute(--nr); 57 | return order[ptr++]; 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /src/tech/rerooting.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | std::vector rerooting(const std::vector>& G, int r, U ide, To to, Adj adj, Ope ope, Merge merge) { 5 | int N = G.size(); 6 | std::vector tdp(N); 7 | std::vector par(N, -1); 8 | std::vector que(N); 9 | int qi = 0; 10 | que[qi++] = r; 11 | 12 | int MAX = 1; 13 | for(int i = 0;i < qi;i++) { 14 | int v = que[i]; 15 | for(const auto& e: G[v]) { 16 | int t = to(e); 17 | if(t == par[v]) continue; 18 | par[t] = v; 19 | que[qi++] = t; 20 | } 21 | MAX = std::max(MAX, (int)G[v].size() + 1); 22 | } 23 | 24 | for(int i = qi; i --> 0;) { 25 | int v = que[i]; 26 | U sum = ide; 27 | for(const auto& e : G[v]) { 28 | int t = to(e); 29 | if(t == par[v]) continue; 30 | sum = ope(sum, adj(tdp[t], e)); 31 | } 32 | tdp[v] = merge(sum, v); 33 | } 34 | 35 | std::vector f(MAX); 36 | std::vector b(MAX); 37 | 38 | for(int i = 0; i < qi; i++) { 39 | int v = que[i]; 40 | for(int j = 0;j < G[v].size();j++) { 41 | int t = to(G[v][j]); 42 | f[j + 1] = adj(tdp[t == par[v] ? v : t], G[v][j]); 43 | } 44 | b[G[v].size()] = ide; 45 | for(int j = G[v].size(); j --> 0;) b[j] = ope(f[j + 1], b[j + 1]); 46 | f[0] = ide; 47 | for(int j = 0;j < G[v].size(); j++) { 48 | int t = to(G[v][j]); 49 | f[j + 1] = ope(f[j], f[j + 1]); 50 | if(t != par[v]) { 51 | tdp[t] = merge(ope(f[j], b[j + 1]), v); 52 | } 53 | } 54 | tdp[v] = merge(f[G[v].size()], v); 55 | } 56 | return tdp; 57 | } 58 | --------------------------------------------------------------------------------