0% found this document useful (0 votes)
89 views34 pages

Kactl

The document contains a comprehensive outline of various mathematical and programming concepts, including equations, data structures, numerical methods, and combinatorial problems. It provides guidelines for troubleshooting and optimizing algorithms, as well as specific mathematical formulas and definitions. The content appears to be aimed at students or participants in a programming contest or mathematics competition.

Uploaded by

Iván Renison
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
89 views34 pages

Kactl

The document contains a comprehensive outline of various mathematical and programming concepts, including equations, data structures, numerical methods, and combinatorial problems. It provides guidelines for troubleshooting and optimizing algorithms, as well as specific mathematical formulas and definitions. The content appears to be aimed at students or participants in a programming contest or mathematics competition.

Uploaded by

Iván Renison
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 34

Universidad Nacional De Córdoba

Gracias Mateo
Antonio Mondejar, Pietro Palombini, Iván Renison

2025-04-20
1 Contest 1 8.4 Misc. Point Set Problems . . . . . . . . . . . . . . 26 troubleshoot.txt 52 lines
8.5 3D . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Pre-submit:
2 Mathematics 1 Write a few simple test cases if sample is not enough.
Are time limits close? If so, generate max cases.
2.1 Equations . . . . . . . . . . . . . . . . . . . . . . . 1 9 Strings 27 Is the memory usage fine?
2.2 Recurrences . . . . . . . . . . . . . . . . . . . . . . 1 Could anything overflow?
2.3 Trigonometry . . . . . . . . . . . . . . . . . . . . . 1 10 Various 29 Make sure to submit the right file.
2.4 Geometry . . . . . . . . . . . . . . . . . . . . . . . 1 10.1 Dates . . . . . . . . . . . . . . . . . . . . . . . . . 29 Wrong answer:
2.5 Derivatives/Integrals . . . . . . . . . . . . . . . . . 2 10.2 Intervals . . . . . . . . . . . . . . . . . . . . . . . . 29 Print your solution! Print debug output, as well.
2.6 Sums . . . . . . . . . . . . . . . . . . . . . . . . . . 2 10.3 Misc. algorithms . . . . . . . . . . . . . . . . . . . 30 Are you clearing all data structures between test cases?
Can your algorithm handle the whole range of input?
2.7 Series . . . . . . . . . . . . . . . . . . . . . . . . . 2 10.4 Dynamic programming . . . . . . . . . . . . . . . . 30 Read the full problem statement again.
2.8 Probability theory . . . . . . . . . . . . . . . . . . 2 10.5 Debugging tricks . . . . . . . . . . . . . . . . . . . 30 Do you handle all corner cases correctly?
Have you understood the problem correctly?
2.9 Markov chains . . . . . . . . . . . . . . . . . . . . 3 10.6 Optimization tricks . . . . . . . . . . . . . . . . . . 30 Any uninitialized variables?
Any overflows?
3 Data structures 3 Contest (1) Confusing N and M, i and j, etc.?
Are you sure your algorithm works?
What special cases have you not thought of?
4 Numerical 7 template.cpp 18 lines Are you sure the STL functions you use work as you think?
4.1 Polynomials and recurrences . . . . . . . . . . . . . 7 #include <bits/stdc++.h> Add some assertions, maybe resubmit.
using namespace std; Create some testcases to run your algorithm on.
4.2 Optimization . . . . . . . . . . . . . . . . . . . . . 7 Go through the algorithm for a simple case.
4.3 Matrices . . . . . . . . . . . . . . . . . . . . . . . . 8 #define fst first Go through this list again.
4.4 Fourier transforms . . . . . . . . . . . . . . . . . . 10 #define snd second Explain your algorithm to a teammate.
#define pb push_back Ask the teammate to look at your code.
#define fore(i, a, b) for (ll i = a, gmat = b; i < gmat; i++) Go for a small walk, e.g. to the toilet.
5 Number theory 11 #define ALL(x) x.begin(), x.end() Is your output format correct? (including whitespace)
#define SZ(x) (ll)(x).size() Rewrite your solution from the start or let a teammate do it.
5.1 Modular arithmetic . . . . . . . . . . . . . . . . . . 11
#define mset(a, v) memset((a), (v), sizeof(a))
5.2 Primality . . . . . . . . . . . . . . . . . . . . . . . 12 typedef long long ll; Runtime error:
5.3 Divisibility . . . . . . . . . . . . . . . . . . . . . . 12 typedef pair<ll, ll> ii; Have you tested all corner cases locally?
typedef vector<ll> vi; Any uninitialized variables?
5.4 Fractions . . . . . . . . . . . . . . . . . . . . . . . 13 Are you reading or writing outside the range of any vector?
5.5 Pythagorean Triples . . . . . . . . . . . . . . . . . 13 int main() { Any assertions that might fail?
5.6 Primes . . . . . . . . . . . . . . . . . . . . . . . . . 13 cin.tie(0)->sync_with_stdio(0); Any possible division by 0? (mod 0 for example)
Any possible infinite recursion?
5.7 Highly composite numbers . . . . . . . . . . . . . . 13 } Invalidated pointers or iterators?
5.8 Mobius Function . . . . . . . . . . . . . . . . . . . 13 Are you using too much memory?
hash.sh Debug with resubmits (e.g. remapped signals, see Various).
3 lines
6 Combinatorial 13 # Hashes a f i l e , ignoring a l l whitespace and comments. Use for Time limit exceeded:
6.1 Permutations . . . . . . . . . . . . . . . . . . . . . 13 # verifying that code was correctly typed . Do you have any possible infinite loops?
cpp -dD -P -fpreprocessed | tr -d ’[:space:]’| md5sum |cut -c-6 What is the complexity of your algorithm?
6.2 Partitions and subsets . . . . . . . . . . . . . . . . 14 Are you copying a lot of unnecessary data? (References)
6.3 General purpose numbers . . . . . . . . . . . . . . 14 problemInteraction.sh How big is the input and output? (consider scanf)
3 lines Avoid vector, map. (use arrays/unordered_map)
6.4 Game theory . . . . . . . . . . . . . . . . . . . . . 14
# For interactive problems What do your teammates think about your algorithm?
mkfifo fifo
7 Graph 14 (./solution < fifo) | (./interactor > fifo) Memory limit exceeded:
What is the max amount of memory your algorithm should need?
7.1 Fundamentals . . . . . . . . . . . . . . . . . . . . . 14 Are you clearing all data structures between test cases?
7.2 Network flow . . . . . . . . . . . . . . . . . . . . . 15 tester.py 15 lines

7.3 Matching . . . . . . . . . . . . . . . . . . . . . . . 17 from os import system


7.4 DFS algorithms . . . . . . . . . . . . . . . . . . . . 17 it = 100000 Mathematics (2)
7.5 Coloring . . . . . . . . . . . . . . . . . . . . . . . . 18 for t in range(it):
7.6 Heuristics . . . . . . . . . . . . . . . . . . . . . . . 18 system("./caseGen > in")

7.7 Trees . . . . . . . . . . . . . . . . . . . . . . . . . . 19
system("./good < in > o")
system("./bad < in > o2")
2.1 Equations
7.8 Math . . . . . . . . . . . . . . . . . . . . . . . . . . 22 x = open("o", "r").read().strip().split() √
y = open("o2", "r").read().strip().split() 2 −b ± b2 − 4ac
ax + bx + c = 0 ⇒ x =
8 Geometry 22 for i in range(len(x)): 2a
8.1 Geometric primitives . . . . . . . . . . . . . . . . . 23 if (x[i] != y[i]):
print("FAILED!!!!!", i + 1)
8.2 Circles . . . . . . . . . . . . . . . . . . . . . . . . . 24 exit(0)
8.3 Polygons . . . . . . . . . . . . . . . . . . . . . . . . 24 print("ok", t + 1) The extremum is given by x = −b/2a.
UNC template hash problemInteraction tester troubleshoot 2025-04-20 2
2.4.2 Triangles 2.5 Derivatives/Integrals
ed − bf Side lengths: a, b, c
ax + by = e x=
ad − bc a+b+c d 1 d 1
⇒ Semiperimeter: p = arcsin x = √ arccos x = − √
cx + dy = f af − ec 2 dx dx
y= p
Area: A = p(p − a)(p − b)(p − c) 1 − x2 1 − x2
ad − bc
abc d d 1
Circumradius: R = tan x = 1 + tan2 x arctan x =
4A dx dx 1 + x2
In general, given an equation Ax = b, the solution to a variable A Z Z
Inradius: r = ln | cos ax| sin ax − ax cos ax
xi is given by tan ax = − x sin ax =
p a a2
det A′i Length √of median (divides triangle into two equal-area triangles): √
xi = Z
2 π
Z
e ax
det A ma = 12 2b2 + 2c2 − a2 e−x = erf(x) xeax dx = 2 (ax − 1)
2 a
where A′i is A with the i’th column replaced by b. Length
v of "bisector (divides angles in two):
u  2 #
a
2.2 Recurrences
u
sa = tbc 1 − Integration by parts:
b+c
If an = c1 an−1 + · · · + ck an−k , and r1 , . . . , rk are distinct roots of
xk − c1 xk−1 − · · · − ck , there are d1 , . . . , dk s.t. sin α sin β sin γ 1 b b
Law of sines: = = =
Z Z
a b c 2R f (x)g(x)dx = [F (x)g(x)]ba − F (x)g ′ (x)dx
an = d1 r1n + ··· + dk rkn . Law of cosines: a2 = b2 + c2 − 2bc cos α a a
2.4.3 Quadrilaterals tan α + β
Non-distinct roots r become polynomial factors, e.g. With
Law ofside lengths aa,+b,bc,=d, diagonals
tangents: 2 e, f , diagonals angle θ, area
a − b
A and magic flux F = b +tan 2 2 α −2β
d − a − c2 : 2.6 Sums
an = (d1 n + d2 )rn . 2 cb+1 − ca
ca + ca+1 + · · · + cb = , c ̸= 1
2.3 Trigonometry c−1

sin(v + w) = sin v cos w + cos v sin w


n(n + 1)
cos(v + w) = cos v cos w − sin v sin w 1 + 2 + 3 + ··· + n =
2
p 2 2 2 2 n(2n + 1)(n + 1)
4A = 2ef · sin θ = F tan θ = 4e2 f 2 − F 2 1 + 2 + 3 + ··· + n =
6
3 3 3 3 n2 (n + 1)2
tan v + tan w 1 + 2 + 3 + ··· + n =
tan(v + w) = 4
1 − tan v tan w
v+w v−w 4 4 4 4 n(n + 1)(2n + 1)(3n2 + 3n − 1)
sin v + sin w = 2 sin cos 1 + 2 + 3 + ··· + n =
2 2 30
2.4.4 Spherical coordinates
v+w v−w
cos v + cos w = 2 cos cos For cyclic quadrilateralspthe sum of opposite angles is 180◦ ,
2 2
ef = ac + bd, and A = (p − a)(p − b)(p − c)(p − d).
(V + W ) tan(v − w)/2 = (V − W ) tan(v + w)/2 z 2.7 Series
r x2 x3
where V, W are lengths of sides opposite angles v, w. ex = 1 + x + + + . . . , (−∞ < x < ∞)
y 2! 3!
a cos x + b sin x = r cos(x − ϕ)
x2 x3 x4
a sin x + b cos x = r sin(x + ϕ) x ln(1 + x) = x −
2
+
3

4
+ . . . , (−1 < x ≤ 1)

where r = a2 + b2 , ϕ = atan2(b, a). √ x x2 2x3 5x4
1+x=1+ − + − + . . . , (−1 ≤ x ≤ 1)
2.4 Geometry 2 8 32 128
2.4.1 Pick’s theorem x3 x5 x7
Given a simple polygon with vertices with integer coordinates, its sin x = x − + − + . . . , (−∞ < x < ∞)
3! 5! 7!
area is I + B2 − 1, where I is the number of integer points inside
p
x = r sin θ cos ϕ r = xp 2 + y2 + z2

the polygon and B is the number of integer points on the y = r sin θ sin ϕ θ = acos(z/ x2 + y 2 + z 2 ) x2 x4 x6
boundary. z = r cos θ ϕ = atan2(y, x) cos x = 1 − + − + . . . , (−∞ < x < ∞)
2! 4! 6!
UNC OrderStatisticTree HashMap rope SegmentTree 2025-04-20 3
2.8 Probability theory 2.8.2 Continuous distributions A Markov chain is an A-chain if the states can be partitioned
Let X be a discrete random variable with probability pX (x) of Uniform distribution into two sets A and G, such that all states in A are absorbing
assuming theP value x. It will then have an expected value (mean) (pii = 1), and all states in G leads to an absorbing state in A.
If the probability density function is constant between a and b
µ = E(X) = x xpX (x) and variance The probability for absorption in state i ∈ A, when the initial
and 0 elsewhere it is U(a, b), a < b. P
σ 2 = V (X) = E(X 2 ) − (E(X))2 = x (x − E(X))2 pX (x) where σ state is j, is aij = pij + k∈G aik pkj . The expected
P time until
P
absorption, when the initial state is i, is ti = 1 + k∈G pki tk .
 1
is the standard deviation. If X is instead continuous it will have b−a
a<x<b
f (x) =
a probability density function fX (x) and the sums above will 0 otherwise
instead be integrals with pX (x) replaced by fX (x).
a+b 2 (b − a)2 Data structures (3)
Expectation is linear: µ= ,σ =
2 12
OrderStatisticTree.h
E(aX + bY ) = aE(X) + bE(Y ) Exponential distribution Description: A set (not multiset!) with support for finding the n’th ele-
ment, and finding the index of an element. To get a map, change null type.
The time between events in a Poisson process is Time: O (log N ) ac5104, 16 lines
For independent X and Y , Exp(λ), λ > 0. #include "ext/pb_ds/assoc_container.hpp"
λe−λx x ≥ 0

using namespace __gnu_pbds;
f (x) =
V (aX + bY ) = a2 V (X) + b2 V (Y ). 0 x<0
template<class T>
1 1 using Tree = tree<T, null_type, less<T>, rb_tree_tag,
µ = , σ2 = 2 tree_order_statistics_node_update>;
2.8.1 Discrete distributions λ λ
Binomial distribution Normal distribution
void example() {
Tree<ll> t, t2; t.insert(8);
The number of successes in n independent yes/no experiments, Most real random values with mean µ and variance σ 2 are well auto it = t.insert(10).fst;
assert(it == t.lower_bound(9));
each which yields success with probability p is described by N (µ, σ 2 ), σ > 0. assert(t.order_of_key(10) == 1);
Bin(n, p), n = 1, 2, . . . , 0 ≤ p ≤ 1. assert(t.order_of_key(11) == 2);
1 (x−µ)2 assert(*t.find_by_order(0) == 8);

! f (x) = √ e 2σ2 t.join(t2); // assuming T < T2 or T > T2, merge t2 into t
n k 2πσ 2 }
p(k) = p (1 − p)n−k
k If X1 ∼ N (µ1 , σ12 ) and X2 ∼ N (µ2 , σ22 ) then
HashMap.h
Description: Hash map with mostly the same API as unordered map, but
aX1 + bX2 + c ∼ N (µ1 + µ2 + c, a2 σ12 + b2 σ22 ) ∼3x faster. Uses 1.5x memory. Initial capacity must be a power of 2 (if
µ = np, σ 2 = np(1 − p) provided). 23cd06, 7 lines

Bin(n, p) is approximately Po(np) for small p.


2.9 Markov chains #include "ext/pb_ds/assoc_container.hpp"
A Markov chain is a discrete random process with the property // To use most b i t s rather than j u s t the lowest ones :
First success distribution struct chash { // large odd number for C
that the next state depends only on the current state. Let const uint64_t C = ll(4e18 * acos(0)) | 71;
The number of trials needed to get the first success in X1 , X2 , . . . be a sequence of random variables generated by the ll operator()(ll x) const { return __builtin_bswap64(x*C); }
independent yes/no experiments, each which yields success with };
Markov process. Then there is a transition matrix P = (pij ), __gnu_pbds::gp_hash_table<ll,ll,chash> h({},{},{},{},{1<<16});
probability p is Fs(p), 0 ≤ p ≤ 1. with pij = Pr(Xn = i|Xn−1 = j), and p(n) = Pn p(0) is the
(n)
probability distribution for Xn (i.e., pi = Pr(Xn = i)), where rope.h
p(k) = p(1 − p)k−1 , k = 1, 2, . . . (0)
p is the initial distribution. Description: Sequence with O(log(n)) random access, insert, erase at any
position. Very high constant factors.
π is a stationary distribution if π = πP. If the Markov chain is Usage: s.pb(x);
1 2 1−p s.insert(i,r) // insert rope r at position i
µ= ,σ = irreducible (it is possible to get to any state from any state), then s.erase(i,k) // erase subsequence [i,i+k)
p p2 πi = E(T1 i ) where E(Ti ) is the expected time between two visits in s.substr(i,k) // return a new rope
s[i] // access ith element (cannot modify)
Poisson distribution state i. πj /πi is the expected number of visits in state j between s.mutable reference at(i)
two visits in state i. s.begin() and s.end() are const iterators
The number of events occurring in a fixed period of time t if these s.mutable begin(), s.mutable end() 4cbb8d, 3 lines
events occur with a known average rate κ and independently of For a connected, undirected and non-bipartite graph, where the #include <ext/rope>
the time since the last event is Po(λ), λ = tκ. transition probability is uniform among all neighbors, πi is using namespace __gnu_cxx;
proportional to node i’s degree. rope<ll> s;

λk
p(k) = e−λ , k = 0, 1, 2, . . . A Markov chain is ergodic if the asymptotic distribution is SegmentTree.h
k! independent of the initial distribution. A finite Markov chain is Description: Zero-indexed max-tree. Bounds are inclusive to the left and
exclusive to the right. Can be changed by modifying T, f and neut.
ergodic iff it is irreducible and aperiodic (i.e., the gcd of cycle Time: O (log N )
µ = λ, σ 2 = λ lengths is 1). limk→∞ Pk = 1π. 921f55, 19 lines
UNC LazySegmentTree MemoryLazySegmentTree PersistentSegmentTree SegmentTree2d 2025-04-20 4
struct Tree { ll m = (s + e) / 2; }
typedef ll T; upd(2*k, s, m, a, b, v), upd(2*k+1, m, e, a, b, v); l->lazy = comb(l->lazy, lazy);
static constexpr T neut = LONG_LONG_MIN; st[k] = f(st[2*k], st[2*k+1]); r->lazy = comb(r->lazy, lazy);
T f(T a, T b) { return max(a, b); } // (any associative fn ) } lazy = lneut;
vector<T> s; ll n; T query(ll k, ll s, ll e, ll a, ll b) { val = f(l->query(lo, hi), r->query(lo, hi));
Tree(ll n = 0, T def = neut) : s(2*n, def), n(n) {} if (s >= b || e <= a) return tneut; }
void upd(ll pos, T val) { push(k, s, e); };
for (s[pos += n] = val; pos /= 2;) if (s >= a && e <= b) return st[k];
s[pos] = f(s[pos * 2], s[pos * 2 + 1]); ll m = (s + e) / 2;
} return f(query(2*k, s, m, a, b),query(2*k+1, m, e, a, b)); PersistentSegmentTree.h
T query(ll b, ll e) { // query [ b , e) } Description: Max segment tree in which each update creates a new version
T ra = neut, rb = neut; void upd(ll a, ll b, L v) { upd(1, 0, n, a, b, v); } of the tree and you can query and update on any version of the tree. Can be
for (b += n, e += n; b < e; b /= 2, e /= 2) { T query(ll a, ll b) { return query(1, 0, n, a, b); } changed by modifying T, f and unit.
if (b % 2) ra = f(ra, s[b++]); }; Usage: Tree rmq(n);
if (e % 2) rb = f(s[--e], rb); ver = rmq.init(xs);
} new ver = rmq.upd(ver, i, x);
MemoryLazySegmentTree.h rmq.query(ver, l, u);
return f(ra, rb); Description: Segment tree with ability to add or set values of large inter-
} Time: O (log N ) 83b8e4, 43 lines
vals, and compute max of intervals. Can be changed to other things. Use
}; with a bump allocator for better performance, and SmallPtr or implicit in- struct Tree {
dices to save memory. typedef ll T;
Usage: Node* tr = new Node(v, 0, SZ(v)); static constexpr T neut = LONG_LONG_MIN;
LazySegmentTree.h Time: O (log N ). T f(T a, T b) { return max(a, b); } // (any associative fn )
Description: Segment tree with ability to add values of large intervals, and "../various/BumpAllocator.h" a87495, 53 lines
compute the sum of intervals. Ranges are [s, e). Can be changed to other vector<T> st;
things. const ll inf = 1e18;
struct Node { vi L, R;
Usage: Tree st(n); ll n, rt;
st.init(x); typedef ll T; // data type
struct L { ll toset, toadd; }; // lazy type Tree(ll n) : st(1, neut), L(1), R(1), n(n), rt(0) {}
st.upd(s, e, v); ll new_node(T v, ll l, ll r) {
st.query(s, e); const T tneut = -inf; // neutral elements
const L lneut = {inf, 0}; st.pb(v), L.pb(l), R.pb(r);
Time: O (log N ). 0fc20e, 53 lines return SZ(st) - 1;
T f (T a, T b) { return max(a, b); } // (any associative fn )
typedef ll T; typedef ll L; // T: data type , L: lazy type T apply (T a, L b) { }
const T tneut = 0; const L lneut = 0; // neutrals return b.toset != inf ? b.toset + b.toadd : a + b.toadd; // not necessary in most cases
T f(T a, T b) { return a + b; } // associative } // Apply lazy ll init(ll s, ll e, vector<T>& a) {
T apply(T v, L l, ll s, ll e) { // new s t according to lazy L comb(L a, L b) { if (s + 1 == e) return new_node(a[s], 0, 0);
return v + l * (e - s); } if (b.toset != inf) return b; ll m = (s + e) / 2, l = init(s, m, a), r = init(m, e, a);
L comb(L a, L b) { return a + b; } // cumulative e f f e c t of lazy return {a.toset, a.toadd + b.toadd}; return new_node(f(st[l], st[r]), l, r);
} // Combine lazy }
struct Tree { // example : range sum with range addition ll upd(ll k, ll s, ll e, ll p, T v) {
ll n; Node *l = 0, *r = 0; ll ks = new_node(st[k], L[k], R[k]);
vector<T> st; ll lo, hi; T val = tneut; L lazy = lneut; if (s + 1 == e) {
vector<L> lazy; Node(ll lo,ll hi):lo(lo),hi(hi) {} //Large interval of tneut st[ks] = v;
Tree(ll n) : n(n), st(4*n, tneut), lazy(4*n, lneut) {} Node(vector<T>& v, ll lo, ll hi) : lo(lo), hi(hi) { return ks;
Tree(vector<T> &a) : n(SZ(a)), st(4*n), lazy(4*n, lneut) { if (lo + 1 < hi) { }
init(1, 0, n, a); ll mid = lo + (hi - lo)/2; ll m = (s + e) / 2;
} l = new Node(v, lo, mid); r = new Node(v, mid, hi); if (p < m) L[ks] = upd(L[ks], s, m, p, v);
void init(ll k, ll s, ll e, vector<T> &a) { val = f(l->val, r->val); else R[ks] = upd(R[ks], m, e, p, v);
lazy[k] = lneut; } st[ks] = f(st[L[ks]], st[R[ks]]);
if (s + 1 == e) { st[k] = a[s]; return; } else val = v[lo]; return ks;
ll m = (s + e) / 2; } }
init(2*k, s, m, a), init(2*k+1, m, e, a); T query(ll L, ll R) { T query(ll k, ll s, ll e, ll a, ll b) {
st[k] = f(st[2*k], st[2*k+1]); if (R <= lo || hi <= L) return tneut; if (e <= a || b <= s) return neut;
} if (L <= lo && hi <= R) return apply(val, lazy); if (a <= s && e <= b) return st[k];
void push(ll k, ll s, ll e) { push(); ll m = (s + e) / 2;
if (lazy[k] == lneut) return; // i f neutral , nothing to do return f(l->query(L, R), r->query(L, R)); return f(query(L[k], s, m, a, b), query(R[k], m, e, a, b));
st[k] = apply(st[k], lazy[k], s, e); } }
if (s + 1 < e) { // propagate to children void upd(ll Le, ll Ri, L x) { ll init(vector<T>& a) { return init(0, n, a); }
lazy[2*k] = comb(lazy[2*k], lazy[k]); if (Ri <= lo || hi <= Le) return; ll upd(ll ver, ll p, T v) {return rt = upd(ver, 0, n, p, v);}
lazy[2*k+1] = comb(lazy[2*k+1], lazy[k]); if (Le <= lo && hi <= Ri) lazy = comb(lazy, x); // upd on l a s t root
} else { ll upd(ll p, T v) { return upd(rt, p, v); }
lazy[k] = lneut; // clear node lazy push(), l->upd(Le, Ri, x), r->upd(Le, Ri, x); T query(ll ver, ll a, ll b) {return query(ver, 0, n, a, b);}
} val = f(l->query(lo, hi), r->query(lo, hi)); };
void upd(ll k, ll s, ll e, ll a, ll b, L v) { }
push(k, s, e); } SegmentTree2d.h
if (s >= b || e <= a) return; void set(ll L, ll R, ll x) { upd(L, R, {x, 0}); } Description: Query sum of area ans make point updates. Bounds are in-
if (s >= a && e <= b) { void add(ll L, ll R, ll x) { upd(L, R, {inf, x}); } clusive to the left and exclusive to the right. Can be changed by modifying
lazy[k] = comb(lazy[k], v); // accumulate lazy void push() { T, f and unit.
push(k, s, e); if (!l) { Time: O (log N )
return; ll mid = lo + (hi - lo)/2; 4f243e, 37 lines

} l = new Node(lo, mid), r = new Node(mid, hi); struct Tree2 {


UNC UnionFind UnionFindRollback UnionFindRollbackStore SubMatrix Matrix LineContainer 2025-04-20 5
typedef ll T; for (ll i = time(); i --> t;) p[r+1][c+1] = v[r][c] + p[r][c+1] + p[r+1][c] - p[r][c];
static constexpr T neut = 0; e[st[i].fst] = st[i].snd; }
T f(T a, T b) { return a + b; } // associative & commutative st.resize(t); T sum(ll u, ll l, ll d, ll r) {
} return p[d][r] - p[d][l] - p[u][r] + p[u][l];
ll n, m; bool join(ll a, ll b) { }
vector<vector<T>> a, st; a = find(a), b = find(b); };
Tree2(ll n, ll m) : n(n), m(m), a(n, vector<T>(m)), if (a == b) return false;
st(2 * n, vector<T>(2 * m)) { if (e[a] > e[b]) swap(a, b);
fore(i, 0, n) fore(j, 0, m) st[i + n][j + m] = a[i][j]; st.pb({a, e[a]}), st.pb({b, e[b]}); Matrix.h
fore(i, 0, n) for (ll j = m; --j;) e[a] += e[b], e[b] = a; Description: Basic operations on square matrices.
st[i + n][j] = f(st[i + n][2 * j], st[i + n][2 * j + 1]); return true; Usage: Matrix<ll, 3> A;
for (ll i = n; --i;) fore(j, 0, 2 * m) } A.d = {{{{1,2,3}}, {{4,5,6}}, {{7,8,9}}}};
st[i][j] = f(st[2 * i][j], st[2 * i + 1][j]); }; array<ll, 3> vec = {1,2,3};
} vec = (AˆN) * vec; 5a57ed, 26 lines
void upd(ll x, ll y, T v) { template<class T, ll N> struct Matrix {
st[x + n][y + m] = v; UnionFindRollbackStore.h typedef Matrix M;
for (ll j = y + m; j > 1; j /= 2) Description: Disjoint-set data structure, with undo and support for storing
additional data in each component and global data. Default operations and array<array<T, N>, N> d{};
st[x + n][j / 2] = f(st[x + n][j], st[x + n][j ^ 1]); M operator*(const M& m) const {
for (x += n; x > 1; x /= 2) for (ll j = y + m; j; j /= 2) data are for sum in each component and count of components.
Time: O (log(N )) M a;
st[x / 2][j] = f(st[x][j], st[x ^ 1][j]); 9207a8, 34 lines fore(i,0,N) fore(j,0,N)
} typedef ll T; // Global data fore(k,0,N) a.d[i][j] += d[i][k]*m.d[k][j];
T query(ll x0, ll x1, ll y0, ll y1) { // [ x0 , x1) ∗ [ y0 , y1) typedef ll D; // Component data return a;
T r = neut; struct RSUF { }
for (x0 += n, x1 += n; x0 < x1; x0 /= 2, x1 /= 2) { T ans; // Global data i n i t i a l value , set in constructor array<T, N> operator*(const array<T, N>& vec) const {
ll t[4], q = 0; void merge(D& large, const D& small) { array<T, N> ret{};
if (x0 & 1) t[q++] = x0++; large = large + small, ans--; fore(i,0,N) fore(j,0,N) ret[i] += d[i][j] * vec[j];
if (x1 & 1) t[q++] = --x1; } return ret;
fore(k, 0, q) }
for (ll j0 = y0+m, j1 = y1+m; j0 < j1; j0/=2, j1/=2) { ll n; M operator^(ll p) const {
if (j0 & 1) r = f(r, st[t[k]][j0++]); vi e; vector<D> d; assert(p >= 0);
if (j1 & 1) r = f(r, st[t[k]][--j1]); vector<tuple<ll,ll,ll,D,T>> st; M a, b(*this);
} RSUF(ll n) : ans(n), n(n), e(n, -1), d(n) {} fore(i,0,N) a.d[i][i] = 1;
} RSUF(vector<D>& d) : ans(SZ(d)), n(SZ(d)), e(n,-1), d(d) {} while (p) {
return r; ll size(ll x) { return -e[find(x)]; } if (p&1) a = a*b;
} ll find(ll x) { return e[x] < 0 ? x : find(e[x]); } b = b*b;
}; ll time() { return SZ(st); } p >>= 1;
D get(ll x) { return d[find(x)]; } }
UnionFind.h void rollback(ll t) { return a;
Description: Disjoint-set data structure. while (SZ(st) > t) { }
Time: O (α(N )) auto [a, b, s, v, t] = st.back(); };
d49635, 14 lines st.pop_back();
struct UF { d[a] = v, e[a] -= e[b] = s, ans = t;
vi e; } LineContainer.h
UF(ll n) : e(n, -1) {} } Description: Container where you can add lines of the form kx+m, and
bool sameSet(ll a, ll b) { return find(a) == find(b); } bool join(ll a, ll b) { query maximum values at points x. Useful for dynamic programming (“con-
ll size(ll x) { return -e[find(x)]; } a = find(a), b = find(b); vex hull trick”).
ll find(ll x) { return e[x] < 0 ? x : e[x] = find(e[x]); } if (a == b) return false; Time: O (log N ) 8ec1c7, 31 lines
bool join(ll a, ll b) { if (e[a] > e[b]) swap(a, b); struct Line {
a = find(a), b = find(b); st.pb({a, b, e[b], d[a], ans}); mutable ll k, m, p;
if (a == b) return false; merge(d[a], d[b]); bool operator<(const Line& o) const { return k < o.k; }
if (e[a] > e[b]) swap(a, b); e[a] += e[b], e[b] = a; bool operator<(ll x) const { return p < x; }
e[a] += e[b], e[b] = a; return true; };
return true; }
} }; struct LineContainer : multiset<Line, less<>> {
}; // ( for doubles , use i nf = 1/.0 , div (a , b) = a/b)
SubMatrix.h static const ll inf = LLONG_MAX;
UnionFindRollback.h Description: Calculate submatrix sums quickly, given upper-left and lower- ll div(ll a, ll b) { // floored division
Description: Disjoint-set data structure with undo. If undo is not needed, right corners (half-open). return a / b - ((a ^ b) < 0 && a % b);
skip st, time() and rollback(). Usage: SubMatrix<ll> m(matrix); }
Usage: ll t = uf.time(); ...; uf.rollback(t); m.sum(0, 0, 2, 2); // top left 4 elements bool isect(iterator x, iterator y) {
Time: O (log(N )) Time: O N 2 + Q
 if (y == end()) return x->p = inf, 0;
41c6ec, 20 lines 2bb68d, 13 lines if (x->k == y->k) x->p = x->m > y->m ? inf : -inf;
struct RollbackUF { template<class T> else x->p = div(y->m - x->m, x->k - y->k);
vi e; vector<ii> st; struct SubMatrix { return x->p >= y->p;
RollbackUF(ll n) : e(n, -1) {} vector<vector<T>> p; }
ll size(ll x) { return -e[find(x)]; } SubMatrix(vector<vector<T>>& v) { void add(ll k, ll m) {
ll find(ll x) { return e[x] < 0 ? x : find(e[x]); } ll R = SZ(v), C = SZ(v[0]); auto z = insert({k, m, 0}), y = z++, x = y;
ll time() { return SZ(st); } p.assign(R+1, vector<T>(C+1)); while (isect(y, z)) z = erase(z);
void rollback(ll t) { fore(r,0,R) fore(c,0,C) if (x != begin() && isect(--x, y)) isect(x, y = erase(y));
UNC Treap FenwickTree FenwickTree2d RMQ FastRMQ 2025-04-20 6
2

while ((y = x) != begin() && (--x)->p >= y->p) return ret; Time: O log N . (Use persistent segment trees for O (log N ).)
isect(x, erase(y)); } else { "FenwickTree.h" 9abd20, 22 lines
} Node* ret = r->split(k - cnt - 1); // and j u s t ”k” struct FT2 {
ll query(ll x) { recalc(), ret->recalc(); vector<vi> ys; vector<FT> ft;
assert(!empty()); return ret; FT2(ll limx) : ys(limx) {}
auto l = *lower_bound(x); } void fakeUpd(ll x, ll y) {
return l.k * x + l.m; } for (; x < SZ(ys); x |= x + 1) ys[x].pb(y);
} void merge(Node* ri) { }
}; if (!ri) return; void init() {
push(), ri->push(); for (vi& v : ys) sort(ALL(v)), ft.pb(SZ(v));
if (y > ri->y) { }
Treap.h if (r) r->merge(ri); ll ind(ll x, ll y) {
Description: A short self-balancing tree. It acts as a sequential container else r = ri; return (ll)(lower_bound(ALL(ys[x]), y) - ys[x].begin()); }
with log-time splits, joins, queries and updates. Can also support reversals } else { void upd(ll x, ll y, ll dif) {
with the commented REVERSE lines and getting the position of a node with merge(ri->l); for (; x < SZ(ys); x |= x + 1)
the PARENT lines. ri->l = ri; ft[x].upd(ind(x, y), dif);
Time: O (log N ) aa40e9, 86 lines
swap(*this, *ri); }
} ll query(ll x, ll y) {
typedef ll T; typedef ll L; // T: data type , L: lazy type recalc();
const T tneut = 0; const L lneut = 0; // neutrals ll sum = 0;
} for (; x; x &= x - 1)
T f(T a, T b) { return a + b; } // associative // l l pos () { // In which position I am // PARENT
T apply(T v, L l, ll len) { // new s t according to lazy sum += ft[x-1].query(ind(x-1, y));
// p u l l A l l () ; return sum;
return v + l * len; } // l l ans = l ? l−>c : 0;
L comb(L a, L b) { return a + b; } // cumulative e f f e c t of lazy }
// i f ( ! p) return ans ; };
// i f (p−>r == t h i s ) return ans + p−>pos () + 1;
struct Node { // e l s e return p−>pos () + 1 − ( r ? r−>c : 0) ;
Node *l = 0, *r = 0; // } RMQ.h
// Node ∗p = 0; // PARENT T query() { // Query f u l l range Description: Range Minimum Queries on an array. Returns min(V[a], V[a
T val, acc; L lazy = lneut; push(); + 1], ... V[b - 1]) in constant time.
ll y, c = 1; return acc; Usage: RMQ rmq(values);
// bool rev = f a l s e ; // REVERSE } rmq.query(inclusive, exclusive);
Node(T val = tneut) : val(val), acc(val), y(rand()) {} void upd(L v) { lazy = comb(lazy, v); } // Update f u l l range Time: O (|V | log |V | + Q) e0b6d1, 16 lines
void recalc() { // void reverse () { rev = ! rev ; } // REVERSE
c = 1, acc = tneut; template<class T>
}; struct RMQ {
if (l) l->push(), acc = f(acc, l->acc), c += l->c;
acc = f(acc, val); vector<vector<T>> jmp;
if (r) r->push(), acc = f(acc, r->acc), c += r->c; RMQ(const vector<T>& V) : jmp(1, V) {
// i f ( l ) l−>p = t h i s ; // PARENT
FenwickTree.h for (ll pw = 1, k = 1; pw * 2 <= SZ(V); pw *= 2, ++k) {
Description: Computes partial sums a[0] + a[1] + ... + a[pos - 1], and
// i f ( r ) r−>p = t h i s ; jmp.emplace_back(SZ(V) - pw * 2 + 1);
updates single elements a[i], taking the difference between the old and new
} fore(j,0,SZ(jmp[k]))
value.
void push() { jmp[k][j] = min(jmp[k - 1][j], jmp[k - 1][j + pw]);
Time: Both operations are O (log N ). 669a70, 22 lines }
// i f ( rev ) { // REVERSE
// swap( l , r ) , rev = f a l s e ; struct FT { }
// i f ( l ) l−>rev ^= 1; i f ( r ) r−>rev ^= 1; vi s; T query(ll a, ll b) {
// } FT(ll n) : s(n) {} assert(a < b); // or return i nf i f a == b
val = apply(val, lazy, 1), acc = apply(acc, lazy, c); void upd(ll pos, ll dif) { // a [ pos ] += d i f ll dep = 63 - __builtin_clzll(b - a);
if (l) l->lazy = comb(l->lazy, lazy); for (; pos < SZ(s); pos |= pos + 1) s[pos] += dif; return min(jmp[dep][a], jmp[dep][b - (1 << dep)]);
if (r) r->lazy = comb(r->lazy, lazy); } }
lazy = lneut; ll query(ll pos) { // sum of values in [0 , pos) };
} ll res = 0;
// void p u l l A l l () { // PARENT for (; pos > 0; pos &= pos - 1) res += s[pos-1]; FastRMQ.h
// i f (p) p−>p u l l A l l () ; return res; Description: Like RMQ but with construction O(|V |) and slower queries.
// push() ; } Time: O (|V | + Q)
// } ll lower_bound(ll sum) {// min pos s t sum of [0 , pos ] >= sum f4bfbf, 40 lines

// Returns n i f no sum i s >= sum, or −1 i f empty sum i s . template<class T>


Node* split(ll k) { if (sum <= 0) return -1; struct RMQ {
assert(k > 0); ll pos = 0; ll n;
if (k >= c) return 0; for (ll pw = 1 << 25; pw; pw >>= 1) { static constexpr T inf = 1e9; // change sign of in f for max
push(); if (pos + pw <= SZ(s) && s[pos + pw-1] < sum) vector<ll> mk;
ll cnt = l ? l->c : 0; pos += pw, sum -= s[pos-1]; vector<T> bk, v;
if (k <= cnt) { // ”k <= val” for lower bound(k) } ll f(ll x) { return x >> 5; }
Node* nl = l->split(k),* ret = l; return pos; RMQ(vector<T>& V) : n(SZ(V)), mk(n), bk(n, inf), v(V) {
l = nl; } ll lst = 0;
recalc(); }; fore(i, 0, n) {
swap(*this, *ret); bk[f(i)] = min(bk[f(i)], v[i]);
return ret; while (lst && v[i-__builtin_ctzll(lst)]>v[i])// < for max
} else if (k == cnt + 1) { // k == val FenwickTree2d.h lst ^= lst & -lst;
Node* ret = r; Description: Computes sums a[i,j] for all i<I, j<J, and increases single ele- mk[i] = ++lst, lst *= 2;
r = 0; ments a[i,j]. Requires that the elements to be updated are known in advance }
recalc(); (call fakeUpd() before init()). ll top = f(n);
UNC MoQueries MoTree Polynomial PolyRoots PolyInterpolate 2025-04-20 7
fore(k, 1, 64 - __builtin_clzll(top + 1)) { }; }
fore(i, 0, top - (1 << k) + 1) Poly mul(const Poly& p, const Poly& q) { // O(n^2)
bk[top*k + i] = if (p.empty() || q.empty()) return {};
min(bk[top*(k-1) + i], bk[top*(k-1) + i + (1<<k-1)]); MoTree.h Poly res(SZ(p) + SZ(q) - 1);
} Description: Answer tree path queries by finding an approximate TSP fore(i,0,SZ(p)) fore(j,0,SZ(q))
} through the queries, and moving from one query to the next by adding/re- res[i+j] += p[i] * q[j];
T get(ll st, ll en) { moving points at the ends. If values are on tree edges, change step to return res;
return v[en-64+__builtin_clzll(mk[en-1]&((1ll<<en-st)-1))]; add/remove the
√ edge
 (a, c) and remove the initial add call (but keep in). }
} Time: O N Q 437687, 31 lines pair<Poly, double> divSmall(const Poly& p, double x0) { // O(n)
T query(ll s, ll e) { // [ s , e) constexpr ll B = 447; // ∼N/sqrt (Q) ll n = SZ(p)-1; // Divide p by (x−x0) , returns {res , rem}
ll b1 = f(s), b2 = f(e - 1); struct MoTree { if (n < 0) return {{}, 0};
if (b1 == b2) return get(s, e); typedef ll T; if (n == 0) return {{}, p[0]};
T ans = min(get(s, (b1 + 1)*32), get(b2*32, e)); void add(ll pos, ll end) {} Poly res(n);
s = (b1 + 1)*32; void del(ll pos, ll end) {} res[n-1] = p[n];
e = b2*32; T calc() { return 0; } for (ll i = n - 1; i--;) res[i] = p[i+1] + x0 * res[i+1];
if (s < e) { vector<T> solve(vector<ii> Q, vector<vi>& g, ll root=0) { return {res, p[0] + x0 * res[0]};
ll k = 63 - __builtin_clzll(f(e - s)); ll N = SZ(g), pos[2] = {}; }
ll top = f(n) * k; vi s(SZ(Q)), I(N), L(N), R(N), in(N), par(N); pair<Poly, Poly> div(Poly p, const Poly& q) { // O(n^2)
ans = min(ans, vector<T> res(SZ(Q)); if (SZ(p) < SZ(q)) return {{}, p}; // returns {res , rem}
min(bk[top + f(s)], bk[top + f(e - 1) - (1<<k) + 1])); add(0, 0), in[0] = 1; ll n = SZ(p) - SZ(q) + 1;
} auto dfs = [&](ll x, ll p, ll dep, auto&& f) -> void { Poly res(n);
return ans; par[x] = p, L[x] = dep ? I[x] = N++ : N; for (ll i = n; i--;) {
} for (ll y : g[x]) if (y != p) f(y, x, !dep, f); res[i] = p.back() / q.back();
}; R[x] = !dep ? I[x] = ++N : N; fore(j, 0, SZ(q)) p[j + i] -= res[i] * q[j];
}; p.pop_back();
dfs(root, -1, 0, dfs); }
MoQueries.h #define K(x) ii(I[x.fst]/B, I[x.snd] ^ -(I[x.fst]/B & 1)) while (!p.empty() && abs(p.back()) < eps) p.pop_back();
Description: Answer range queries offline using Hilbert order or SQRT iota(ALL(s), 0); return {res, p};
decomposition. For Hilbert, change lines with SQ for commented lines. De- sort(ALL(s), [&](ll s, ll t) {return K(Q[s]) < K(Q[t]);}); }
fine add, rem, calc, add necessary fields to MoQueries, instantiate, and call for (ll qi : s) fore(e,0,2) {
solve. Queries are given as pairs [l, r). end is true if the element should be ll &a = pos[e], b = e ? Q[qi].fst : Q[qi].snd, i = 0;
added/removed from the end of the range. qid is the query index. Starts at #define step(c)in[c]?(del(a,e),in[a]=0):(add(c,e),in[c]=1),a=c; PolyRoots.h
[0, 0). Description: Finds the real roots to a polynomial.
√ while (L[a] < L[b] || R[b] < R[a]) b = par[I[i++] = b];
Usage: polyRoots({{2,-3,1}},-1e9,1e9)

Time: Fast O T N Q + CQ where T is the cost of add and rem and C is while (a != b) step(par[a]); // solve xˆ2-3x+2 = 0
Time: O n2 log(1/ϵ)

the cost of calc. dad6b3, 35 lines while (i--) step(I[i]);
"Polynomial.h" c5dc54, 20 lines
constexpr ll B = 447; // ∼N/sqrt (Q) if (e) res[qi] = calc();
} vector<double> polyRoots(Poly& p, double xmin, double xmax) {
struct MoQueries {
return res; if (SZ(p) == 2) return {-p[0]/p[1]};
typedef ll T;
} vector<double> ret;
void add(ll pos, bool end, ll qid) {}
}; Poly der = derivate(p), dr = polyRoots(der, xmin, xmax);
void rem(ll pos, bool end, ll qid) {}
dr.pb(xmin-1), dr.pb(xmax+1);
T calc() { return 0; }
sort(ALL(dr));
ii k(ii &x) { return {x.fst/B, x.snd ^ -(x.fst/B&1)};} // SQ
vector<T> solve(ll n, vector<ii> &qs) { Numerical (4) fore(i,0,SZ(dr)-1) {
double l = dr[i], h = dr[i+1];
ll l = 0, r = 0, q = SZ(qs); // , rx , ry , k , s ;
bool sign = eval(p, l) > 0;
vi p(q); // , o(q) ;
iota(ALL(p), 0); 4.1 Polynomials and recurrences if (sign ^ (eval(p, h) > 0)) {
fore(it, 0, 60) { // while (h − l > 1e−8)
//fore ( i , 0 , q) { Polynomial.h double m = (l + h) / 2, f = eval(p, m);
// auto [ x , y ] = qs [ i ] ; Description: Some operations with polynomials. Everything except div if ((f <= 0) ^ sign) l = m;
// for (k = s = b i t c e i l (( unsigned)n) ; s >>= 1;) { works also with integers. For a faster version of mul, see FFT. 51f958, 48 lines else h = m;
// rx = (x&s )>0, ry = (y&s )>0, o [ i ] += s∗s ∗(( rx∗3)^ry) ;
}
// i f ( ! ry) { const double eps = 1e-9;
ret.pb((l + h) / 2);
// i f ( rx ) x = k − 1 − x , y = k − 1 − y ; typedef vector<double> Poly;
}
// swap(x , y) ;
}
// } double eval(const Poly& p, double x) { // O(n)
return ret;
// } double val = 0;
}
//} for (ll i = SZ(p); i--;) (val *= x) += p[i];
//sort (ALL(p) , [&]( l l i , l l j ) { return o [ i ] < o [ j ] ; }) ; return val;
sort(ALL(p),[&](ll i,ll j){return k(qs[i])<k(qs[j]);});//SQ } PolyInterpolate.h
vector<T> res(q); Poly derivate(const Poly& p) { // O(n) Description: Given n points (x[i], y[i]), computes an n-1-degree polynomial
for (ll i : p) { Poly res(SZ(p)-1); p that passes through them: p(x) = a[0] ∗ x0 + ... + a[n − 1] ∗ xn−1 . For
auto [ql, qr] = qs[i]; fore(i, 1, SZ(p)) res[i-1] = i*p[i]; numerical precision, pick x[k] = c ∗ cos(k/(n − 1) ∗ π), k = 0 . . . n − 1.
while (l > ql) add(--l, 0, i); return res; Time: O n2

while (r < qr) add(r++, 1, i); } d72300, 13 lines
while (l < ql) rem(l++, 0, i); Poly add(const Poly& p, const Poly& q) { // O(n) typedef vector<double> vd;
while (r > qr) rem(--r, 1, i); Poly res(max(SZ(p), SZ(q))); vd interpolate(vd x, vd y, ll n) {
res[i] = calc(); fore(i,0,SZ(p)) res[i] += p[i]; vd res(n), temp(n);
} fore(i,0,SZ(q)) res[i] += q[i]; fore(k,0,n-1) fore(i,k+1,n)
return res; while (!res.empty() && abs(res.back()) < eps) res.pop_back(); y[i] = (y[i] - y[k]) / (x[i] - x[k]);
} return res; double last = 0; temp[0] = 1;
UNC PolyInterpolatePuntual BerlekampMassey LinearRecurrence GoldenSectionSearch HillClimbing Integrate IntegrateAdaptive Simplex 2025-04-20 8
fore(k,0,n) fore(i,0,n) { double quad(double a, double b, auto f, const ll n = 1000) {
res[i] += y[k] * temp[i]; auto combine = [&](Poly a, Poly b) { double h = (b - a) / 2 / n, v = f(a) + f(b);
swap(last, temp[i]); Poly res(n * 2 + 1); fore(i,1,n*2)
temp[i] -= last * x[k]; fore(i,0,n+1) fore(j,0,n+1) v += f(a + i*h) * (i&1 ? 4 : 2);
} res[i + j] = (res[i + j] + a[i] * b[j]) % mod; return v * h / 3;
return res; for (ll i = 2 * n; i > n; --i) fore(j,0,n) }
} res[i - 1 - j] = (res[i - 1 - j] + res[i] * tr[j]) % mod;
res.resize(n + 1);
return res; IntegrateAdaptive.h
PolyInterpolatePuntual.h }; Description: Fast integration using an adaptive Simpson’s rule.
Description: Given for i ∈ {0, 1, ..., n − 1} points (i, y[i]) computes the Usage: double sphereVolume = quad(-1, 1, [](double x) {
value of the n-1-degree polynomial that passes through them at point x. return quad(-1, 1, [&](double y) {
Poly pol(n + 1), e(pol);
Time: O (n log mod) return quad(-1, 1, [&](double z) {
pol[0] = e[1] = 1;
"../number-theory/ModularArithmetic.h" 0bd5d5, 15 lines return x*x + y*y + z*z < 1; });});}); 592cae, 13 lines
Mod interpolate(vector<Mod>& y, Mod x) { for (++k; k; k /= 2) { typedef double d;
ll n = SZ(y); if (k % 2) pol = combine(pol, e); #define S(a,b) (f(a) + 4*f((a+b) / 2) + f(b)) * (b-a) / 6
static vector<Mod> fi {1}; // Inverses of f a c t o r i a l s e = combine(e, e);
while (SZ(fi) < n) fi.pb(fi.back() / SZ(fi)); } d rec(auto& f, d a, d b, d eps, d S) {
if (x.x < n) return y[x.x];
d c = (a + b) / 2;
Mod p = 1; ll res = 0; d S1 = S(a, c), S2 = S(c, b), T = S1 + S2;
fore(i, 0, n) p = p * (x - i); fore(i,0,n) res = (res + pol[i + 1] * S[i]) % mod; if (abs(T - S) <= 15 * eps || b - a < 1e-10)
Mod ans = 0; return res; return T + (T - S) / 15;
fore(i, 0, n) { } return rec(f, a, c, eps / 2, S1) + rec(f, c, b, eps / 2, S2);
Mod t = y[i] * p / (x-i) * fi[i] * fi[n-1-i];
}
if ((n-i) % 2 == 0) t = t * (mod - 1);
ans = ans + t;
4.2 Optimization d quad(d a, d b, auto f, d eps = 1e-8) {
return rec(f, a, b, eps, S(a, b));
} GoldenSectionSearch.h }
return ans; Description: Finds the argument minimizing the function f in the interval
} [a, b] assuming f is unimodal on the interval, i.e. has only one local mini-
mum and no local maximum. The maximum error in the result is eps. Works Simplex.h
BerlekampMassey.h equally well for maximization with a small change in the code. See Ternary- Description: Solves a general linear maximization problem: maximize cT x
Description: Recovers any n-order linear recurrence relation from the first Search.h in the Various chapter for a discrete version. subject to Ax ≤ b, x ≥ 0. Returns -inf if there is no solution, inf if there
2n terms of the recurrence. Useful for guessing linear recurrences after brute- Usage: double func(double x) { return 4+x+.3*x*x; } are arbitrarily good solutions, or the maximum value of cT x otherwise. The
forcing the first terms. Should work on any field, but numerical stability for double xmin = gss(-1000,1000,func); input vector is set to an optimal x (or in the unbounded case, an arbitrary
floats is not guaranteed. Output will have size ≤ n. Time: O (log((b − a)/ϵ)) badd5e, 10 lines solution fulfilling the constraints). Numerical stability is not guaranteed. For
Usage: berlekampMassey({0, 1, 1, 3, 5, 11}) // {1, 2} better performance, define variables such that x = 0 is viable.
double gss(double a, double b, auto f) {
Time: O N 2 Usage: vvd A = {{1,-1}, {-1,1}, {-1,-2}};

double r = (sqrt(5)-1)/2, x1 = b - r*(b-a), x2 = a + r*(b-a);
"../number-theory/ModPow.h" 6620a1, 20 lines vd b = {1,1,-4}, c = {-1,-1}, x;
double f1 = f(x1), f2 = f(x2), eps = 1e-7;
vi berlekampMassey(vi s) { T val = LPSolver(A, b, c).solve(x);
while (b-a > eps)
Time: O (N M ∗ #pivots), where a pivot may be e.g. an edge relaxation.
ll n = SZ(s), L = 0, m = 0; if (f1 < f2) // change to > to find maximum
vi C(n), B(n), T; O (2n ) in the general case.
b = x2, x2 = x1, f2 = f1, f1 = f(x1 = b - r*(b-a)); 76f7d9, 68 lines
C[0] = B[0] = 1; else typedef double T; // long double , Rational , double + mod<P>...
a = x1, x1 = x2, f1 = f2, f2 = f(x2 = a + r*(b-a)); typedef vector<T> vd;
ll b = 1; return a; typedef vector<vd> vvd;
fore(i,0,n) { ++m; }
ll d = s[i] % mod; const T eps = 1e-8, inf = 1/.0;
fore(j,1,L+1) d = (d + C[j] * s[i - j]) % mod; HillClimbing.h #define MP make_pair
if (!d) continue; Description: Poor man’s optimization for unimodal functions. #define ltj(X) if(s == -1 || MP(X[j],N[j]) < MP(X[s],N[s])) s=j
T = C; ll coef = d * modpow(b, mod-2) % mod; e848c6, 13 lines

fore(j,m,n) C[j] = (C[j] - coef * B[j - m]) % mod; typedef array<double, 2> P; struct LPSolver {
if (2 * L > i) continue; ll m, n;
L = i + 1 - L, B = T, b = d, m = 0; pair<double, P> hillClimb(P start, auto&& f) { vi N, B;
} pair<double, P> cur(f(start), start); vvd D;
for (double jmp = 1e9; jmp > 1e-20; jmp /= 2) {
C.resize(L + 1); C.erase(C.begin()); fore(j,0,100) fore(dx,-1,2) fore(dy,-1,2) { LPSolver(const vvd& A, const vd& b, const vd& c) :
for (ll& x : C) x = (mod - x) % mod; P p = cur.snd; m(SZ(b)), n(SZ(c)), N(n+1), B(m), D(m+2, vd(n+2)) {
return C; p[0] += dx*jmp, p[1] += dy*jmp; fore(i,0,m) fore(j,0,n) D[i][j] = A[i][j];
} cur = min(cur, make_pair(f(p), p)); fore(i,0,m) {B[i]=n+i; D[i][n]=-1; D[i][n+1]=b[i];}
} fore(j,0,n) { N[j] = j; D[m][j] = -c[j]; }
}
LinearRecurrence.h return cur;
N[n] = -1, D[m+1][n] = 1;
Description: Generates the k’th term of an n-order linear recurrence }
P }
S[i] = j S[i − j − 1]tr[j], given S[0 . . . ≥ n − 1] and tr[0 . . . n − 1]. Faster
than matrix multiplication. Useful together with Berlekamp–Massey. void pivot(ll r, ll s) {
Usage: linearRec({0, 1}, {1, 1}, k) // k’th Fibonacci number Integrate.h T *a = D[r].data(), inv = 1 / a[s];
Time: O n2 log k
 Description: Simple integration of a function over an interval using Simp- fore(i,0,m+2) if (i != r && abs(D[i][s]) > eps) {
a61838, 26 lines
son’s rule. The error should be proportional to h4 , although in practice you T *b = D[i].data(), inv2 = b[s] * inv;
typedef vi Poly; will want to verify that the result is stable to desired precision when epsilon fore(j,0,n+2) b[j] -= a[j] * inv2;
ll linearRec(Poly S, Poly tr, ll k) { changes. b[s] = a[s] * inv2;
1c4ce6, 6 lines
ll n = SZ(tr); }
UNC IntegerLinearProgramming Determinant IntDeterminant SolveLinear SolveLinear2 SolveLinearBinary MatrixInverse 2025-04-20 9
fore(j,0,n+2) if (j != s) D[r][j] *= inv; IntDeterminant.h SolveLinear2.h
fore(i,0,m+2) if (i != r) D[i][s] *= -inv; Description: Calculates determinant using modular arithmetics. Modulos Description: To get all uniquely determined values of x back from Solve-
D[r][s] = inv; can also be removed to get a pure-integer version. Linear, make the following changes:
Time: O N 3

swap(B[r], N[s]); d39cf6, 18 lines
"SolveLinear.h" 11ffdd, 7 lines
} fore(j,0,n) if (j != i) // instead of fore ( j , i +1,n)
const ll mod = 12345;
ll det(vector<vi>& a) { // . . . then at the end :
bool simplex(ll phase) { x.assign(m, undefined);
ll x = m + phase - 1; ll n = SZ(a); ll ans = 1;
fore(i,0,n) { fore(i,0,rank) {
for (;;) { fore(j,rank,m) if (fabs(A[i][j]) > eps) goto fail;
ll s = -1; fore(j,i+1,n) {
while (a[j][i] != 0) { // gcd step x[col[i]] = b[i] / A[i][i];
fore(j,0,n+1) if (N[j] != -phase) ltj(D[x]); fail:; }
if (D[x][s] >= -eps) return true; ll t = a[i][i] / a[j][i];
ll r = -1; if (t) fore(k,i,n)
fore(i,0,m) { a[i][k] = (a[i][k] - a[j][k] * t) % mod; SolveLinearBinary.h
if (D[i][s] <= eps) continue; swap(a[i], a[j]); Description: Solves Ax = b over F2 . If there are multiple solutions, one is
if (r == -1 || MP(D[i][n+1] / D[i][s], B[i]) ans *= -1; returned arbitrarily. Returns rank, or -1 if no solutions. Destroys A and b.
Time: O n2 m

< MP(D[r][n+1] / D[r][s], B[r])) r = i; }
54a024, 34 lines
} }
ans = ans * a[i][i] % mod; typedef bitset<1000> bs;
if (r == -1) return false;
pivot(r, s); if (!ans) return 0;
} ll solveLinear(vector<bs>& A, vi& b, bs& x, ll m) {
} ll n = SZ(A), rank = 0, br;
} return (ans + mod) % mod;
} assert(m <= SZ(x));
vi col(m); iota(ALL(col), 0);
T solve(vd &x) { fore(i,0,n) {
ll r = 0; for (br = i; br < n; ++br) if (A[br].any()) break;
fore(i,1,m) if (D[i][n+1] < D[r][n+1]) r = i; if (br == n) {
if (D[r][n+1] < -eps) { SolveLinear.h fore(j,i,n) if (b[j]) return -1;
pivot(r, n); Description: Solves A ∗ x = b. If there are multiple solutions, an arbitrary break;
if (!simplex(2) || D[m+1][n+1] < -eps) return -inf; one is returned. Returns rank, or -1 if no solutions. Data in A and b is lost. }
fore(i,0,m) if (B[i] == -1) { Time: O n2 m ll bc = (ll)A[br]._Find_next(i-1);
ll s = 0; 9863aa, 38 lines
swap(A[i], A[br]);
fore(j,1,n+1) ltj(D[i]); typedef vector<double> vd; swap(b[i], b[br]);
pivot(i, s); const double eps = 1e-12; swap(col[i], col[bc]);
} fore(j,0,n) if (A[j][i] != A[j][bc]) {
} ll solveLinear(vector<vd>& A, vd& b, vd& x) { A[j].flip(i); A[j].flip(bc);
bool ok = simplex(1); x = vd(n); ll n = SZ(A), m = SZ(x), rank = 0, br, bc; }
fore(i,0,m) if (B[i] < n) x[B[i]] = D[i][n+1]; if (n) assert(SZ(A[0]) == m); fore(j,i+1,n) if (A[j][i]) {
return ok ? D[m][n+1] : inf; vi col(m); iota(ALL(col), 0); b[j] ^= b[i];
} A[j] ^= A[i];
}; fore(i,0,n) { }
double v, bv = 0; rank++;
IntegerLinearProgramming.h fore(r,i,n) fore(c,i,m) }
Description: When A and b have all integer entries and A is totally unimod- if ((v = fabs(A[r][c])) > bv)
ular then every basic feasible solution is integral so the simplex algorithm br = r, bc = c, bv = v; x = bs();
can be used to solve ILP. A matrix A is totally unimodular if every square if (bv <= eps) { for (ll i = rank; i--;) {
submatrix of A has determinant 0, 1 or −1. fore(j,i,n) if (fabs(b[j]) > eps) return -1; if (!b[i]) continue;
break; x[col[i]] = 1;
} fore(j,0,i) b[j] ^= A[j][i];
swap(A[i], A[br]); }
4.3 Matrices swap(b[i], b[br]); return rank; // ( multiple solutions i f rank < m)
Determinant.h swap(col[i], col[bc]); }
Description: Calculates determinant of a matrix. Destroys the matrix. fore(j,0,n) swap(A[j][i], A[j][bc]);
Time: O N 3 bv = 1/A[i][i];
144e26, 15 lines fore(j,i+1,n) { MatrixInverse.h
double det(vector<vector<double>>& a) { double fac = A[j][i] * bv; Description: Invert matrix A. Returns rank; result is stored in A unless
ll n = SZ(a); double res = 1; b[j] -= fac * b[i]; singular (rank < n). Can easily be extended to prime moduli; for prime
fore(i,0,n) { fore(k,i+1,m) A[j][k] -= fac*A[i][k]; powers, repeatedly set A−1 = A−1 (2I − AA−1 ) (mod pk ) where A−1 starts
ll b = i; } as the inverseof A mod p, and k is doubled in each step.
fore(j,i+1,n) if (fabs(a[j][i]) > fabs(a[b][i])) b = j; rank++; Time: O n3 8a7b27, 35 lines
if (i != b) swap(a[i], a[b]), res *= -1; }
ll matInv(vector<vector<double>>& A) {
res *= a[i][i];
ll n = SZ(A); vi col(n);
if (res == 0) return 0; x.assign(m, 0);
vector<vector<double>> tmp(n, vector<double>(n));
fore(j,i+1,n) { for (ll i = rank; i--;) {
fore(i,0,n) tmp[i][i] = 1, col[i] = i;
double v = a[j][i] / a[i][i]; b[i] /= A[i][i];
if (v != 0) fore(k,i+1,n) a[j][k] -= v * a[i][k]; x[col[i]] = b[i];
fore(i,0,n) {
} fore(j,0,i) b[j] -= A[j][i] * b[i];
ll r = i, c = i;
} }
fore(j,i,n) fore(k,i,n)
return res; return rank; // ( multiple solutions i f rank < m)
if (fabs(A[j][k]) > fabs(A[r][c]))
} }
r = j, c = k;
UNC MatrixInverse-mod Tridiagonal FastFourierTransform FastFourierTransformMod NumberTheoreticTransform 2025-04-20 10
if (fabs(A[r][c]) < 1e-12) return i; return n; for (static ll k = 2; k < n; k *= 2) {
A[i].swap(A[r]); tmp[i].swap(tmp[r]); } R.resize(n); rt.resize(n);
fore(j,0,n) auto x = polar(1.0L, acos(-1.0L) / k);
swap(A[j][i], A[j][c]), swap(tmp[j][i], tmp[j][c]); Tridiagonal.h fore(i,k,2*k) rt[i] = R[i] = i&1 ? R[i/2] * x : R[i/2];
swap(col[i], col[c]); Description: x = tridiagonal(d, p, q, b) solves the equation system }
double v = A[i][i]; vi rev(n);
b0 d0 p0 0 0 ··· 0 x0
    
fore(j,i+1,n) { fore(i,0,n) rev[i] = (rev[i / 2] | (i & 1) << L) / 2;
double f = A[j][i] / v;  b1   q0 d1 p1 0 ··· 0   x1  fore(i,0,n) if (i < rev[i]) swap(a[i], a[rev[i]]);
A[j][i] = 0;
 b
 2


 0
 q1 d2 p2 ··· 0   x2
  
 for (ll k = 1; k < n; k *= 2)
 b  x
= . . . .
  
fore(k,i+1,n) A[j][k] -= f*A[i][k]; 3 .. .. .. 3 for (ll i = 0; i < n; i += 2 * k) fore(j,0,k) {
 . . .
 
fore(k,0,n) tmp[j][k] -= f*tmp[i][k];

.

 . . . . . .

.

C z = rt[j+k] * a[i+j+k]; // (25% faster i f hand−r o l l e d )
. .
   
}
 .   0 0 ··· qn−3 dn−2 pn−2   . 
a[i + j + k] = a[i + j] - z;
fore(j,i+1,n) A[i][j] /= v; bn−1 0 0 ··· 0 qn−2 dn−1 xn−1 a[i + j] += z;
fore(j,0,n) tmp[i][j] /= v; This is useful for solving problems on the type }
A[i][i] = 1; }
} ai = bi ai−1 + ci ai+1 + di , 1 ≤ i ≤ n, vd conv(const vd& a, const vd& b) {
where a0 , an+1 , bi , ci and di are known. a can then be obtained from if (a.empty() || b.empty()) return {};
for (ll i = n-1; i > 0; --i) fore(j,0,i) { vd res(SZ(a) + SZ(b) - 1);
double v = A[j][i]; {ai } = tridiagonal({1, −1, −1, ..., −1, 1}, {0, c1 , c2 , . . . , cn }, ll L = 64 - __builtin_clzll(SZ(res)), n = 1 << L;
fore(k,0,n) tmp[j][k] -= v*tmp[i][k]; {b1 , b2 , . . . , bn , 0}, {a0 , d1 , d2 , . . . , dn , an+1 }). vector<C> in(n), out(n);
} copy(ALL(a), begin(in));
Fails if the solution is not unique.
fore(i,0,SZ(b)) in[i].imag(b[i]);
If |di | > |pi | + |qi−1 | for all i, or |di | > |pi−1 | + |qi |, or the matrix is positive
fore(i,0,n) fore(j,0,n) A[col[i]][col[j]] = tmp[i][j]; fft(in);
definite, the algorithm is numerically stable and neither tr nor the check for
return n; for (C& x : in) x *= x;
diag[i] == 0 is needed.
} fore(i,0,n) out[i] = in[-i & (n - 1)] - conj(in[i]);
Time: O (N ) 3c76ca, 26 lines fft(out);
typedef double T; fore(i,0,SZ(res)) res[i] = imag(out[i]) / (4 * n);
MatrixInverse-mod.h vector<T> tridiagonal(vector<T> diag, const vector<T>& super, return res;
Description: Invert matrix A modulo a prime. Returns rank; result is const vector<T>& sub, vector<T> b) { }
stored in A unless singular (rank < n). For prime powers, repeatedly set ll n = SZ(b); vi tr(n);
A−1 = A−1 (2I − AA−1 ) (mod pk ) where A−1 starts as the inverse of A mod fore(i,0,n-1) { FastFourierTransformMod.h
p, and k is doubled in each step. if (abs(diag[i]) < 1e-9 * abs(super[i])) { // diag [ i ] == 0 Description: Higher precision FFT, can be used for convolutions modulo
Time: O n3

b[i+1] -= b[i] * diag[i+1] / super[i]; arbitrary integers as long as N log2 N · mod < 8.6 · 1014 (in practice 1016 or
"../number-theory/ModPow.h" a019e9, 37 lines if (i+2 < n) b[i+2] -= b[i] * sub[i+1] / super[i]; higher). Inputs must be in [0, mod).
ll matInv(vector<vi>& A) { diag[i+1] = sub[i]; tr[++i] = 1; Time: O (N log N ), where N = |A| + |B| (twice as slow as NTT or FFT)
ll n = SZ(A); vi col(n); } else { "FastFourierTransform.h" 8121b2, 21 lines
vector<vi> tmp(n, vi(n)); diag[i+1] -= super[i]*sub[i]/diag[i];
b[i+1] -= b[i]*sub[i]/diag[i]; template<ll M> vi convMod(const vi &a, const vi &b) {
fore(i,0,n) tmp[i][i] = 1, col[i] = i; if (a.empty() || b.empty()) return {};
}
} vi res(SZ(a) + SZ(b) - 1);
fore(i,0,n) { ll B=64-__builtin_clzll(SZ(res)), n=1<<B, cut=ll(sqrt(M));
ll r = i, c = i; for (ll i = n; i--;) {
if (tr[i]) { vector<C> L(n), R(n), outs(n), outl(n);
fore(j,i,n) fore(k,i,n) if (A[j][k]) { fore(i,0,SZ(a)) L[i] = C((ll)a[i] / cut, (ll)a[i] % cut);
r = j; c = k; goto found; swap(b[i], b[i-1]);
diag[i-1] = diag[i]; fore(i,0,SZ(b)) R[i] = C((ll)b[i] / cut, (ll)b[i] % cut);
} fft(L), fft(R);
return i; b[i] /= super[i-1];
} else { fore(i,0,n) {
found: ll j = -i & (n - 1);
A[i].swap(A[r]); tmp[i].swap(tmp[r]); b[i] /= diag[i];
if (i) b[i-1] -= b[i]*super[i-1]; outl[j] = (L[i] + conj(L[j])) * R[i] / (2.0 * n);
fore(j,0,n) outs[j] = (L[i] - conj(L[j])) * R[i] / (2.0 * n) / 1i;
swap(A[j][i], A[j][c]), swap(tmp[j][i], tmp[j][c]); }
} }
swap(col[i], col[c]); fft(outl), fft(outs);
ll v = modpow(A[i][i], mod - 2); return b;
} fore(i,0,SZ(res)) {
fore(j,i+1,n) { ll av = ll(real(outl[i])+.5), cv = ll(imag(outs[i])+.5);
ll f = A[j][i] * v % mod; ll bv = ll(imag(outl[i])+.5) + ll(real(outs[i])+.5);
A[j][i] = 0; 4.4 Fourier transforms res[i] = ((av % M * cut + bv) % M * cut + cv) % M;
fore(k,i+1,n) A[j][k] = (A[j][k] - f*A[i][k]) % mod; FastFourierTransform.h }
fore(k,0,n) tmp[j][k] = (tmp[j][k] - f*tmp[i][k]) % mod; Description: fft(a) computes fˆ(k) =
P
return res;
x a[x] exp(2πi · kx/N ) for all k.
} N mustPbe a power of 2. Useful for convolution: conv(a, b) = c, where }
fore(j,i+1,n) A[i][j] = A[i][j] * v % mod; c[x] = a[i]b[x − i]. For convolution of complex numbers or more than two
fore(j,0,n) tmp[i][j] = tmp[i][j] * v % mod; vectors: FFT, multiply pointwise, divide by n, reverse(start+1, end), FFT
A[i][i] = 1; NumberTheoreticTransform.h
back. Rounding is safe if ( a2i + b2i ) log2 N < 9 · 1014 (in practice 1016 ;
P P
Description: ntt(a) computes fˆ(k) = xk
P
} x a[x]g for all k, where g =
higher for random inputs). Otherwise, use NTT/FFTMod. (mod−1)/N
Time: O (N log N ) with N = |A| + |B| (∼1s for N = 222 ) root . N must be a power of 2. Useful for convolution modulo spe-
for (ll i = n-1; i > 0; --i) fore(j,0,i) { 71e979, 35 lines cific nice primes of the form 2a b + 1, where the convolution result has size
ll v = A[j][i]; typedef complex<double> C; at mostP 2a . For arbitrary modulo, see FFTMod. conv(a, b) = c, where
fore(k,0,n) tmp[j][k] = (tmp[j][k] - v*tmp[i][k]) % mod; typedef vector<double> vd; c[x] = a[i]b[x − i]. For manual convolution: NTT the inputs, multiply
} void fft(vector<C>& a) { pointwise, divide by n, reverse(start+1, end), NTT back. Inputs must be in
ll n = SZ(a), L = 63 - __builtin_clzll(n); [0, mod).
fore(i,0,n) fore(j,0,n) static vector<complex<long double>> R(2, 1); Time: O (N log N )
A[col[i]][col[j]] = tmp[i][j] % mod + (tmp[i][j] < 0)*mod; static vector<C> rt(2, 1); // (^ 10% f a s t e r i f double ) "../number-theory/ModPow.h" a249ae, 34 lines
UNC FastSubsetTransform NTT-operations ModularArithmetic PrecomputeInverses 2025-04-20 11
Poly res(max(SZ(p), SZ(q))); }
const ll mod = (119 << 23) + 1, root = 62; // = 998244353 fore(i, 0, SZ(p)) res[i] += p[i];
// For p < 2^30 there i s also e . g . 5 << 25, 7 << 26, 479 << 21 fore(i, 0, SZ(q)) res[i] += q[i]; vector<Poly> filltree(vi& x) {
// and 483 << 21 (same root ) . The l a s t two are > 10^9. for (ll& x : res) x %= mod; ll k = SZ(x);
void ntt(vi &a) { while (!res.empty() && !res.back()) res.pop_back(); vector<Poly> tr(2*k);
ll n = SZ(a), L = 63 - __builtin_clzll(n); return res; fore(i, k, 2*k) tr[i] = {(mod - x[i - k]) % mod, 1};
static vi rt(2, 1); } for (ll i = k; --i;) tr[i] = conv(tr[2*i], tr[2*i+1]);
for (static ll k = 2, s = 2; k < n; k *= 2, s++) { Poly derivate(const Poly& p) { // O(n) return tr;
rt.resize(n); Poly res(max(0ll, SZ(p)-1)); }
ll z[] = {1, modpow(root, mod >> s)}; fore(i, 1, SZ(p)) res[i-1] = (i * p[i]) % mod; vi evaluate(Poly& a, vi& x) { // O(n log (n)^2)
fore(i,k,2*k) rt[i] = rt[i / 2] * z[i & 1] % mod; return res; ll k = SZ(x); // Evaluate a in a l l points of x
} } if (!SZ(a)) return vi(k);
vi rev(n); Poly integrate(const Poly& p) { // O(n) vector<Poly> tr = filltree(x), ans(2*k);
fore(i,0,n) rev[i] = (rev[i / 2] | (i & 1) << L) / 2; Poly ans(SZ(p) + 1); ans[1] = div(a, tr[1]).snd;
fore(i,0,n) if (i < rev[i]) swap(a[i], a[rev[i]]); fore(i, 0, SZ(p)) ans[i+1] = (p[i] * inv(i+1)) % mod; fore(i, 2, 2*k) ans[i] = div(ans[i/2], tr[i]).snd;
for (ll k = 1; k < n; k *= 2) return ans; vi r(k);
for (ll i = 0; i < n; i += 2 * k) fore(j,0,k) { } fore(i, 0, k) if (SZ(ans[i+k])) r[i] = ans[i+k][0];
ll z = rt[j + k] * a[i + j + k] % mod, &ai = a[i + j]; return r;
a[i + j + k] = ai - z + (z > ai ? mod : 0); Poly takeMod(Poly p, ll n) { // O(n) }
ai += (ai + z >= mod ? z - mod : z); p.resize(min(SZ(p), n)); // p % (x^n) Poly interpolate(vi& x, vi& y) { // O(n log (n)^2)
} while (!p.empty() && !p.back()) p.pop_back(); vector<Poly> tr = filltree(x);
} return p; Poly p = derivate(tr[1]);
vi conv(const vi &a, const vi &b) { } ll k = SZ(y);
if (a.empty() || b.empty()) return {}; vi d = evaluate(p, x); // pass tr here for a speed up
ll s = SZ(a) + SZ(b) - 1, B = 64 - __builtin_clzll(s), Poly inv(const Poly& p, ll d) { // O(n log (n) ) vector<Poly> intr(2*k);
n = 1 << B; Poly res = {inv(p[0])}; // f i r s t d terms of 1/p fore(i, k, 2*k) intr[i] = {(y[i-k] * inv(d[i-k])) % mod};
ll inv = modpow(n, mod - 2); ll sz = 1; for (ll i = k; --i;) intr[i] = add(
vi L(a), R(b), out(n); while (sz < d) { conv(tr[2*i], intr[2*i+1]), conv(tr[2*i+1], intr[2*i]));
L.resize(n), R.resize(n); sz *= 2; return intr[1];
ntt(L), ntt(R); Poly pre(p.begin(), p.begin() + min(SZ(p), sz)); }
fore(i,0,n) Poly cur = conv(res, pre);
out[-i & (n - 1)] = (ll)L[i] * R[i] % mod * inv % mod; fore(i, 0, SZ(cur)) if (cur[i]) cur[i] = mod - cur[i];
ntt(out);
return {out.begin(), out.begin() + s};
cur[0] = cur[0] + 2;
res = takeMod(conv(res, cur), sz);
Number theory (5)
} }
res.resize(d); 5.1 Modular arithmetic
FastSubsetTransform.h return res; ModularArithmetic.h
Description: Transform to a basis with fast convolutions of the form } Description: Operators for modular arithmetic. Update mod. Use com-
X Poly log(const Poly& p, ll d) { // O(n log (n) ) mented code in invert if mod is not prime.
c[z] = a[x] · b[y], where ⊕ is one of AND, OR, XOR. The size Poly cur = takeMod(p, d); // f i r s t d terms of log (p)
z=x⊕y "euclid.h" 433a25, 20 lines
of a must be a power of two. Poly res = integrate(
Time: O (N log N ) takeMod(conv(inv(cur, d), derivate(cur)), d - 1)); const ll mod = 17; // change to something e l s e
265ad3, 16 lines struct Mod {
res.resize(d);
void FST(vi& a, bool inv) { return res; ll x;
for (ll n = SZ(a), step = 1; step < n; step *= 2) { } Mod(ll xx) : x(xx) {}
for (ll i = 0; i < n; i += 2 * step) fore(j,i,i+step) { Poly exp(const Poly& p, ll d) { // O(n log (n)^2) Mod operator+(Mod b) { return Mod((x + b.x) % mod); }
ll &u = a[j], &v = a[j + step]; tie(u, v) = Poly res = {1}; // f i r s t d terms of exp(p) Mod operator-(Mod b) { return Mod((x - b.x + mod) % mod); }
inv ? ii(v - u, u) : ii(v, u + v); // AND for (ll sz = 1; sz < d; ) { Mod operator*(Mod b) { return Mod((x * b.x) % mod); }
inv ? ii(v, u - v) : ii(u + v, u); // OR sz *= 2; Mod operator/(Mod b) { return *this * invert(b); }
ii(u + v, u - v); // XOR Poly lg = log(res, sz), cur(sz); Mod invert(Mod a) {
} fore(i, 0, sz) cur[i] = (mod + (i<SZ(p) ? p[i] : 0) return a ^ (mod - 2);
} - (i<SZ(lg) ? lg[i] : 0)) % mod; // l l x , y , g = euclid (a . x , mod, x , y) ;
if (inv) for (ll& x : a) x /= SZ(a); // XOR only cur[0] = (cur[0] + 1) % mod; // assert (g == 1) ; return Mod(( x + mod) % mod) ;
} res = takeMod(conv(res, cur), sz); }
vi conv(vi a, vi b) { } Mod operator^(ll e) {
FST(a, 0); FST(b, 0); res.resize(d); Mod ans(1);
fore(i,0,SZ(a)) a[i] *= b[i]; return res; for (Mod b = *this; e; b = b * b, e >>= 1)
FST(a, 1); return a; } if (e & 1) ans = ans * b;
} return ans;
pair<Poly,Poly> div(const Poly& a, const Poly& b) { }
ll m = SZ(a), n = SZ(b); // O(n log (n) ) , returns {res , rem} };
NTT-operations.h
Description: Some operations on polynomials made fast with NTT. The if (m < n) return {{}, a}; // i f min(m−n,n) < 750 i t may be
may also work with doubles and FFT, but it’s numerically unstable. inv, Poly ap = a, bp = b; // f a s t e r to use cuadratic version PrecomputeInverses.h
log ans exp return truncated infinite series. Poly elements should not have reverse(ALL(ap)), reverse(ALL(bp)); Description: Pre-computation of modular inverses. Assumes LIM ≤ mod
trailing zeros. The zero polynomial is {}. Poly q = conv(ap, inv(bp, m - n + 1)); and that mod is a prime. 7f666d, 6 lines
"NumberTheoreticTransform.h", "../number-theory/FastInverse.h" b315c7, 102 lines
q.resize(SZ(q) + m - n - SZ(q) + 1, 0), reverse(ALL(q));
Poly bq = conv(b, q); constexpr ll mod = 1e9+7, LIM = 2e5;
typedef vi Poly; fore(i, 0, SZ(bq)) if (bq[i]) bq[i] = mod - bq[i]; array<ll, LIM> inv;
return {q, add(a, bq)}; void initInv() {
Poly add(const Poly& p, const Poly& q) { // O(n) inv[1] = 1;
UNC FastInverse ModPow ModLog ModSum ModMulLL ModSqrt Eratosthenes FastEratosthenes MillerRabin Factor 2025-04-20 12
fore(i,2,LIM) inv[i] = mod - mod / i * inv[mod % i] % mod; ModMulLL.h }
} Description: Calculate a·b mod c (or ab mod c) for 0 ≤ a, b ≤ c ≤ 7.2·1018 .
Time: O (1) for modmul, O (log b) for modpow bbbd8f, 11 lines FastEratosthenes.h
FastInverse.h typedef unsigned long long ull; Description: Prime sieve for generating all primes smaller than LIM.
Description: Fast modular inverse for a constant modulus. ull modmul(ull a, ull b, ull M) { Time: O (n log log n); LIM=1e9 ≈ 1.5s 9d96d8, 20 lines
Time: O (logn), ≈ 2.7x faster than euclid in CF. 4fccf0, 11 lines ll ret = a * b - M * ull(1.L / M * a * b); const ll LIM = 1e6;
constexpr ll mod = 1e9 + 7; return ret + M * (ret < 0) - M * (ret >= (ll)M); bitset<LIM> isPrime;
constexpr ll k = bit_width((unsigned long long)(mod - 2)); } vi eratosthenes() {
ll inv(ll a) { ull modpow(ull b, ull e, ull mod) { const ll S = (ll)round(sqrt(LIM)), R = LIM / 2;
ll r = 1; ull ans = 1; vi pr = {2}, sieve(S+1); pr.reserve(ll(LIM/log(LIM)*1.1));
#pragma GCC unroll(k) for (; e; b = modmul(b, b, mod), e /= 2) vector<ii> cp;
fore(l, 0, k) { if (e & 1) ans = modmul(ans, b, mod); for (ll i = 3; i <= S; i += 2) if (!sieve[i]) {
if ((mod - 2) >> l & 1) r = r * a % mod; return ans; cp.pb({i, i * i / 2});
a = a * a % mod; } for (ll j = i * i; j <= S; j += 2 * i) sieve[j] = 1;
} }
return r; ModSqrt.h for (ll L = 1; L <= R; L += S) {
} Description: Tonelli-Shanks algorithm for modular square roots. Finds x array<bool, S> block{};
s.t. x2 = a (mod p) (−x gives the other solution). for (auto &[p, idx] : cp)
Time: O log2 p worst case, O (log p) for most p for (ll i=idx; i < S+L; idx = (i+=p)) block[i-L] = 1;
ModPow.h c6ee78, 8 lines "ModPow.h" b167b9, 24 lines fore(i,0,min(S, R - L))
const ll mod = 1000000007; // f a s t e r i f const ll sqrt(ll a, ll p) { if (!block[i]) pr.pb((L + i) * 2 + 1);
a %= p; if (a < 0) a += p; }
ll modpow(ll b, ll e) { if (a == 0) return 0; for (ll i : pr) isPrime[i] = 1;
ll ans = 1; assert(modpow(a, (p-1)/2, p) == 1); // e l s e no solution return pr;
for (; e; b = b * b % mod, e >>= 1) if (p % 4 == 3) return modpow(a, (p+1)/4, p); }
if (e & 1) ans = ans * b % mod; // a^(n+3)/8 or 2^(n+3)/8 ∗ 2^(n−1)/4 works i f p % 8 == 5
return ans; ll s = p - 1, n = 2; MillerRabin.h
} ll r = 0, m; Description: Deterministic Miller-Rabin primality test. Guaranteed to
while (s % 2 == 0) work for numbers up to 7 · 1018 ; for larger numbers, use Python and ex-
ModLog.h ++r, s /= 2; tend A randomly.
Description: Returns the smallest x > 0 s.t. ax = b (mod m), or −1 if no while (modpow(n, (p - 1) / 2, p) != p - 1) ++n; Time: 7 times the complexity of ab mod c.
such x exists. ll x = modpow(a, (s + 1) / 2, p);
√ modLog(a,1,m) can be used to calculate the order of a. "ModMulLL.h" 1d5cc3, 11 lines
ll b = modpow(a, s, p), g = modpow(n, s, p);

Time: O m 0e2062, 11 lines bool isPrime(ull n) {
for (;; r = m) { if (n < 2 || n % 6 % 4 != 1) return (n | 1) == 3;
ll modLog(ll a, ll b, ll m) { ll t = b; ll s = __builtin_ctzll(n-1), d = n >> s;
ll n = (ll) sqrt(m) + 1, e = 1, f = 1, j = 1; for (m = 0; m < r && t != 1; ++m) for (ull a : {2,325,9375,28178,450775,9780504,1795265022}) {
unordered_map<ll, ll> A; t = t * t % p; ull p = modpow(a%n, d, n), i = s;
while (j <= n && (e = f = e * a % m) != b % m) if (m == 0) return x; while (p != 1 && p != n - 1 && a % n && i--)
A[e * b % m] = j++; ll gs = modpow(g, 1LL << (r - m - 1), p); p = modmul(p, p, n);
if (e == b % m) return j; g = gs * gs % p; if (p != n-1 && i != s) return 0;
if (gcd(m, e) == gcd(m, b)) x = x * gs % p; }
fore(i,2,n+2) if (A.count(e = e * f % m)) b = b * g % p; return 1;
return n * i - A[e]; } }
return -1; }
}
5.2 Primality Factor.h
Description: Pollard-rho randomized factorization algorithm. Returns
ModSum.h Eratosthenes.h
Description: Sums of mod’ed arithmetic progressions.  ofa number, in arbitrary order (e.g. 2299 -> {11, 19, 11}).
prime factors
Pto−1 Description: s[i] = smallest prime factor of i (except for i = 0, 1). sieve Time: O n1/4 , less for numbers with small factors.
modsum(to, c, k, m) = i=0 (ki + c)%m. divsum is similar but for
returns sorted primes less than L. fact returns sorted prime, exponent pairs
floored division. "ModMulLL.h", "MillerRabin.h" fd4221, 18 lines
of the factorization of n.
Time: log(m), with a large constant. 5c5bc5, 16 lines
55dd05, 18 lines ull pollard(ull n) {
const ll L = 1e6; ull x = 0, y = 0, t = 30, prd = 2, i = 1, q;
typedef unsigned long long ull;
array<ll, L> s; auto f = [&](ull x) { return modmul(x, x, n) + i; };
ull sumsq(ull to) { return to / 2 * ((to-1) | 1); }
vi sieve() { while (t++ % 40 || gcd(prd, n) == 1) {
vi p; if (x == y) x = ++i, y = f(x);
ull divsum(ull to, ull c, ull k, ull m) {
for (ll i = 4; i < L; i += 2) s[i] = 2; if ((q = modmul(prd, max(x,y) - min(x,y), n))) prd = q;
ull res = k / m * sumsq(to) + c / m * to;
for (ll i = 3; i * i < L; i += 2) if (!s[i]) x = f(x), y = f(f(y));
k %= m; c %= m;
for (ll j=i*i; j < L; j += 2*i) if (!s[j]) s[j] = i; }
if (!k) return res;
fore(i,2,L) if (!s[i]) p.pb(i), s[i] = i; return gcd(prd, n);
ull to2 = (to * k + c) / m;
return p; }
return res + (to - 1) * to2 - divsum(to2, m-1 - c, m, k);
} vector<ull> factor(ull n) {
}
vector<ii> fact(ll n) { if (n == 1) return {};
vector<ii> res; if (isPrime(n)) return {n};
ll modsum(ull to, ll c, ll k, ll m) {
for (; n > 1; n /= s[n]) { ull x = pollard(n);
c = ((c % m) + m) % m;
if (!SZ(res) || res.back().fst!=s[n]) res.pb({s[n],0}); auto l = factor(x), r = factor(n / x);
k = ((k % m) + m) % m;
res.back().snd++; l.insert(l.end(), ALL(r));
return to * c + k * sumsq(to) - m * divsum(to, c, k, m);
} return l;
}
return res; }
UNC FastDivisors euclid Diophantine CRT phiFunction PointsUnderLine ContinuedFractions FracBinarySearch 2025-04-20 13
FastDivisors.h Description: Euler’s ϕ function is defined as ϕ(n) := # of positive integers FracBinarySearch.h
Description: Given the prime factorization of a number, returns all its di- ≤ n that are coprime with n. ϕ(1) = 1, p prime ⇒ ϕ(pk ) = (p − 1)pk−1 , Description: Given f and N , finds the smallest fraction p/q ∈ [0, 1] such
visors. k
m, n coprime ⇒ ϕ(mn) = ϕ(m)ϕ(n). If n = p1 1 p2 2 ...pk
k r then ϕ(n) = that f (p/q) is true, and p, q ≤ N . You may want to throw an exception from
r
Time: O (d), where d is the number of divisors. 3c6074, 8 lines k1 −1 kr −1 Q f if it finds an exact solution, in which case N can be removed.
(p1 − 1)p1 ...(pr − 1)pr . ϕ(n) = n · p|n (1 − 1/p). Usage: fracBS([](Frac f) { return f.p>=3*f.q; }, 10); // {1,3}
vi divisors(vector<ii>& f) { P P
Time: O (log(N ))
d|n ϕ(d) = n, 1≤k≤n,gcd(k,n)=1 k = nϕ(n)/2, n > 1 79308c, 20 lines
vi res = {1};
for (auto& [p, k] : f) { Euler’s: a, n coprime ⇒ aϕ(n) ≡ 1 (mod n), am ≡ am mod ϕ(n) (mod n). struct Frac { ll p, q; };
ll sz = SZ(res); Generalization: m ≥ log2 (n) ⇒ xm ≡ xϕ(n)+(m mod ϕ(n)) (mod n).
fore(i,0,sz) for(ll j=0,x=p;j<k;j++,x*=p) res.pb(res[i]*x); Fermat’s little thm: p prime ⇒ ∀a : ap−1 ≡ 1 (mod p). 151aa0, 8 lines
Frac fracBS(auto&& f, ll N) {
} bool dir = 1, A = 1, B = 1;
return res; const ll LIM = 5000000; Frac lo{0, 1}, hi{1, 1}; // Set hi to 1/0 to search (0 , N]
} array<ll, LIM> phi; if (f(lo)) return lo;
assert(f(hi));
void calculatePhi() {
5.3 Divisibility fore(i,0,LIM) phi[i] = i&1 ? i : i/2;
while (A || B) {
ll adv = 0, step = 1; // move hi i f dir , e l s e lo
euclid.h for (ll i = 3; i < LIM; i += 2) if (phi[i] == i) for (ll si = 0; step; (step *= 2) >>= si) {
Description: Finds two integers x and y, such that ax + by = gcd(a, b). If for (ll j = i; j < LIM; j += i) phi[j] -= phi[j] / i; adv += step;
you just need gcd, use the built in gcd instead. If a and b are coprime, then } Frac mid{lo.p * adv + hi.p, lo.q * adv + hi.q};
x is the inverse of a (mod b). 33ba8f, 5 lines
if (abs(mid.p) > N || mid.q > N || dir == !f(mid))
adv -= step, si = 2;
ll euclid(ll a, ll b, ll &x, ll &y) { PointsUnderLine.h }
if (!b) return x = 1, y = 0, a; Description: Given a, b > 0, f returns the number of lattice points (x, y) hi.p += lo.p * adv, hi.q += lo.q * adv;
ll d = euclid(b, a % b, y, x); such that ax + by ≤ c and x, y > 0, and g returns the number of lattice dir = !dir, swap(lo, hi), A = B, B = !!adv;
return y -= a/b * x, d; points (x, y) such that ax + by ≤ c, 0 < x ≤ X and 0 < y ≤ Y 388aa4,
. }
11 lines
} return dir ? hi : lo;
ll f(ll a, ll b, ll c) {
if (c <= 0) return 0; }
Diophantine.h if (a < b) swap(a, b);
Description: Returns (x0 , y0 , dx, dy) such that all integer solutions (x, y)
to ax + by = r are (x0 + k · dx, y0 + k · dy) for integer k.
ll m = c / a, k = (a - 1) / b, h = (c - a * m) / b; 5.5 Pythagorean Triples
if (a == b) return m * (m - 1) / 2; The Pythagorean triples are uniquely generated by
Time: O (log(min(a, b))) return f(b, a - b*k, c - b*(k*m + h)) + k*m*(m - 1)/2 + m*h;
"./euclid.h" 12347a, 6 lines
}
array<ll, 4> diophantine(ll a, ll b, ll r) { ll g(ll a, ll b, ll c, ll X, ll Y) { a = k · (m2 − n2 ), b = k · (2mn), c = k · (m2 + n2 ),
ll x, y, g = euclid(a, b, x, y); if (a * X + b * Y <= c) return X * Y;
a /= g, b /= g, r /= g, x *= r, y *= r; return f(a,b,c)-f(a,b,c-a*X)-f(a,b,c-b*Y)+f(a,b,c-a*X-b*Y); with m > n > 0, k > 0, m⊥n, and either m or n even.
assert(a * x + b * y == r); // otherwise no solution }
return {x, y, -b, a}; 5.6 Primes
}
p = 962592769 is such that 221 | p − 1, which may be useful. For
CRT.h 5.4 Fractions hashing use 970592641 (31-bit number), 31443539979727 (45-bit),
Description: Chinese Remainder Theorem. ContinuedFractions.h 3006703054056749 (52-bit). There are 78498 primes less than
crt(a, m, b, n) computes x such that x ≡ a (mod m), x ≡ b (mod n). If Description: Given N and a real number x ≥ 0, finds the closest rational 1 000 000.
|a| < m and |b| < n, x will obey 0 ≤ x < lcm(m, n). Assumes mn < 262 . approximation p/q with p, q ≤ N . It will obey |p/q − x| ≤ 1/qN .
Time: log(n) For consecutive convergents, pk+1 qk − qk+1 pk = (−1)k . (pk /qk alternates Primitive roots exist modulo any prime power pa , except for
"euclid.h" 04d93a, 7 lines between > x and < x.) If x is rational, y eventually becomes ∞; if x is the
ll crt(ll a, ll m, ll b, ll n) { root of a degree 2 polynomial the a’s eventually become cyclic. p = 2, a > 2, and there are ϕ(ϕ(pa )) many. For p = 2, a > 2, the
if (n > m) swap(a, b), swap(m, n); Time: O (log N ) 5f8089, 21 lines
group Z× 2a is instead isomorphic to Z2 × Z2a−2 .
ll x, y, g = euclid(m, n, x, y);
assert((a - b) % g == 0); // e l s e no solution // double i s safe for N ∼ 1e7 , use long double for N ∼ 1e9
typedef long double ld;
5.7 Highly composite numbers
x = (b - a) % n * x % n / g * m + a;
return x < 0 ? x + m*n/g : x; ii approximate(ld x, ll N) { The number of divisors of n is O(log(log(n))). Max number of
} ll LP = 0, LQ = 1, P = 1, Q = 0, inf = LLONG_MAX; ld y = x; divisors up to 10n :
for (;;) {
ll lim = min(P ? (N-LP) / P : inf, Q ? (N-LQ)/Q : inf), n 0 1 2 3 4 5 6 7
5.3.1 Bézout’s identity a = (ll)floor(y), b = min(a, lim),
For a ̸=, b ̸= 0, then d = gcd(a, b) is the smallest positive integer NP = b*P + LP, NQ = b*Q + LQ; divisors 1 4 12 32 64 128 240 448
for which there are integer solutions to if (a > b) { number 1 6 60 840 7560 83160 720720 8648640
// I f b > a/2, we have a semi−convergent that gives us a
// better approximation ; i f b = a/2, we ∗may∗ have one .
8 9 10 11 12
ax + by = d // Return {P, Q} here for a more canonical approximation . 768 1344 2304 4032 6720
return (abs(x - (ld)NP/(ld)NQ) < abs(x - (ld)P/(ld)Q)) ? 73513440 735134400 6983776800 97772875200 963761198400
If (x, y) is one solution, then all solutions are given by ii{NP, NQ} : ii{P, Q};
} 13 14 15
  if (abs(y = 1/(y - (ld)a)) > 3*N) { 10752 17280 26880
kb ka return {NP, NQ};
x+ ,y − , k∈Z }
9316358251200 97821761637600 866421317361600
gcd(a, b) gcd(a, b) 16 17 18
LP = P, P = NP, LQ = Q, Q = NQ;
} 41472 64512 103680
}
phiFunction.h 8086598962041600 74801040398884800 897612484786617600
UNC Mobius IntPerm multinomial 2025-04-20 14
P
d|n d = O(n log log n). IntPerm.h 6.2.2 Lucas’ Theorem
Description: Permutation -> integer conversion. (Not order preserving.)
Let n, m be non-negative integers and p a prime. Write
5.8 Mobius Function Integer -> permutation can use a lookup table.
n= pk + ... +n1 p + n0 and m = mk pk + ... + m1 p + m0 . Then
 Time: O (n) d7d731, 7 lines  nkQ k
0
 n is not square free
ll permToInt(vi& v) {
n
m
≡ ni
i=0 mi (mod p).
µ(n) = 1 n has even number of prime factors ll use = 0, i = 0, r = 0; 6.2.3 Binomials
for (ll x : v)
Kummer’s theorem: the exponent of p in nk is the number of
 
−1 n has odd number of prime factors

r = r * ++i + __builtin_popcountll(use & -(1<<x)),
use |= 1 << x; // (note : minus, not ∼! ) carries when adding k and n − k in base p, or, equivalently
return r;
Mobius.h } !!
Description: Computes the Mobius function µ(n) for all n < L. n sp (k) + sp (n − k) − sp (n)
Time: O (L log L) 6.1.2 Cycles νp =
50cb20, 6 lines k p−1
const ll L = 1e6; Let gS (n) be the number of n-permutations whose cycle lengths
array<int8_t, L> mu; all belong to the set S. Then n

void calculateMu() { where sp (n) is the sum of the digits of n in base p. Therefore k
mu[1] = 1; ∞
!
is odd iff k is a submask of n.
fore(i,1,L) if(mu[i]) for(ll j=2*i; j<L; j+=i) mu[j]-=mu[i];
X xn X xn
}
gS (n) = exp
n=0
n! n∈S
n ! ! k
! !
n n n−1 Y n+1−i n−1 n−1
Mobius Inversion: = = = +
k k k−1 i k−1 k
X X
6.1.3 Derangements i=1

g(n) = f (d) ⇔ f (n) = µ(d)g(n/d) Permutations of a set such that none of the elements appear in
their original position. k
! ! n
! !
d|n d|n X n+i n+k+1 X i n+1
= , =
 
n! i k k k+1
Other useful formulas/forms: D(n) = (n − 1)(D(n − 1) + D(n − 2)) = nD(n − 1) + (−1)n = i=0 i=0

P e
d|n µ(d) = [n = 1] (very useful) n
!2 ! n
!
X n 2n X n
P P 6.1.4 Burnside’s lemma = , k = n2n−1
g(n) = n|d f (d) ⇔ f (n) = n|d µ(d/n)g(d) k n k
k=0 k=0
Given a group G of symmetries and a set X, the number of
n n
elements of X up to symmetry equals
P P
g(n) = 1≤m≤n f ( m ) ⇔ f (n) = 1≤m≤n µ(m)g( m )
1 X g multinomial.h k + · · · + k  P
|X |, 1 n ( ki )!
|G| g∈G Description: Computes = .
k1 , k2 , . . . , k n k1 !k2 !...kn !
Combinatorial (6) ll multinomial(vi& v) {
91eef8, 5 lines

where X g are the elements fixed by g (g.x = x). ll c = 1, m = v.empty() ? 1 : v[0];


6.1 Permutations fore(i,1,SZ(v)) fore(j,0,v[i]) c = c * ++m / (j+1);
return c;
6.1.1 Factorial If f (n) counts “configurations” (of some sort) of length n, we can }
Legendre’s formula: the exponent of p in the factorization of n! ignore rotational symmetry using G = Zn to get
is n−1 6.3 General purpose numbers
∞ 
1X 1X

X n n − sp (n) g(n) = f (gcd(n, k)) = f (k)ϕ(n/k).
νp (n!) = = 6.3.1 Bernoulli numbers
p i p−1 n n
i=1 k=0 k|n EGF of Bernoulli numbers is B(t) = et t−1 (FFT-able).
where sp (n) is the sum of the digits of n in base p. B[0, . . .] = [1, − 12 , 16 , 0, − 30
1 1
, 0, 42 , . . .]
6.2 Partitions and subsets
Wilson’s: n > 1 is prime iff (n − 1)! ≡ −1 (mod n). Sums of powers:
6.2.1 Partition function
n m 
Number of ways of writing n as a sum of positive integers, X 1 X m + 1
√  n n nm = Bk · (n + 1)m+1−k
disregarding the order of the summands. m + 1 k=0 k
n! ∼ 2πn i=1
e X
p(0) = 1, p(n) = (−1)k+1 p(n − k(3k − 1)/2)
n 123 4 5 6 7 8 9 10 Euler-Maclaurin formula for infinite sums:
k∈Z\{0}
n! 1 2 6 24 120 720 5040 40320 362880 3628800 ∞ ∞
Z ∞ Bk (k−1)
n 11 12 13 14 15 16 17 √ X
f (i) = f (x)dx −
X
f (m)
p(n) ∼ 0.145/n · exp(2.56 n) k!
n! 4.0e7 4.8e8 6.2e9 8.7e10 1.3e12 2.1e13 3.6e14 i=m m k=1
n 20 25 30 40 50 100 150 171 n 0 1 2 3 4 5 6 7 8 9 20 50 100 ∞ f ′ (m) f ′′′ (m)
Z
f (m)
n! 2e18 2e25 3e32 8e47 3e64 9e157 6e262 >DBL MAX p(n) 1 1 2 3 5 7 11 15 22 30 627 ∼2e5 ∼2e8 ≈ f (x)dx + − + + O(f (5) (m))
m 2 12 720
UNC BellmanFord FloydWarshall TopoSort DynamicConnectivity 2025-04-20 15
6.3.2 Stirling numbers of the first kind 6.3.8 Catalan numbers const ll inf = 1LL << 62;
void floydWarshall(vector<vi>& m) {
Number of permutations on n items with k cycles. ! ! ! ll n = SZ(m);
1 2n 2n 2n (2n)! fore(i,0,n) m[i][i] = min(m[i][i], 0LL);
Cn = = − =
c(n, k) = c(n − 1, k − 1) + (n − 1)c(n − 1, k), c(0, 0) = 1 n+1 n n n+1 (n + 1)!n! fore(k,0,n) fore(i,0,n) fore(j,0,n)
Pn if (m[i][k] != inf && m[k][j] != inf) {
k
k=0 c(n, k)x = x(x + 1) . . . (x + n − 1)
auto newDist = max(m[i][k] + m[k][j], -inf);
2(2n + 1) X
m[i][j] = min(m[i][j], newDist);
C0 = 1, Cn+1 = Cn , Cn+1 = Ci Cn−i
n+2 }
c(8, k) = 8, 0, 5040, 13068, 13132, 6769, 1960, 322, 28, 1 fore(k,0,n) if (m[k][k] < 0) fore(i,0,n) fore(j,0,n)
c(n, 2) = 0, 0, 1, 3, 11, 50, 274, 1764, 13068, 109584, . . . 4n if (m[i][k] != inf && m[k][j] != inf) m[i][j] = -inf;
Cn ∼ √ }
n3/2 π
6.3.3 Eulerian numbers
Number of permutations π ∈ Sn in which exactly k elements are Cn = 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, . . . TopoSort.h
greater than the previous element. k j:s s.t. π(j) > π(j + 1), Description: Topological sorting. Given is an oriented graph. Output is an
• sub-diagonal monotone paths in an n × n grid. ordering of vertices, such that there are edges only from left to right. If there
k + 1 j:s s.t. π(j) ≥ j, k j:s s.t. π(j) > j. • strings with n pairs of parenthesis, correctly nested. are cycles, the returned list will have size smaller than n – nodes reachable
from cycles will not be returned.
• binary trees with with n + 1 leaves (0 or 2 children). Time: O (|V | + |E|)
E(n, k) = (n − k)E(n − 1, k − 1) + (k + 1)E(n − 1, k) • ordered trees with n + 1 vertices.
d543aa, 8 lines
vi topoSort(const vector<vi>& g) {
• ways a convex polygon with n + 2 sides can be cut into vi d(SZ(g)), q;
E(n, 0) = E(n, n − 1) = 1 triangles by connecting vertices with straight lines. for (auto& li : g) for (ll x : li) d[x]++;

! • permutations of [n] with no 3-term increasing subseq. fore(i,0,SZ(g)) if (!d[i]) q.pb(i);


for (ll j = 0; j < SZ(q); j++) for (ll x : g[q[j]])
k
j n+1 6.4 Game theory if (!--d[x]) q.pb(x);
X
E(n, k) = (−1) (k + 1 − j)n return q;
j=0
j Misere nim: Second player wins iff (some heap size is greater }
than 1 and xor is 0) or (all heap sizes are 1 and n is odd).
6.3.4 Stirling numbers of the second kind DynamicConnectivity.h
Description: Offline disjoint-set data structure with remove of arbitrary
Partitions of n distinct elements into exactly k groups. edges. Uses UnionFindRollbackStore so it also supports queries of global
Graph (7) value of RSUF. First use add, remove and query to make operations and
then call process to get the answers of the queries in the variable ans. Does
S(n, k) = S(n − 1, k − 1) + kS(n − 1, k)
not support multiple edges.
7.1 Fundamentals Time: O Q log2 N
S(n, 1) = S(n, n) = 1 BellmanFord.h "../data-structures/UnionFindRollbackStore.h" c8407a, 51 lines

Description: Calculates shortest paths from s in a graph that might have enum { ADD, DEL, QUERY };
! negative edge weights. Stores the answer in nodes. Unreachable nodes get struct Query { ll type, x, y; }; // You can add s t u f f for QUERY
k
1 X struct DynCon {
k−j k dist = inf; nodes reachable through negative-weight cycles get dist = -inf.
S(n, k) = (−1) jn Assumes V 2 max |wi | < ∼263 . vector<Query> q;
k! j=0 j Time: O (V E) RSUF uf;
387d3f, 17 lines
vi mt;
const ll inf = LLONG_MAX; map<ii, ll> last;
6.3.5 Bell numbers struct Ed { ll a, b, w, s() { return a < b ? a : -a; }}; vector<T> ans;
Total number of partitions of n distinct elements. B(n) = struct Node { ll dist = inf, prev = -1; }; DynCon(ll n) : uf(n) {}
1, 1, 2, 5, 15, 52, 203, 877, 4140, 21147, . . . . For p prime, DynCon(vector<D>& d) : uf(d) {}
void bellmanFord(vector<Node>& nodes, vector<Ed>& eds, ll s) { void add(ll x, ll y) {
nodes[s].dist = 0; if (x > y) swap(x, y);
B(pm + n) ≡ mB(n) + B(n + 1) (mod p) sort(ALL(eds), [](Ed a, Ed b) { return a.s() < b.s(); });
ll lim = SZ(nodes) / 2 + 2; // /3+100 with shuffled vertices
mt.pb(-1);
last[{x, y}] = SZ(q);
fore(i,0,lim) for (Ed ed : eds) { q.pb({ADD, x, y});
Node cur = nodes[ed.a], &dest = nodes[ed.b];
6.3.6 Fibonacci numbers if (abs(cur.dist) == inf) continue;
}
void remove(ll x, ll y) {
ll d = cur.dist + ed.w; if (x > y) swap(x, y);
if (d < dest.dist) dest = {i < lim-1 ? d : -inf, ed.a}; ll pr = last[{x, y}];
n
X } mt[pr] = SZ(q);
2
F2n+1 = Fn+1 + Fn2 , 2
F2n = Fn+1 2
− Fn−1 , Fi = Fn+2 − 1 fore(i,0,lim) for (Ed e : eds) mt.pb(pr);
if (nodes[e.a].dist == -inf) nodes[e.b].dist = -inf; q.pb({DEL, x, y});
i=1 } }
void query() { // Add parameters i f needed
Fn+i Fn+j − Fn Fn+i+j = (−1)n Fi Fj FloydWarshall.h q.pb({QUERY, -1, -1});
Description: Calculates all-pairs shortest path in a directed graph that mt.pb(-1);
might have negative edge weights. Input is an distance matrix m, where }
6.3.7 Labeled unrooted trees m[i][j] = inf if i and j are not adjacent. As output, m[i][j] is set to the void process() { // Answers a l l queries in order
# on n vertices: nn−2 shortest distance between i and j, inf if no path, or -inf if the path goes if (q.empty()) return;
through a negative-weight cycle. fore(i, 0, SZ(q))
# on k existing trees of size ni : n1 n2 · · · nk nk−2 Time: O N 3

if (q[i].type == ADD && mt[i] < 0) mt[i] = SZ(q);
7eb90d, 12 lines
# with degrees di : (n − 2)!/((d1 − 1)! · · · (dn − 1)!) go(0, SZ(q));
UNC PushRelabel MinCostMaxFlow EdmondsKarp 2025-04-20 16
} } else if (cur[u]->c && H[u] == H[cur[u]->dest]+1) fl = min(fl, x->cap - x->flow);
void go(ll s, ll e) { addFlow(*cur[u], min(ec[u], cur[u]->c));
if (s + 1 == e) { else ++cur[u]; totflow += fl;
if (q[s].type == QUERY) { // Answer query using DSU } for (edge* x = par[t]; x; x = par[x->from]) {
ans.pb(uf.ans); // Maybe you want to use uf . get (x) } x->flow += fl;
} // for some x stored in Query bool leftOfMinCut(ll a) { return H[a] >= SZ(g); } ed[x->to][x->rev].flow -= fl;
return; }; }
} }
ll k = uf.time(), m = (s + e) / 2; fore(i,0,N) for (edge& e : ed[i])
for (ll i = e; --i >= m;) MinCostMaxFlow.h totcost += e.cost * e.flow;
if (0 <= mt[i] && mt[i] < s) uf.join(q[i].x, q[i].y); Description: Min-cost max-flow. If costs can be negative, call setpi before return {totflow, totcost/2};
go(s, m); maxflow, but note that negative cost cycles are not supported. To obtain }
uf.rollback(k); the actual flow, look at positive values only.
for (ll i = m; --i >= s;) Time: O (F E log(V )) where F is max flow. O (V E) for setpi. 735f9d, 80 lines // I f some costs can be negative , c a l l t h i s before maxflow :
if (mt[i] >= e) uf.join(q[i].x, q[i].y); void setpi(ll s) { // ( otherwise , leave t h i s out)
go(m, e); #include "ext/pb_ds/priority_queue.hpp" fill(ALL(pi), INF); pi[s] = 0;
uf.rollback(k); ll it = N, ch = 1; ll v;
} const ll INF = numeric_limits<ll>::max() / 4; while (ch-- && it--)
}; fore(i,0,N) if (pi[i] != INF)
struct MCMF { for (edge& e : ed[i]) if (e.cap)
struct edge { if ((v = pi[i] + e.cost) < pi[e.to])
7.2 Network flow ll from, to, rev;
ll cap, cost, flow;
pi[e.to] = v, ch = 1;
assert(it >= 0); // negative cost cycle
PushRelabel.h }; }
Description: Push-relabel using the highest label selection rule and the gap ll N; };
heuristic. Quite fast in practice. To obtain the actual flow, look at positive vector<vector<edge>> ed;
values only.
 √  vi seen;
Time: O V 2 E vi dist, pi;
da4f8b, 48 lines vector<edge*> par;
struct PushRelabel { EdmondsKarp.h
struct Edge { MCMF(ll N) : N(N), ed(N), seen(N), dist(N), pi(N), par(N) {} Description: Flow algorithm with guaranteed complexity O(V E 2 ). To get
ll dest, back; edge flow values, compare capacities before and after, and take the positive
ll f, c; void addEdge(ll from, ll to, ll cap, ll cost) { values only. 1e8088, 36 lines
}; if (from == to) return;
template<class T> T edmondsKarp(vector<unordered_map<ll, T>>&
vector<vector<Edge>> g; ed[from].pb(edge{from, to, SZ(ed[to]), cap, cost, 0});
graph, ll source, ll sink) {
vi ec; ed[to].pb(edge{to, from, SZ(ed[from])-1, 0, -cost, 0});
assert(source != sink);
vector<Edge*> cur; }
T flow = 0;
vector<vi> hs; vi H;
vi par(SZ(graph)), q = par;
PushRelabel(ll n) : g(n), ec(n), cur(n), hs(2*n), H(n) {} void path(ll s) {
fill(ALL(seen), 0);
for (;;) {
void addEdge(ll s, ll t, ll cap, ll rcap=0) { fill(ALL(dist), INF);
fill(ALL(par), -1);
if (s == t) return; dist[s] = 0; ll di;
par[source] = 0;
g[s].pb({t, SZ(g[t]), 0, cap});
ll ptr = 1;
g[t].pb({s, SZ(g[s])-1, 0, rcap}); __gnu_pbds::priority_queue<ii> q;
q[0] = source;
} vector<decltype(q)::point_iterator> its(N);
q.push({ 0, s });
for (ll i = 0; i < ptr; i++) {
void addFlow(Edge& e, ll f) {
ll x = q[i];
Edge &back = g[e.dest][e.back]; while (!q.empty()) {
for (auto e : graph[x]) {
if (!ec[e.dest] && f) hs[H[e.dest]].pb(e.dest); s = q.top().snd; q.pop();
if (par[e.fst] == -1 && e.snd > 0) {
e.f += f; e.c -= f; ec[e.dest] += f; seen[s] = 1; di = dist[s] + pi[s];
par[e.fst] = x;
back.f -= f; back.c += f; ec[back.dest] -= f; for (edge& e : ed[s]) if (!seen[e.to]) {
q[ptr++] = e.fst;
} ll val = di - pi[e.to] + e.cost;
if (e.fst == sink) goto out;
ll calc(ll s, ll t) { if (e.cap - e.flow > 0 && val < dist[e.to]) {
}
ll v = SZ(g); H[s] = v; ec[t] = 1; dist[e.to] = val;
}
vi co(2*v); co[0] = v-1; par[e.to] = &e;
}
fore(i,0,v) cur[i] = g[i].data(); if (its[e.to] == q.end())
return flow;
for (Edge& e : g[s]) addFlow(e, e.c); its[e.to] = q.push({ -dist[e.to], e.to });
out:
else
T inc = numeric_limits<T>::max();
for (ll hi = 0;;) { q.modify(its[e.to], { -dist[e.to], e.to });
for (ll y = sink; y != source; y = par[y])
while (hs[hi].empty()) if (!hi--) return -ec[s]; }
inc = min(inc, graph[par[y]][y]);
ll u = hs[hi].back(); hs[hi].pop_back(); }
while (ec[u] > 0) // discharge u }
flow += inc;
if (cur[u] == g[u].data() + SZ(g[u])) { fore(i,0,N) pi[i] = min(pi[i] + dist[i], INF);
for (ll y = sink; y != source; y = par[y]) {
H[u] = 1e9; }
ll p = par[y];
for (Edge& e : g[u]) if (e.c && H[u] > H[e.dest]+1)
if ((graph[p][y] -= inc) <= 0) graph[p].erase(y);
H[u] = H[e.dest]+1, cur[u] = &e; ii maxflow(ll s, ll t) {
graph[y][p] += inc;
if (++co[H[u]], !--co[hi] && hi < v) ll totflow = 0, totcost = 0;
}
fore(i,0,v) if (hi < H[i] && H[i] < v) while (path(s), seen[t]) {
}
--co[H[i]], H[i] = v + 1; ll fl = INF;
}
hi = H[u]; for (edge* x = par[t]; x; x = par[x->from])
UNC Dinic MinCut GlobalMinCut GomoryHu hopcroftKarp DFSMatching MinimumVertexCover 2025-04-20 17
Dinic.h s = t, t = max_element(ALL(w)) - w.begin(); }
Description: Flow algorithm with complexity O(V E log U ) where U = fore(i,0,n) w[i] += mat[t][i]; else if (btoa[b] != a && !B[b]) {

max |cap|. O(min(E 1/2 , V 2/3 )E) if U = 1; O( V E) for bipartite match- } B[b] = lay;
ing. best = min(best, {w[t] - mat[t][t], co[t]}); next.pb(btoa[b]);
d44dbc, 42 lines
co[s].insert(co[s].end(), ALL(co[t])); }
struct Dinic { fore(i,0,n) mat[s][i] += mat[t][i]; }
struct Edge { fore(i,0,n) mat[i][s] = mat[s][i]; if (islast) break;
ll to, rev; mat[0][t] = LLONG_MIN; if (next.empty()) return res;
ll c, oc; } for (ll a : next) A[a] = lay;
ll flow() { return max(oc - c, 0LL); } // i f you need flows return best; cur.swap(next);
}; } }
vi lvl, ptr, q; fore(a,0,SZ(g))
vector<vector<Edge>> adj; res += dfs(a, 0, g, btoa, A, B);
Dinic(ll n) : lvl(n), ptr(n), q(n), adj(n) {}
GomoryHu.h
Description: Given a list of edges representing an undirected flow graph, }
void addEdge(ll a, ll b, ll c, ll rcap = 0) { }
returns edges of the Gomory-Hu tree. The max flow between any pair of
adj[a].pb({b, SZ(adj[b]), c, c});
vertices is given by minimum edge weight along the Gomory-Hu tree path.
adj[b].pb({a, SZ(adj[a]) - 1, rcap, rcap});
}
Time: O (V ) Flow Computations DFSMatching.h
"PushRelabel.h" a93d73, 13 lines Description: Simple bipartite matching algorithm. Graph g should be a list
ll dfs(ll v, ll t, ll f) {
typedef array<ll, 3> Edge; of neighbors of the left partition, and btoa should be a vector full of -1’s of
if (v == t || !f) return f;
vector<Edge> gomoryHu(ll N, vector<Edge> ed) { the same size as the right partition. Returns the size of the matching. btoa[i]
for (ll& i = ptr[v]; i < SZ(adj[v]); i++) {
vector<Edge> tree; will be the match for vertex i on the right side, or −1 if it’s not matched.
Edge& e = adj[v][i];
vi par(N); Usage: vi btoa(m, -1); dfsMatching(g, btoa);
if (lvl[e.to] == lvl[v] + 1)
fore(i,1,N) { Time: O (V E)
if (ll p = dfs(e.to, t, min(f, e.c))) { 6a75ec, 22 lines
e.c -= p, adj[e.to][e.rev].c += p; PushRelabel D(N); // Dinic also works bool find(ll j, vector<vi>& g, vi& btoa, vi& vis) {
return p; for (Edge t : ed) D.addEdge(t[0], t[1], t[2], t[2]); if (btoa[j] == -1) return 1;
} tree.pb({i, par[i], D.calc(i, par[i])}); vis[j] = 1; ll di = btoa[j];
} fore(j,i+1,N) for (ll e : g[di])
return 0; if (par[j] == par[i] && D.leftOfMinCut(j)) par[j] = i; if (!vis[e] && find(e, g, btoa, vis)) {
} } btoa[e] = di;
ll calc(ll s, ll t) { return tree; return 1;
ll flow = 0; q[0] = s; } }
fore(L,0,31) do { // ’ l l L=30’ maybe f a s t e r for random data return 0;
lvl = ptr = vi(SZ(q)); 7.3 Matching }
ll qi = 0, qe = lvl[s] = 1; ll dfsMatching(vector<vi>& g, vi& btoa) {
while (qi < qe && !lvl[t]) { hopcroftKarp.h vi vis;
ll v = q[qi++]; Description: Fast bipartite matching algorithm. Graph g should be a list
fore(i,0,SZ(g)) {
for (Edge e : adj[v]) of neighbors of the left partition, and btoa should be a vector full of -1’s of
vis.assign(SZ(btoa), 0);
if (!lvl[e.to] && e.c >> (30 - L)) the same size as the right partition. Returns the size of the matching. btoa[i]
for (ll j : g[i])
q[qe++] = e.to, lvl[e.to] = lvl[v] + 1; will be the match for vertex i on the right side, or −1 if it’s not matched.
if (find(j, g, btoa, vis)) {
} Usage: vi √btoa(m, -1); hopcroftKarp(g, btoa);
 btoa[j] = i;
while (ll p = dfs(s, t, LLONG_MAX)) flow += p; Time: O VE break;
2bbb99, 42 lines
} while (lvl[t]); }
return flow; bool dfs(ll a, ll L, vector<vi>& g, vi& btoa, vi& A, vi& B) { }
} if (A[a] != L) return 0; return SZ(btoa) - (ll)count(ALL(btoa), -1);
bool leftOfMinCut(ll a) { return lvl[a] != 0; } A[a] = -1; }
}; for (ll b : g[a]) if (B[b] == L + 1) {
B[b] = 0;
if (btoa[b] == -1 || dfs(btoa[b], L + 1, g, btoa, A, B)) MinimumVertexCover.h
MinCut.h return btoa[b] = a, 1; Description: Finds a minimum vertex cover in a bipartite graph. The size
Description: After running max-flow, the left side of a min-cut from s to t } is the same as the size of a maximum matching, and the complement is a
is given by all vertices reachable from s, only traversing edges with positive return 0; maximum independent set.
residual capacity. } "DFSMatching.h" cd3f06, 20 lines

vi cover(vector<vi>& g, ll n, ll m) {
ll hopcroftKarp(vector<vi>& g, vi& btoa) { vi match(m, -1);
GlobalMinCut.h ll res = 0; ll res = dfsMatching(g, match);
Description: Find a global minimum cut in an undirected graph, as repre- vi A(g.size()), B(btoa.size()), cur, next; vector<bool> lfound(n, true), seen(m);
sented by an adjacency matrix. for (;;) { for (ll it : match) if (it != -1) lfound[it] = false;
Time: O V 3
 fill(ALL(A), 0); vi q, cover;
16cb60, 21 lines fill(ALL(B), 0); fore(i,0,n) if (lfound[i]) q.pb(i);
pair<ll, vi> globalMinCut(vector<vi> mat) { cur.clear(); while (!q.empty()) {
pair<ll, vi> best = {LLONG_MAX, {}}; for (ll a : btoa) if (a != -1) A[a] = -1; ll i = q.back(); q.pop_back();
ll n = SZ(mat); fore(a,0,SZ(g)) if (A[a] == 0) cur.pb(a); lfound[i] = 1;
vector<vi> co(n); for (ll lay = 1;; lay++) { for (ll e : g[i]) if (!seen[e] && match[e] != -1) {
fore(i,0,n) co[i] = {i}; bool islast = 0; seen[e] = true;
fore(ph,1,n) { next.clear(); q.pb(match[e]);
vi w = mat[0]; for (ll a : cur) for (ll b : g[a]) { }
size_t s = 0, t = 0; if (btoa[b] == -1) { }
fore(it,0,n-ph) { // O(V^2) −> O(E log V) with prio . queue B[b] = lay; fore(i,0,n) if (!lfound[i]) cover.pb(i);
w[t] = LLONG_MIN; islast = 1; fore(i,0,m) if (seen[i]) cover.pb(n+i);
UNC WeightedMatching GeneralMatching SCC BiconnectedComponents 2sat 2025-04-20 18
assert(SZ(cover) == res); vi has(M, 1); vector<ii> ret; if (y == at) { // s e l f loop
return cover; fore(it,0,M/2) { nodesComp[at].insert(edgesComp[e] = nComps++);
} fore(i,0,M) if (has[i]) } else if (num[y]) {
fore(j,i+1,M) if (A[i][j] && mat[i][j]) { top = min(top, num[y]);
WeightedMatching.h fi = i; fj = j; goto done; if (num[y] < me) st.pb(e);
Description: Given a weighted bipartite graph, matches every node on the } assert(0); done: } else {
left with a node on the right such that no nodes are in two matchings and the if (fj < N) ret.pb({fi, fj}); ll si = SZ(st), up = dfs(y, e);
sum of the edge weights is minimal. Takes cost[N][M], where cost[i][j] = cost has[fi] = has[fj] = 0; top = min(top, up);
for L[i] to be matched with R[j] and returns (min cost, match), where L[i] is fore(sw,0,2) { if (up == me) {
matched with R[match[i]]. Negate costs for max cost. Requires N ≤ M . ll a = modpow(A[fi][fj], mod-2); st.pb(e); // from s i to SZ( s t ) we have a comp
Time: O N 2 M
 fore(i,0,M) if (has[i] && A[i][fj]) { fore(i, si, SZ(st)) {
178f97, 31 lines ll b = A[i][fj] * a % mod; edgesComp[st[i]] = nComps;
pair<ll, vi> hungarian(const vector<vi> &a) { fore(j,0,M) A[i][j] = (A[i][j] - A[fi][j] * b) % mod; auto [u, v] = edges[st[i]];
if (a.empty()) return {0, {}}; } nodesComp[u].insert(nComps);
ll n = SZ(a) + 1, m = SZ(a[0]) + 1; swap(fi,fj); nodesComp[v].insert(nComps);
vi u(n), v(m), p(m), ans(n - 1); } }
fore(i,1,n) { } nComps++, st.resize(si);
p[0] = i; return ret; } else if (up < me) st.pb(e); // e l s e e i s bridge
ll j0 = 0; // add ”dummy” worker 0 } }
vi dist(m, LLONG_MAX), pre(m, -1); }
vector<bool> done(m + 1);
do { // d i j k s t r a
7.4 DFS algorithms };
return top;

done[j0] = true; SCC.h


ll i0 = p[j0], j1, delta = LLONG_MAX; Description: Finds strongly connected components in a directed graph. If fore(u, 0, n) if (!num[u]) dfs(u, -1);
fore(j,1,m) if (!done[j]) { vertices u, v belong to the same component, we can reach u from v and vice fore(u, 0, n) if (nodesComp[u].empty())
auto cur = a[i0 - 1][j - 1] - u[i0] - v[j]; versa. Returns the number of components and the component of each vertex. nodesComp[u].insert(nComps++);
if (cur < dist[j]) dist[j] = cur, pre[j] = j0; Natural order of components is reverse topological order (a component only
if (dist[j] < delta) delta = dist[j], j1 = j; has edges to components with lower index). return tuple(nComps, edgesComp, nodesComp);
} Time: O (E + V ) d2c984, 17 lines
};
fore(j,0,m) {
if (done[j]) u[p[j]] += delta, v[j] -= delta; pair<ll, vi> scc(vector<vi>& g) {
else dist[j] -= delta; ll n = SZ(g), Time = 0, ncomps = 0; 2sat.h
} vi val(n), comp(n, -1), z; Description: Calculates a valid assignment to boolean variables a,
j0 = j1; function<ll(ll)> dfs = [&](ll j) { b, c,... to a 2-SAT problem, so that an expression of the type
} while (p[j0]); ll low = val[j] = ++Time, x; z.pb(j); (a||b)&&(!a||c)&&(d||!b)&&... becomes true, or reports that it is unsatis-
while (j0) { // update alternating path for (ll e : g[j]) if (comp[e] < 0) fiable. Negated variables are represented by bit-inversions (∼x).
ll j1 = pre[j0]; low = min(low, val[e] ?: dfs(e)); Usage: TwoSat ts(number of boolean variables);
p[j0] = p[j1], j0 = j1; if (low == val[j]) { ts.either(0, ∼3); // Var 0 is true or var 3 is false
} do comp[x = z.back()] = ncomps, z.pop_back(); ts.setValue(2); // Var 2 is true
} while (x != j); ts.atMostOne({0,∼1,2}); // <= 1 of vars 0, ∼1 and 2 are true
fore(j,1,m) if (p[j]) ans[p[j] - 1] = j - 1; ncomps++; ts.solve(); // Returns true iff it is solvable
return {-v[0], ans}; // min cost } ts.values[0..N-1] holds the assigned values to the vars
} return val[j] = low; Time: O (N + E), where N is the number of boolean variables, and E is the
}; number of clauses.
fore(i, 0, n) if (comp[i] < 0) dfs(i); 0c5d9b, 50 lines
GeneralMatching.h return {ncomps, comp}; struct TwoSat {
Description: Matching for general graphs. Fails with probability N/mod. } ll N;
Time: O N 3 vector<vi> gr;
"../numerical/MatrixInverse-mod.h" d15d4f, 40 lines vi values; // 0 = false , 1 = true
BiconnectedComponents.h
vector<ii> generalMatching(ll N, vector<ii>& ed) { Description: Finds all biconnected components in an undirected graph, and
vector<vi> mat(N, vi(N)), A; runs a callback for the edges in each. In a biconnected component there are TwoSat(ll n = 0) : N(n), gr(2*n) {}
for (auto [a, b] : ed) { at least two distinct paths between any two nodes. Note that a node can be
ll r = rand() % mod; in several components. An edge which is not in a component is a bridge, i.e., ll addVar() { // ( optional )
mat[a][b] = r, mat[b][a] = (mod - r) % mod; not part of any cycle. gr.pb({}), gr.pb({});
} Time: O (E + V ) return N++;
6def45, 43 lines }
ll r = matInv(A = mat), M = 2*N - r, fi, fj; auto BCC(ll n, const vector<ii>& edges) {
assert(r % 2 == 0); ll Time = 0, eid = 0; void either(ll f, ll j) {
vi num(n), st; f = max(2*f, -1-2*f), j = max(2*j, -1-2*j);
if (M != N) do { vector<vector<ii>> adj(n); gr[f].pb(j^1), gr[j].pb(f^1);
mat.resize(M, vi(M)); for (auto [a, b] : edges) }
fore(i,0,N) { adj[a].pb({b, eid}), adj[b].pb({a, eid++}); void setValue(ll x) { either(x, x); }
mat[i].resize(M);
fore(j,N,M) { ll nComps = 0; // number of biconnected components void atMostOne(const vi& li) { // ( optional )
ll r = rand() % mod; vi edgesComp(eid, -1); // comp of each edge or −1 i f bridge if (SZ(li) <= 1) return;
mat[i][j] = r, mat[j][i] = (mod - r) % mod; vector<set<ll>> nodesComp(n); // comps of each node ll cur = ∼li[0];
} fore(i, 2, SZ(li)) {
} function<ll(ll, ll)> dfs = [&](ll at, ll par) { ll next = addVar();
} while (matInv(A = mat) != M); ll me = num[at] = ++Time, top = me; either(cur, ∼li[i]);
for (auto [y, e] : adj[at]) if (e != par) { either(cur, next);
UNC EulerWalk EdgeColoring MaximalCliques MaximumClique MaximumIndependentSet BinaryLifting LCA 2025-04-20 19
either(∼li[i], next); while (adj[fan[i]][d] != -1) { auto f = [&](ll i) { return e[v.i][i]; };
cur = ∼next; ll left = fan[i], right = fan[++i], e = cc[i]; while (any_of(ALL(C[k]), f)) k++;
} adj[u][e] = left, adj[left][e] = u; if (k > mxk) mxk = k, C[mxk + 1].clear();
either(cur, ∼li[1]); adj[right][e] = -1, free[right] = e; if (k < mnk) T[j++].i = v.i;
} } C[k].pb(v.i);
adj[u][d] = fan[i], adj[fan[i]][d] = u; }
vi val, comp, z; ll time = 0; for (ll y : {fan[0], u, end}) if (j > 0) T[j - 1].d = 0;
ll dfs(ll i) { for (ll& z = free[y] = 0; adj[y][z] != -1; z++); fore(k,mnk,mxk + 1) for (ll i : C[k])
ll low = val[i] = ++time, x; z.pb(i); } T[j].i = i, T[j++].d = k;
for (ll e : gr[i]) if (!comp[e]) for (auto [u, v] : eds) expand(T, lev + 1);
low = min(low, val[e] ?: dfs(e)); ret.pb(find(ALL(adj[u]), v) - adj[u].begin()); } else if (SZ(q) > SZ(qmax)) qmax = q;
if (low == val[i]) do { return ret; q.pop_back(), R.pop_back();
comp[x = z.back()] = low, z.pop_back(); } }
if (values[x>>1] == -1) values[x>>1] = x&1; }
} while (x != i); vi maxClique() { init(V), expand(V); return qmax; }
return val[i] = low; 7.6 Heuristics Maxclique(vb conn) : e(conn), C(SZ(e)+1), S(SZ(C)), old(S) {
} MaximalCliques.h fore(i,0,SZ(e)) V.pb({i});
Description: Runs a callback for all maximal cliques in a graph (given as a }
bool solve() { symmetric bitset matrix; self-edges not allowed). Callback is given a bitset };
values.assign(N, -1), val.assign(2*N, 0), comp = val; representing
fore(i, 0, 2*N) if (!comp[i]) dfs(i);  themaximal clique.
fore(i, 0, N) if (comp[2*i] == comp[2*i+1]) return 0; Time: O 3n/3 , much faster for sparse graphs MaximumIndependentSet.h
307f7f, 9 lines Description: To obtain a maximum independent set of a graph, find a max
return 1; typedef bitset<128> B; clique of the complement. If the graph is bipartite, see MinimumVertex-
} void cliques(vector<B>& eds, auto&& f, B P=-1, B X=0, B R=0) { Cover.
}; if (!P.any()) { if (!X.any()) f(R); return; }
ll q = (P | X)._Find_first();
EulerWalk.h B cands = P & ∼eds[q]; 7.7 Trees
Description: Eulerian undirected/directed path/cycle algorithm. Input fore(i,0,SZ(eds)) if (cands[i])
should be a vector of (dest, global edge index), where for undirected graphs, R[i] = 1, cliques(eds, f, P & eds[i], X & eds[i], R), BinaryLifting.h
forward/backward edges have the same index. Returns a list of nodes in R[i] = P[i] = 0, X[i] = 1; Description: Calculate power of two jumps in a tree, to support fast up-
the Eulerian path/cycle with src at both start and end, or empty list if no } ward jumps and LCAs. Assumes the root node points to itself.
cycle/path exists. To get edge indices back, add .snd to s and ret. Time: construction O (N log N ), queries O (log N ) 90fce2, 22 lines
Time: O (V + E) 092ee4, 13 lines MaximumClique.h vector<vi> treeJump(vi& P){
vi eulerWalk(vector<vector<ii>>& gr, ll nedges, ll src=0) { Description: Quickly finds a maximum clique of a graph (given as symmet- ll d = bit_width((unsigned)SZ(P));
ll n = SZ(gr); ric bitset matrix; self-edges not allowed). Can be used to find a maximum vector<vi> jmp(d, P);
vi D(n), its(n), eu(nedges), ret, s = {src}; independent set by finding a clique of the complement graph. fore(i,1,d)fore(j,0,SZ(P)) jmp[i][j] = jmp[i-1][jmp[i-1][j]];
D[src]++; // to allow Euler paths , not j u s t cycles Time: Runs in about 1s for n=155 and worst case random graphs (p=.90). return jmp;
while (!s.empty()) { Runs faster for sparse graphs. 89fbc5, 49 lines
}
ll x = s.back(), &it = its[x], end = SZ(gr[x]);
if (it == end) { ret.pb(x), s.pop_back(); continue; } typedef vector<bitset<200>> vb; ll jmp(vector<vi>& tbl, ll nod, ll steps) {
auto [y, e] = gr[x][it++]; struct Maxclique { fore(i,0,SZ(tbl)) if (steps & (1<<i)) nod = tbl[i][nod];
if (!eu[e]) D[x]--, D[y]++, eu[e] = 1, s.pb(y); double limit=0.025, pk=0; return nod;
} struct Vertex { ll i, d=0; }; }
for (ll x : D) if (x < 0 || SZ(ret) != nedges+1) return {}; typedef vector<Vertex> vv;
return {ret.rbegin(), ret.rend()}; vb e; ll lca(vector<vi>& tbl, vi& depth, ll a, ll b) {
} vv V; if (depth[a] < depth[b]) swap(a, b);
vector<vi> C; a = jmp(tbl, a, depth[a] - depth[b]);
vi qmax, q, S, old;
7.5 Coloring void init(vv& r) {
if (a == b) return a;
for (ll i = SZ(tbl); i--;) {
EdgeColoring.h for (auto& v : r) v.d = 0; ll c = tbl[i][a], d = tbl[i][b];
Description: Given a simple, undirected graph with max degree D, com- for (auto& v : r) for (auto j : r) v.d += e[v.i][j.i]; if (c != d) a = c, b = d;
putes a (D + 1)-coloring of the edges such that no neighboring edges share sort(ALL(r), [](auto a, auto b) { return a.d > b.d; }); }
a color. (D-coloring is NP-hard, but can be done for bipartite graphs by ll mxD = r[0].d; return tbl[0][a];
repeated matchings of max-degree nodes.) fore(i,0,SZ(r)) r[i].d = min(i, mxD) + 1; }
Time: O (N M ) }
6f96a9, 26 lines void expand(vv& R, ll lev = 1) {
vi edgeColoring(ll N, vector<ii> eds) { S[lev] += S[lev - 1] - old[lev]; LCA.h
vi cc(N + 1), ret, fan(N), free(N), loc; old[lev] = S[lev - 1]; Description: Data structure for computing lowest common ancestors in a
for (auto [u, v] : eds) ++cc[u], ++cc[v]; while (SZ(R)) { tree (with 0 as root). C should be an adjacency list of the tree, either di-
ll ncols = *max_element(ALL(cc)) + 1; if (SZ(q) + R.back().d <= SZ(qmax)) return; rected or undirected.
vector<vi> adj(N, vi(ncols, -1)); q.pb(R.back().i); Time: O (N log N + Q)
for (auto [u, v] : eds) { vv T; "../data-structures/RMQ.h" b66e8f, 21 lines

fan[0] = v, loc.assign(ncols, 0); for (auto v : R) if (e[R.back().i][v.i]) T.pb({v.i}); struct LCA {


ll at = u, end = u, d, c = free[u], ind = 0, i = 0; if (SZ(T)) { ll T = 0;
while (d = free[v], !loc[d] && (v = adj[u][d]) != -1) if (S[lev]++ / ++pk < limit) init(T); vi time, path, ret;
loc[d] = ++ind, cc[ind] = d, fan[ind] = v; ll j = 0, mxk = 1, mnk = max(SZ(qmax) - SZ(q) + 1,1ll); RMQ<ll> rmq;
cc[loc[d]] = c; C[1].clear(), C[2].clear();
for (ll cd = d; at != -1; cd ^= c ^ d, at = adj[at][cd]) for (auto v : T) { LCA(vector<vi>& C) : time(SZ(C)), rmq((dfs(C,0,-1), ret)) {}
swap(adj[at][cd], adj[end = at][cd ^ c ^ d]); ll k = 1; void dfs(vector<vi>& C, ll v, ll par) {
UNC TreePathQueries CompressTree HLD Kruskal DirectedMST 2025-04-20 20
time[v] = T++; ans = f(ans, f(part[k][u], part[k][v])); if (pos[u] > pos[v]) swap(u, v);
for (ll y : C[v]) if (y != par) { u = anc[k][u], v = anc[k][v]; if (rt[u] == rt[v]) break;
path.pb(v), ret.pb(time[v]); } op(pos[rt[v]], pos[v] + 1);
dfs(C, y, v); ans = f(ans, f(part[0][u], part[0][v])); }
} return f(ans, part[0][anc[0][u]]); // NODES op(pos[u] + VALS_ED, pos[v] + 1);
} // return ans ; // EDGES }
} void updPath(ll u, ll v, L val) {
ll lca(ll a, ll b) { }; process(u, v, [&](ll l, ll r) { t.upd(l, r, val); });
if (a == b) return a; }
tie(a, b) = minmax(time[a], time[b]); T queryPath(ll u, ll v) {
return path[rmq.query(a, b)];
CompressTree.h T res = tneut;
Description: Given a tree T rooted at 0, and a subset of nodes X returns
} process(u, v, [&](ll l, ll r) {
tree with vertex set {lca(x, y) : x ∈ X, y ∈ X} and edges between every pair
// d i s t (a , b) {return depth [ a ] + depth [ b ] − 2∗depth [ lca (a , b) ] ;} res = f(res, t.query(l, r));
of vertices in which one is an ancestor of the other in T . Size is at most
}; });
2|X| − 1, including X. Returns a list of (par, orig index) representing a tree
return res;
rooted at 0. The root points to itself.
}
TreePathQueries.h Time: O (|X| log |X|)
T querySubtree(ll v) { // updSubtree i s similar
"LCA.h" d8a7c9, 12 lines
Description: Data structure for computing queries on paths in a tree. return t.query(pos[v] + VALS_ED, pos[v] + siz[v]);
Works for nodes having values but can be changed to work with edges having vector<ii> compressTree(LCA& lca, vi X) { }
values. static vi rev; rev.resize(SZ(lca.time)); // void updPoint( l l v , T val ) { // For normal segment tree
Time: construction O (N log N ), queries O (log N ) auto cmp = [&](ll a,ll b){ return lca.time[a]<lca.time[b]; }; // t . upd(pos [ v ] , val ) ; // queryPoint i s similar
aeb7e6, 56 lines
sort(ALL(X), cmp); // }
struct PathQueries { fore(i,0,SZ(X)-1) X.pb(lca.lca(X[i], X[i+1])); };
typedef ll T; sort(ALL(X), cmp), X.erase(unique(ALL(X)), X.end());
constexpr static T neut = LONG_LONG_MIN; fore(i,0,SZ(X)) rev[X[i]] = i;
T f(const T& a, const T& b) { vector<ii> ret = {{{0, X[0]}}}; Kruskal.h
return max(a, b); fore(i,0,SZ(X)-1) Description: Finds MST of weighted graph. Returns only cost by default.
} // (any associative and commutative fn ) ret.pb({rev[lca.lca(X[i], X[i+1])], X[i+1]}); Time: O (m)
return ret; "../data-structures/UnionFind.h" eed941, 13 lines
ll n, K; } ll kruskal(vector<pair<ll, ii>>& es, ll n) {
vector<vi> anc; sort(ALL(es));
vector<vector<T>> part; UF uf(n);
vi depth; HLD.h ll r = 0;
PathQueries(const vector<vi>& g, vector<T>& vals) // NODES Description: Decomposes a tree into vertex disjoint heavy paths and light
for (auto [w, p] : es) {
: n(SZ(g)), K(64 - __builtin_clzll(n)), anc(K, vi(n, -1)), edges such that the path from any leaf to the root contains at most log(n)
auto [u, v] = p;
part(K, vector<T>(n, neut)), depth(n) { light edges. Code does additive modifications and sum queries, but can sup-
if (uf.join(u, v)) {
part[0] = vals; port commutative segtree modifications/queries on paths and subtrees. For
r += w;
//PathQueries( vector<vector<pair<l l , T>>> &g ) // EDGES a non-commutative operation see LinkCutTree. Takes as input the full adja-
// {w, {u, v}} i s in MST
// : n(SZ( g ) ) , K(64 − b u i l t i n c l z l l (n) ) , anc(K, vi (n, −1)) , cency list. VALS ED being true means that values are stored in the edges,
}
// part (K, vector<T>(n, neut) ) , depth(n) { as opposed to the nodes, and updates have to be done on child nodes. All
}
// vector<vi> g(n) ; values initialized to the segtree default. Root must be 0. If you only have
return r;
// fore (u, 0 , n) for (auto [ v , data ] : g [ u] ) { point updates you can use normal segment tree instead of lazy. }
// g [ u ] . pb(v) ; Time: O (log N )2
// } "../data-structures/LazySegmentTree.h" 50a556, 49 lines

vi s = {0}; template <bool VALS_ED> struct HLD { DirectedMST.h


while (!s.empty()) { ll N, tim = 0; Description: Finds a minimum spanning tree/arborescence of a directed
ll u = s.back(); vector<vi> adj; graph, given a root node. If no MST exists, returns -1.
s.pop_back(); vi par, siz, rt, pos; Time: O (E log V )
for (ll v : g[u]) if (v != anc[0][u]) { Tree t; "../data-structures/UnionFindRollback.h" 6825cd, 60 lines

anc[0][v] = u, depth[v] = depth[u] + 1, s.pb(v); HLD(vector<vi> adj_) struct Edge { ll a, b; ll w; };


} : N(SZ(adj_)), adj(adj_), par(N, -1), siz(N, 1), struct Node {
} rt(N), pos(N), t(N) { dfsSz(0), dfsHld(0); } Edge key;
// fore (u, 0 , n) for (auto [ v , data ] : g [ u] ) { // EDGES void dfsSz(ll v) { Node *l, *r;
// part [ 0 ] [ depth [u] > depth [ v ] ? u : v ] = data ; for (ll& u : adj[v]) { ll delta;
// } adj[u].erase(find(ALL(adj[u]), v)); void prop() {
fore(k, 0, K - 1) fore(v, 0, n) { par[u] = v; key.w += delta;
if (anc[k][v] != -1) { dfsSz(u); if (l) l->delta += delta;
anc[k + 1][v] = anc[k][anc[k][v]]; siz[v] += siz[u]; if (r) r->delta += delta;
part[k + 1][v] = f(part[k][v], part[k][anc[k][v]]); if (siz[u] > siz[adj[v][0]]) swap(u, adj[v][0]); delta = 0;
} } }
} } Edge top() { prop(); return key; }
} void dfsHld(ll v) { };
T query(ll u, ll v) { pos[v] = tim++; Node *merge(Node *a, Node *b) {
if (depth[u] < depth[v]) swap(u, v); for (ll u : adj[v]) { if (!a || !b) return a ?: b;
T ans = neut; rt[u] = (u == adj[v][0] ? rt[v] : u); a->prop(), b->prop();
fore(k, 0, K) if ((depth[u] - depth[v]) & (1 << k)) dfsHld(u); if (a->key.w > b->key.w) swap(a, b);
ans = f(ans, part[k][u]), u = anc[k][u]; } swap(a->l, (a->r = merge(b, a->r)));
if (u == v) return f(ans, part[0][u]); // NODES } return a;
// i f (u == v) return ans ; // EDGES void process(ll u, ll v, auto op) { }
for (ll k = K; k--;) if (anc[k][u] != anc[k][v]) { for (;; v = par[rt[v]]) { void pop(Node*& a) { a->prop(); a = merge(a->l, a->r); }
UNC CentroidTree LinkCutTree LinkCutTree-PathUpdates 2025-04-20 21
LinkCutTree.h rotate(x);
pair<ll, vi> dmst(ll n, ll r, vector<Edge>& g) { Description: Represents a forest of rooted trees with nodes indexed from }
RollbackUF uf(n); one. You can add and remove edges (as long as the result is still a forest), }
vector<Node*> heap(n); make path queries, subtree queries, point updates and select a node as root };
for (Edge e : g) heap[e.b] = merge(heap[e.b], new Node{e}); of its subtree. If you don’t have subtree queries you can remove the parts
ll res = 0; that say SUBTREE. struct LinkCutTree : SplayTree {
vi seen(n, -1), path(n), par(n); Time: All operations take amortized O (log N ). f82ea6, 123 lines
LinkCutTree(ll n) : SplayTree(n) {}
seen[r] = r; ll access(ll x) {
vector<Edge> Q(n), in(n, {-1,-1}), comp; typedef ll T; ll u = x, v = 0;
deque<tuple<ll, ll, vector<Edge>>> cycs; const T neut = 0; for (; u; v = u, u = nods[u].p) {
fore(s,0,n) { T f(T a, T b) { return a + b; } // associative spa(u);
ll u = s, qi = 0, w; T neg(T a, T b) { return a - b; } // inverse of f for SUBTREE ll& ov = nods[u].c[1];
while (seen[u] < 0) { struct SplayTree { nods[u].vir = f(nods[u].vir, nods[ov].sub);
if (!heap[u]) return {-1,{}}; struct Node { nods[u].vir = neg(nods[u].vir, nods[v].sub); // SUBTREE
Edge e = heap[u]->top(); array<ll, 2> c = {0, 0}; ov = v; pushUp(u);
heap[u]->delta -= e.w, pop(heap[u]); ll p = 0; }
Q[qi] = e, path[qi++] = u, seen[u] = s; array<T, 2> path = {neut, neut}; return spa(x), v;
res += e.w, u = uf.find(e.a); T self = neut, sub = neut, vir = neut; }
if (seen[u] == s) { bool reverse = false;
Node* cyc = 0; }; void mkR(ll u) { // make root of i t s tree
ll end = qi, time = uf.time(); vector<Node> nods; access(u);
do cyc = merge(cyc, heap[w = path[--qi]]); nods[u].reverse ^= 1;
while (uf.join(u, w)); SplayTree(ll n) : nods(n + 1) {} pushDown(u);
u = uf.find(u), heap[u] = cyc, seen[u] = -1; }
cycs.push_front({u, time, {&Q[qi], &Q[end]}}); ll getDir(ll x) { ll lca(ll u, ll v) { // l e a s t common ancestor , 0 i f not conn
} ll p = nods[x].p; if (u == v) return u;
} if (!p) return -1; access(u);
fore(i,0,qi) in[uf.find(Q[i].b)] = Q[i]; if (nods[p].c[0] == x) return 0; ll ret = access(v);
} return nods[p].c[1] == x ? 1 : -1; return nods[u].p ? ret : 0;
} }
for (auto& [u,t,comp] : cycs) { // restore s o l ( optional ) void pushDown(ll x) { bool connected(ll u, ll v) { // are u and v in the same tree
uf.rollback(t); if (!x) return; return lca(u, v) > 0;
Edge inEdge = in[u]; if (nods[x].reverse) { }
for (auto& e : comp) in[uf.find(e.b)] = e; auto [l, r] = nods[x].c; T query(ll u) { // query single element
in[uf.find(inEdge.b)] = inEdge; nods[l].reverse ^= 1, nods[r].reverse ^= 1; return nods[u].self;
} swap(nods[x].c[0], nods[x].c[1]); }
fore(i,0,n) par[i] = in[i].a; swap(nods[x].path[0], nods[x].path[1]); T querySub(ll u) { // query SUBTREE of u
return {res, par}; nods[x].reverse = false; access(u);
} } return f(nods[u].vir, nods[u].self);
} }
void pushUp(ll x) { void upd(ll u, T val) { // update value of u
CentroidTree.h auto [l, r] = nods[x].c; access(u);
Description: Calculate the centroid tree of a tree. Returns vector of fathers pushDown(l), pushDown(r);
(-1 for root). nods[u].self = val;
nods[x].path[0] = pushUp(u);
Time: O (N ) f96917, 24 lines f(f(nods[l].path[0], nods[x].self), nods[r].path[0]); }
vi centroidTree(vector<vi>& g) { nods[x].path[1] = // The following functions change the root
ll n = SZ(g); f(f(nods[r].path[1], nods[x].self), nods[l].path[1]); void link(ll u, ll v) { // add edge between u and v
vector<bool> vis(n, false); nods[x].sub = f( mkR(u), access(v);
vi fat(n), szt(n); f(f(nods[x].vir, nods[l].sub), nods[r].sub), nods[v].vir = f(nods[v].vir, nods[u].sub);
function<ll(ll, ll)> calcsz = [&](ll x, ll f) { nods[x].self); nods[u].p = v;
szt[x] = 1; } pushUp(v);
for (ll y : g[x]) if (y != f && !vis[y]) void setChild(ll x, ll y, ll dir) { }
szt[x] += calcsz(y, x); nods[x].c[dir] = y; void cut(ll u, ll v) { // remove edge u v
return szt[x]; nods[y].p = x; mkR(u), access(v);
}; pushUp(x); nods[v].c[0] = nods[u].p = 0;
function<void(ll, ll, ll)> dfs = [&](ll x, ll f, ll sz) { } pushUp(v);
if (sz < 0) sz = calcsz(x, -1); void rotate(ll x) { }
for (ll y : g[x]) if (!vis[y] && szt[y] * 2 >= sz) { ll y = nods[x].p, dx = getDir(x); T queryPath(ll u, ll v) { // query on path from u to v
szt[x] = 0; ll z = nods[y].p, dy = getDir(y); mkR(u), access(v);
dfs(y, f, sz); setChild(y, nods[x].c[!dx], dx), setChild(x, y, !dx); return nods[v].path[1];
return; if (∼dy) setChild(z, x, dy); }
} nods[x].p = z; };
vis[x] = true; }
fat[x] = f; void spa(ll x) { // splay
for (ll y : g[x]) if (!vis[y]) dfs(y, x, -1); for (pushDown(x); ∼getDir(x); ) { LinkCutTree-PathUpdates.h
}; ll y = nods[x].p, z = nods[y].p; Description: Represents a forest of rooted trees with nodes indexed from
dfs(0, -1, -1); pushDown(z), pushDown(y), pushDown(x); one. You can add and remove edges (as long as the result is still a forest),
return fat; ll dx = getDir(x), dy = getDir(y); make path queries and path updates and select a node as root of its subtree.
} if (∼dy) rotate(dx != dy ? x : y); Time: All operations take amortized O (log N ). e79eae, 133 lines
UNC Reroot RerootInv 2025-04-20 22
struct LinkCutTree { ll lift_rec(ll u, ll t) { finalize is applied before returning answer for p if g[p][ei] was its parent;
typedef ll T; typedef ll L; // T: data type , L: lazy type if (!u) return 0; usually identity function. When p is the root, ei is -1.
static constexpr T tneut = 0; static constexpr L lneut = 0; Node N = nods[u]; Let accumulated(p, S) = a such that finalize(a, ...) is the answer for
T f(T a, T b) { return a + b; } // associative & commutative ll s = nods[N.c[0]].s; p if S were its only children. acc should, given accumulated(p, S) and the
T apply(T v, L l, ll len) { // new s t according to lazy if (t == s) return spa(u), u; answer for g[p][ei], compute accumulated(p, S ∪ {g[p][ei]}) in p ans.
return v + l * len; } if (t < s) return lift_rec(N.c[0], t); neuts[p] should be accumulated(p, ∅).
L comb(L a, L b) { return a + b; }//cumulative e f f e c t of lazy return lift_rec(N.c[1], t - s - 1); root dp[v] is the answer for the whole tree with v as root, fdp[v][ei] is
} the answer for g[v][ei] if v is the root and bdp[v][ei] is the answer for v
struct Node { ll exv(ll u) { // expose if g[v][ei] is the root.
ll s = 1; bool rev = 0; ll last = 0; Equivalent to the following code, but for all roots:
T val, t; L d = lneut; for (ll v = u; v; v = nods[v].p) Data dfs(ll u, ll p) {
array<ll, 2> c = {0, 0}; ll p = 0; spa(v), nods[v].c[0] = last, calc(v), last = v; Data res = neuts[u];
Node(T v = tneut) : val(v), t(v) {} spa(u); fore(ei, 0, SZ(g[u])) if (g[u][ei] != p)
}; return last; acc(res, dfs(g[u][ei], u), u, ei);
vector<Node> nods; } ll pid = p == -1 ? -1 : find(ALL(g[u]), p) - begin(g[u]);
LinkCutTree(ll n) : nods(n + 1) { return dp[u] = finalize(res, u, pid);
nods[0].s = 0; void mkR(ll u) { // make root of i t s tree }
} exv(u), nods[u].rev ^= 1; Time: Fast O (n log n) assuming O (1) operations. af6687, 47 lines
LinkCutTree(vector<T>& a) : nods(SZ(a) + 1) { }
fore(i, 0, SZ(a)) nods[i + 1] = Node(a[i]); ll getR(ll u) { // get root of u tree struct Data {};
nods[0].s = 0; exv(u); typedef vector<Data> vd;
} while (nods[u].c[1]) u = nods[u].c[1];
bool isRoot(ll u) { spa(u); struct Reroot {
Node N = nods[nods[u].p]; return u; ll n; vector<vi>& g; vd& neuts;
return N.c[0] != u && N.c[1] != u; }
} ll father(ll u) { // father of u, 0 i f u i s root Data finalize(const Data& a, ll p, ll ei) {
void push(ll u) { exv(u), u = nods[u].c[1]; return a;
Node& N = nods[u]; while (nods[u].c[0]) u = nods[u].c[0]; }
if (N.rev) { return u; void acc(Data& p_ans, const Data& child_ans, ll p, ll ei) {
N.rev = 0, swap(N.c[0], N.c[1]); } p_ans = Data{};
fore(x, 0, 2) if (N.c[x]) nods[N.c[x]].rev ^= 1; ll lift(ll u, ll t) {//t ancestor of x , l i f t (x ,1) i s x father }
} exv(u);
N.val = apply(N.val, N.d, 1); return lift_rec(u, t); vd root_dp; vector<vd> fdp, bdp;
N.t = apply(N.t, N.d, N.s); } Reroot(vector<vi>& g, vd& neuts) : n(SZ(g)), g(g),
fore(x, 0, 2) if (N.c[x]) ll depth(ll u) { // distance from u to i t s tree root neuts(neuts), root_dp(n), fdp(n), bdp(n) {}
nods[N.c[x]].d = comb(nods[N.c[x]].d, N.d); exv(u); void reroot() {
N.d = lneut; return nods[u].s - 1; if (n==1) { root_dp[0]=finalize(neuts[0], 0, -1); return; }
} } vd dp = neuts, e(n); vi o = {0}, p(n); o.reserve(n);
T get(ll u) { ll lca(ll u, ll v) { // l e a s t common ancestor , 0 i f not conn fore(i, 0, n) for (ll v : g[o[i]]) if (v != p[o[i]])
return apply(nods[u].t, nods[u].d, nods[u].s); exv(u); p[v] = o[i], o.pb(v);
} return exv(v); for (ll u : views::reverse(o)) {
void calc(ll u) { } ll pei = -1;
Node& N = nods[u]; bool connected(ll u, ll v) { // are u and v in the same tree fore(ei, 0, SZ(g[u]))
N.t = f(f(get(N.c[0]), apply(N.val, N.d, 1)), get(N.c[1])); exv(u), exv(v); if (g[u][ei] == p[u]) pei = ei;
N.s = 1 + nods[N.c[0]].s + nods[N.c[1]].s; return u == v || nods[u].p != 0; else acc(dp[u], dp[g[u][ei]], u, ei);
} } dp[u] = finalize(dp[u], u, pei);
void conn(ll c, ll p, ll il) { void cut(ll u) { // cuts u from father , becoming a root }
if (c) nods[c].p = p; exv(father(u)), nods[u].p = 0; for (ll u : o) {
if (il >= 0) nods[p].c[!il] = c; } dp[p[u]] = dp[u];
} // The following functions change the root fdp[u].reserve(SZ(g[u])), bdp[u].reserve(SZ(g[u]));
void rotate(ll u) { void link(ll u, ll v) { // add edge between u and v for (ll v : g[u]) fdp[u].pb(dp[v]);
ll p = nods[u].p, g = nods[p].p; mkR(u), nods[u].p = v; ex(e, fdp[u], neuts[u], u);
bool gCh = isRoot(p), isl = u == nods[p].c[0]; } fore(i, 0, SZ(fdp[u])) bdp[u].pb(finalize(e[i], u, i));
conn(nods[u].c[isl], p, isl); void cut(ll u, ll v) { // remove edge u v acc(e[0], fdp[u][0], u, 0);
conn(p, u, !isl); mkR(u), cut(v); root_dp[u] = finalize(n > 1 ? e[0] : neuts[u], u, -1);
conn(u, g, gCh ? -1 : (p == nods[g].c[0])); } fore(i, 0, SZ(g[u])) dp[g[u][i]] = bdp[u][i];
calc(p); T query(ll u, ll v) { // query on path from u to v }
} mkR(u), exv(v); }
void spa(ll u) { // splay return get(v); void ex(vd& e, vd& a, Data& ne, ll v) {
while (!isRoot(u)) { } ll d = SZ(a); fill(begin(e), begin(e) + d, ne);
ll p = nods[u].p, g = nods[p].p; void upd(ll u, ll v, L d) { // modify path from u to v for (ll b = bit_width((unsigned)d); b--;) {
if (!isRoot(p)) push(g); mkR(u), exv(v), nods[v].d = comb(nods[v].d, d); for (ll i = d; i--;) e[i] = e[i >> 1];
push(p), push(u); } fore(i, 0, d - (d & !b)) acc(e[(i >> b)^1], a[i], v, i);
if (!isRoot(p)) }; }
rotate((u==nods[p].c[0]) ^ (p==nods[g].c[0]) ? u : p); }
rotate(u); };
} Reroot.h
push(u), calc(u); Description: define Data, finalize, acc (as explained below), adding
} any necessary fields to Reroot. Then instantiate, add the data, and call
reroot().
UNC RerootLinear Point lineDistance SegmentDistance SegmentIntersection lineIntersection 2025-04-20 23
RerootInv.h Tutte’s: A graph (V, E) has a perfect matching iff for all U ⊆ V , lineDistance.h res
Description: Make rerooting linear by defining the inverse of acc. Add the subgraph induced by V \ U has at most |U | components with Description: e p
unacc to the struct, keep acc and finalize, and change ex. Don’t use in- Returns the signed distance between point p and the line con-
heritance. an odd number of vertices. taining points a and b. Positive value on left side and negative
unacc should, given accumulated(p, g[p]) and the answer for g[p][ei], com- on right as seen from a towards b. a==b gives nan. P is sup- s
pute accumulated(p, g[p] \ {g[p][ei]}) in ans. posed to be Point<T> or Point3D<T> where T is e.g. double or ll. It uses
Time: Fast O (n) Petersens: Every cubic, bridgeless graph contains a perfect products in intermediate steps so watch out for overflow if using int or ll.
"Reroot.h" f16d08, 11 lines matching. Using Point3D will always give a non-negative distance. For Point3D, call
struct RerootInv : Reroot { .dist on the result of the cross product.
void unacc(Data& ans, const Data& child_ans, ll p, ll ei) { "Point.h" f6bf6b, 4 lines

ans = Data{}; Dilworth’s: In a finite poset, the maximum size of an antichain template<class P>
} equals the minimum number of chains needed to partition the double lineDist(const P& a, const P& b, const P& p) {
void ex(vd& e, vd& a, Data& ne, ll v) { return (double)(b-a).cross(p-a)/(b-a).dist();
ll d = SZ(a); Data b = ne; poset. }
fore(i, 0, d) acc(b, a[i], v, i);
fill(begin(e), begin(e) + d, b);
König’s: In a bipartite graph, the number of edges in a SegmentDistance.h
e res p
fore(i, 0, d) unacc(e[i], a[i], v, i);
} maximum matching equals the number of vertices in a minimum Description:
}; Returns the shortest distance between point p and the line
vertex cover. segment from point s to e.
Usage: Point<double> a, b(2,2), p(1,1); s
RerootLinear.h bool onSegment = segDist(a,b,p) < 1e-10;
Description: Use two operations instead of one to make rerooting linear. Hall’s: A bipartite graph (X, Y, E) has an X-saturating "Point.h" 5c88f4, 6 lines
Usually only worth it for non- O(1) operations. Add merge and extend, and matching iff for all W ⊆ X, |N (W )| ≥ |W |, i.e. it has as many
change acc and exclusive. Don’t use inheritance. typedef Point<double> P;
merge should, given accumulated(p, S) and accumulated(p, T ), with S and neighbors as elements. double segDist(P& s, P& e, P& p) {
T disjoint, return accumulated(p, S ∪ T ). if (s==e) return (p-s).dist();
extend should, given the answer for g[p][ei], return b such that auto d = (e-s).dist2(), t = min(d,max(.0,(p-s).dot(e-s)));
merge(neuts[p], b, p) = accumulated(p, {g[p][ei]}). return ((p-s)*d-(e-s)*t).dist()/d;
Time: Slow O (n) Geometry (8) }
"Reroot.h" 4cb523, 17 lines

struct RerootLinear : Reroot {


8.1 Geometric primitives SegmentIntersection.h e1
Data merge(const Data& a, const Data& b, ll p) {
return Data{};
Description: e2
}
Point.h If a unique intersection point between the line segments going r1
Data extend(const Data& a, ll p, ll ei) {
Description: Class to handle points in the plane. T can be e.g. double or from s1 to e1 and from s2 to e2 exists then it is returned. If s1 s2
long long. (Avoid int.) b838b5, 28 lines no intersection point exists an empty vector is returned. If
return Data{};
infinitely many exist a vector with 2 elements is returned, containing the
} template <class T> ll sgn(T x) { return (x > 0) - (x < 0); }
endpoints of the common line segment. The wrong position will be returned
void acc(Data& p_ans, const Data& child_ans, ll p, ll ei) { template<class T>
if P is Point<ll> and the intersection point does not have integer coordi-
p_ans = merge(p_ans, extend(child_ans, p, ei), p); struct Point {
nates. Products of three coordinates are used in intermediate steps so watch
} typedef Point P;
out for overflow if using int or ll.
void ex(vd& e, vd& a, Data& ne, ll v) { T x, y;
Usage: vector<P> inter = segInter(s1,e1,s2,e2);
ll d = SZ(a); vd p(d + 1, ne), s(d + 1, ne); explicit Point(T x=0, T y=0) : x(x), y(y) {}
if (SZ(inter)==1)
fore(i,0,d) p[i+1] = merge(p[i], a[i]=extend(a[i],v,i), v); bool operator<(P p) const { return tie(x,y) < tie(p.x,p.y); }
cout << "segments intersect at " << inter[0] << endl;
for (ll i = d; i--;) s[i] = merge(a[i], s[i + 1], v); bool operator==(P p) const { return tie(x,y)==tie(p.x,p.y); }
"Point.h", "OnSegment.h" 36c2d7, 13 lines
fore(i, 0, d) e[i] = merge(p[i], s[i + 1], v); P operator+(P p) const { return P(x+p.x, y+p.y); }
} P operator-(P p) const { return P(x-p.x, y-p.y); } template<class P> vector<P> segInter(P a, P b, P c, P d) {
}; P operator*(T d) const { return P(x*d, y*d); } auto oa = c.cross(d, a), ob = c.cross(d, b),
P operator/(T d) const { return P(x/d, y/d); } oc = a.cross(b, c), od = a.cross(b, d);
// Checks i f intersection i s single non−endpoint point .
7.8 Math T dot(P p) const { return x*p.x + y*p.y; }
T cross(P p) const { return x*p.y - y*p.x; } if (sgn(oa) * sgn(ob) < 0 && sgn(oc) * sgn(od) < 0)
7.8.1 Number of Spanning Trees T cross(P a, P b) const { return (a-*this).cross(b-*this); } return {(a * ob - b * oa) / (ob - oa)};
T dist2() const { return x*x + y*y; } set<P> s;
Create an N × N matrix mat, and for each edge a → b ∈ G, do double dist() const { return sqrt((double)dist2()); } if (onSegment(c, d, a)) s.insert(a);
mat[a][b]--, mat[b][b]++ (and mat[b][a]--, // angle to x−axis in interval [−pi , pi ] if (onSegment(c, d, b)) s.insert(b);
double angle() const { return atan2(y, x); } if (onSegment(a, b, c)) s.insert(c);
mat[a][a]++ if G is undirected). Remove the ith row and if (onSegment(a, b, d)) s.insert(d);
P unit() const { return *this/dist(); } // makes d i s t ()=1
column and take the determinant; this yields the number of P perp() const { return P(-y, x); } // rotates +90 degrees return {ALL(s)};
directed spanning trees rooted at i (if G is undirected, remove P normal() const { return perp().unit(); } }
// returns point rotated ’a ’ radians ccw around the origin
any row/column). P rotate(double a) const {
lineIntersection.h
7.8.2 Theorems return P(x*cos(a)-y*sin(a),x*sin(a)+y*cos(a)); }
Description: e2 r
friend ostream& operator<<(ostream& os, P p) {
Erdős-Gallai: A simple graph with node degrees d1 ≥ · · · ≥ dn return os << "(" << p.x << "," << p.y << ")"; } If a unique intersection point of the lines going through s1,e1 e1 s2
and s2,e2 exists {1, point} is returned. If no intersection point
exists iff d1 + · · · + dn is even and for every k = 1 . . . n, };
exists {0, (0,0)} is returned and if infinitely many exists {-1,
s1
(0,0)} is returned. The wrong position will be returned if P is Point<ll> and
k n
X X the intersection point does not have integer coordinates. Products of three
di ≤ k(k − 1) + min(di , k). coordinates are used in intermediate steps so watch out for overflow if using
i=1 i=k+1 int or ll.
UNC sideOf OnSegment HalfplaneIntersection linearTransformation LineProjectionReflection Angle CircleIntersection CircleTangents CircleLine
2025-04-20 24
Usage: auto res = lineInter(s1,e1,s2,e2); if (q < h && abs(PQ(c[h]).cross(PQ(c[h-1]))) < eps) { // them, i . e . , the angle that covers the defined l i n e segment .
if (res.fst == 1) if (PQ(c[h]).dot(PQ(c[h-1])) <= 0) return {}; pair<Angle, Angle> segmentAngles(Angle a, Angle b) {
cout << "intersection point at " << res.snd << endl; if (sideOf(L(v[i]), c[--h].p, eps) < 0) c[h] = v[i]; if (b < a) swap(a, b);
"Point.h" 6a9e96, 8 lines } return (b < a.t180() ?
template<class P> } make_pair(a, b) : make_pair(b, a.t360()));
pair<ll, P> lineInter(P s1, P e1, P s2, P e2) { while (q < h - 1 && sideOf(L(c[q]), I(h, h-1), eps) < 0) h--; }
auto d = (e1 - s1).cross(e2 - s2); while (q < h - 1 && sideOf(L(c[h]), I(q, q+1), eps) < 0) q++; Angle operator+(Angle a, Angle b) { // point a + vector b
if (d == 0) // i f p a r a l l e l if (h - q <= 1) return {}; Angle r(a.x + b.x, a.y + b.y, a.t);
return {-(s1.cross(e1, s2) == 0), P(0, 0)}; c[++h] = c[q]; if (a.t180() < r) r.t--;
auto p = s2.cross(e1, e2), q = s2.cross(e2, s1); vector<P> s; return r.t180() < a ? r.t360() : r;
return {1, (s1 * p + e1 * q) / d}; fore(i, q, h) s.pb(I(i, i+1)); }
} return s; Angle angleDiff(Angle a, Angle b) { // angle b − angle a
} ll tu = b.t - a.t; a.t = b.t;
return {a.x*b.x + a.y*b.y, a.x*b.y - a.y*b.x, tu - (b < a)};
sideOf.h r p1 }
Description: Returns where p is as seen from s towards e. 1/0/-1 ⇔ left/on linearTransformation.h
line/right. If the optional argument eps is given 0 is returned if p is within Description:
Apply the linear transformation (translation, rotation and p0 res 8.2 Circles
distance eps from the line. P is supposed to be Point<T> where T is e.g.
double or ll. It uses products in intermediate steps so watch out for overflow scaling) which takes line p0-p1 to line q0-q1 to point r. q0 CircleIntersection.h
"Point.h" q1
03a306, 6 lines
if using int or ll. Description: Computes the pair of points at which two circles intersect.
Usage: bool left = sideOf(p1,p2,q)==1; typedef Point<double> P; Returns false in case of no intersection.
"Point.h" 89ff34, 9 lines P linearTransformation(const P& p0, const P& p1, "Point.h" 84d6d3, 11 lines
template<class P> const P& q0, const P& q1, const P& r) {
typedef Point<double> P;
ll sideOf(P s, P e, P p) { return sgn(s.cross(e, p)); } P dp = p1-p0, dq = q1-q0, num(dp.cross(dq), dp.dot(dq));
bool circleInter(P a,P b,double r1,double r2,pair<P, P>* out) {
return q0 + P((r-p0).cross(num), (r-p0).dot(num))/dp.dist2();
if (a == b) { assert(r1 != r2); return false; }
template<class P> }
P vec = b - a;
ll sideOf(const P& s, const P& e, const P& p, double eps) { double d2 = vec.dist2(), sum = r1+r2, dif = r1-r2,
auto a = (e-s).cross(p-s); LineProjectionReflection.h p = (d2 + r1*r1 - r2*r2)/(d2*2), h2 = r1*r1 - p*p*d2;
double l = (e-s).dist()*eps; Description: Projects point p onto line ab. Set refl=true to get reflection if (sum*sum < d2 || dif*dif > d2) return false;
return (a > l) - (a < -l); of point p across line ab instead. The wrong point will be returned if P P mid = a + vec*p, per = vec.perp() * sqrt(fmax(0, h2) / d2);
} is an integer point and the desired point doesn’t have integer coordinates. *out = {mid + per, mid - per};
Products of three coordinates are used in intermediate steps so watch out for return true;
OnSegment.h overflow. }
"Point.h" b5562d, 5 lines
Description: Returns true iff p lies on the line segment from s to e. Use
(segDist(s,e,p)<=epsilon) instead when using Point<double>. template<class P> CircleTangents.h
"Point.h" c597e8, 3 lines P lineProj(P a, P b, P p, bool refl=false) { Description: Finds the external tangents of two circles, or internal if r2 is
template<class P> bool onSegment(P s, P e, P p) { P v = b - a; negated. Can return 0, 1, or 2 tangents – 0 if one circle contains the other
return p.cross(s, e) == 0 && (s - p).dot(e - p) <= 0; return p - v.perp()*(1+refl)*v.cross(p-a)/v.dist2(); (or overlaps it, in the internal case, or if the circles are the same); 1 if the
} } circles are tangent to each other (in which case .fst = .snd and the tangent
line is perpendicular to the line between the centers). .fst and .snd give the
Angle.h tangency points at circle 1 and 2 respectively. To find the tangents of a circle
HalfplaneIntersection.h with a point set r2 to 0.
Description: Computes the intersection of a set of half-planes. Input is Description: A class for ordering angles (as represented by ll points and
a number of rotations around the origin). Useful for rotational sweeping. "Point.h" 31cca4, 13 lines
given as a set of planes, facing left. The intersection must form a convex
polygon or be empty. Output is the convex polygon representing the inter- Sometimes also represents points or vectors. template<class P>
section in CCW order. The points may have duplicates and be collinear. Usage: vector<Angle> v = {w[0], w[0].t360() ...}; // sorted vector<pair<P, P>> tangents(P c1, double r1, P c2, double r2) {
Time: O (n log n) ll j = 0; fore(i,0,n) { while (v[j] < v[i].t180()) ++j; } P d = c2 - c1;
"Point.h", "sideOf.h", "lineIntersection.h" e5a703, 34 lines
// sweeps j such that (j-i) represents the number of positively double dr = r1 - r2, d2 = d.dist2(), h2 = d2 - dr * dr;
oriented triangles with vertices at 0 and i c0c63f, 35 lines
if (d2 == 0 || h2 < 0) return {};
typedef Point<double> P; vector<pair<P, P>> out;
struct Line { struct Angle { for (double sign : {-1, 1}) {
P p, q; ll x, y; P v = (d * dr + d.perp() * sqrt(h2) * sign) / d2;
double a; ll t; out.pb({c1 + v * r1, c2 + v * r2});
Line() {} Angle(ll x, ll y, ll t=0) : x(x), y(y), t(t) {} }
Line(P p, P q) : p(p), q(q), a((q - p).angle()) {} Angle operator-(Angle b) const { return {x-b.x, y-b.y, t}; } if (h2 == 0) out.pop_back();
bool operator<(Line o) const { return a < o.a; } ll half() const { return out;
}; assert(x || y); }
#define L(a) a.p, a.q return y < 0 || (y == 0 && x < 0);
#define PQ(a) (a.q - a.p) }
Angle t90() const { return {-y, x, t + (half() && x >= 0)}; } CircleLine.h
vector<P> halfPlaneIntersection(vector<Line> v) { Angle t180() const { return {-x, -y, t + half()}; } Description: Finds the intersection between a circle and a line. Re-
sort(ALL(v)); Angle t360() const { return {x, y, t + 1}; } turns a vector of either 0, 1, or 2 intersection points. P is intended to be
ll n = SZ(v), q = 1, h = 0; }; Point<double>.
const double eps = 1e-9; bool operator<(Angle a, Angle b) { "Point.h" e0cfba, 9 lines
vector<Line> c(n+2); // add a . dist2 () and b . dist2 () to also compare distances template<class P>
#define I(j, k) lineInter(L(c[j]), L(c[k])).snd return make_tuple(a.t, a.half(), a.y * (ll)b.x) < vector<P> circleLine(P c, double r, P a, P b) {
fore(i, 0, n) { make_tuple(b.t, b.half(), a.x * (ll)b.y); P ab = b - a, p = a + ab * (c-a).dot(ab) / ab.dist2();
while (q < h && sideOf(L(v[i]), I(h, h-1), eps) < 0) h--; } double s = a.cross(b, c), h2 = r*r - s*s / ab.dist2();
while (q < h && sideOf(L(v[i]), I(q, q+1), eps) < 0) q++; if (h2 < 0) return {};
c[++h] = v[i]; // Given two points , t h i s calculates the smallest angle between if (h2 == 0) return {p};
UNC 2025-04-20 25
CirclePolygonIntersection circumcircle MinimumEnclosingCircle InsidePolygon PolygonArea PolygonCenter PolygonCut PolygonUnion ConvexHull HullDiameter

P h = ab.unit() * sqrt(h2); 8.3 Polygons PolygonUnion.h


return {p - h, p + h}; Description: Calculates the area of the union of n polygons (not necessar-
}
InsidePolygon.h ily convex). The points within each polygon must be given in CCW order.
Description: Returns true if p lies within the polygon. If strict is true, it
(Epsilon checks may optionally be added to sideOf/sgn, but shouldn’t be
returns false for points on the boundary. The algorithm uses products in
CirclePolygonIntersection.h needed.)
intermediate steps so watch out for overflow.
Time: O N 2 , where N is the total number of points

Description: Returns the area of the intersection of a circle with a ccw Usage: vector<P> v = {P{4,4}, P{1,2}, P{2,1}};
"Point.h", "sideOf.h" de5582, 33 lines
polygon. bool in = inPolygon(v, P{3, 3}, false);
Time: O (n) Time: O (n) typedef Point<double> P;
"../../content/geometry/Point.h" c92d2b, 19 lines "Point.h", "OnSegment.h", "SegmentDistance.h" 3ab66b, 11 lines double rat(P a, P b) { return sgn(b.x) ? a.x/b.x : a.y/b.y; }
typedef Point<double> P; double polyUnion(vector<vector<P>>& poly) {
template<class P>
#define arg(p, q) atan2(p.cross(q), p.dot(q)) double ret = 0;
bool inPolygon(vector<P> &p, P a, bool strict = true) {
double circlePoly(P c, double r, vector<P> ps) { fore(i,0,SZ(poly)) fore(v,0,SZ(poly[i])) {
ll cnt = 0, n = SZ(p);
auto tri = [&](P p, P q) { P A = poly[i][v], B = poly[i][(v + 1) % SZ(poly[i])];
fore(i,0,n) {
auto r2 = r * r / 2; vector<pair<double, ll>> segs = {{0, 0}, {1, 0}};
P q = p[(i + 1) % n];
P d = q - p; fore(j,0,SZ(poly)) if (i != j) {
if (onSegment(p[i], q, a)) return !strict;
auto a = d.dot(p)/d.dist2(), b = (p.dist2()-r*r)/d.dist2(); fore(u,0,SZ(poly[j])) {
//or : i f ( segDist (p [ i ] , q , a) <= eps) return ! s t r i c t ;
auto det = a * a - b; P C = poly[j][u], D = poly[j][(u + 1) % SZ(poly[j])];
cnt ^= ((a.y<p[i].y) - (a.y<q.y)) * a.cross(p[i], q) > 0;
if (det <= 0) return arg(p, q) * r2; ll sc = sideOf(A, B, C), sd = sideOf(A, B, D);
}
auto s = max(0., -a-sqrt(det)), t = min(1., -a+sqrt(det)); if (sc != sd) {
return cnt;
if (t < 0 || 1 <= s) return arg(p, q) * r2; double sa = C.cross(D, A), sb = C.cross(D, B);
}
P u = p + d * s, v = q + d * (t-1); if (min(sc, sd) < 0)
return arg(p,u) * r2 + u.cross(v)/2 + arg(v,q) * r2; segs.pb({sa / (sa - sb), sgn(sc - sd)});
}; PolygonArea.h } else if (!sc && !sd && j<i && sgn((B-A).dot(D-C))>0){
auto sum = 0.0; Description: Returns twice the signed area of a polygon. Clockwise enu- segs.pb({rat(C - A, B - A), 1});
fore(i,0,SZ(ps)) meration gives negative area. Watch out for overflow if using int as T! segs.pb({rat(D - A, B - A), -1});
sum += tri(ps[i] - c, ps[(i + 1) % SZ(ps)] - c); "Point.h" b649a8, 6 lines
}
return sum; }
template<class T> }
} T polygonArea2(vector<Point<T>>& v) { sort(ALL(segs));
T a = v.back().cross(v[0]); for (auto& s : segs) s.fst = min(max(s.fst, 0.0), 1.0);
circumcircle.h B fore(i,0,SZ(v)-1) a += v[i].cross(v[i+1]); double sum = 0;
Description: return a;
r c }
ll cnt = segs[0].snd;
The circumcirle of a triangle is the circle intersecting all C fore(j,1,SZ(segs)) {
three vertices. ccRadius returns the radius of the circle going A if (!cnt) sum += segs[j].fst - segs[j - 1].fst;
through points A, B and C and ccCenter returns the center cnt += segs[j].snd;
of the same circle. PolygonCenter.h }
1caa3a, 9 lines
Description: Returns the center of mass for a polygon.
"Point.h" ret += A.cross(B) * sum;
Time: O (n)
typedef Point<double> P; }
"Point.h" 3bf296, 9 lines
double ccRadius(const P& A, const P& B, const P& C) { return ret / 2;
return (B-A).dist()*(C-B).dist()*(A-C).dist()/ typedef Point<double> P; }
abs((B-A).cross(C-A))/2; P polygonCenter(const vector<P>& v) {
P res(0, 0); double A = 0;
}
for (ll i = 0, j = SZ(v) - 1; i < SZ(v); j = i++) { ConvexHull.h
P ccCenter(const P& A, const P& B, const P& C) { Description:
P b = C-A, c = B-A; res = res + (v[i] + v[j]) * v[j].cross(v[i]);
A += v[j].cross(v[i]); Returns a vector of the points of the convex hull in counter-
return A + (b*c.dist2()-c*b.dist2()).perp()/b.cross(c)/2; clockwise order. Points on the edge of the hull between two
} }
return res / A / 3; other points are not considered part of the hull.
} Time: O (n log n)
MinimumEnclosingCircle.h "Point.h" a592da, 13 lines
Description: Computes the minimum circle that encloses a set of points. e template<class P>
Time: expected O (n) PolygonCut.h vector<P> convexHull(vector<P> pts) {
"circumcircle.h" aec76e, 17 lines Description: if (SZ(pts) <= 1) return pts;
pair<P, double> mec(vector<P> ps) { Returns a vector with the vertices of a polygon with every- sort(ALL(pts));
shuffle(ALL(ps), mt19937(time(0))); thing to the left of the line going from s to e cut away. vector<P> h(SZ(pts)+1);
Usage: vector<P> p = ...; s ll s = 0, t = 0;
P o = ps[0];
double r = 0, EPS = 1 + 1e-8; p = polygonCut(p, P(0,0), P(1,0)); for (ll it = 2; it--; s = --t, reverse(ALL(pts)))
fore(i,0,SZ(ps)) if ((o - ps[i]).dist() > r * EPS) { "Point.h" b9b27a, 12 lines for (P p : pts) {
o = ps[i], r = 0; typedef Point<double> P; while (t >= s + 2 && h[t-2].cross(h[t-1], p) <= 0) t--;
fore(j,0,i) if ((o - ps[j]).dist() > r * EPS) { vector<P> polygonCut(const vector<P>& poly, P s, P e) { h[t++] = p;
o = (ps[i] + ps[j]) / 2; vector<P> res; }
r = (o - ps[i]).dist(); fore(i,0,SZ(poly)) { return {h.begin(), h.begin() + t - (t == 2 && h[0] == h[1])};
fore(k,0,j) if ((o - ps[k]).dist() > r * EPS) { P cur = poly[i], prev = i ? poly[i-1] : poly.back(); }
o = ccCenter(ps[i], ps[j], ps[k]); auto a = s.cross(e, cur), b = s.cross(e, prev);
r = (o - ps[i]).dist(); if ((a < 0) != (b < 0)) HullDiameter.h
} res.pb(cur + (prev - cur) * (a / (a - b))); Description: Returns the two points with max distance on a convex hull
} if (a < 0) res.pb(cur); (ccw, no duplicate/collinear points).
} } Time: O (n)
return {o, r}; return res; "Point.h" 9df441, 12 lines
} }
typedef Point<ll> P;
UNC PointInsideHull LineHullIntersection MinkowskiSum ClosestPair ManhattanMST kdTree 2025-04-20 26
array<P, 2> hullDiameter(vector<P> S) { while ((lo + 1) % n != hi) { }
ll n = SZ(S), j = n < 2 ? 0 : 1; ll m = ((lo + hi + (lo < hi ? 0 : n)) / 2) % n;
pair<ll, array<P, 2>> res({0, {S[0], S[0]}}); (cmpL(m) == cmpL(endB) ? lo : hi) = m;
for (ll i = 0; i < j; i++) }
ManhattanMST.h
Description: Given N points, returns up to 4*N edges, which are guaran-
for (;; j = (j + 1) % n) { res[i] = (lo + !cmpL(hi)) % n;
teed to contain a minimum spanning tree for the graph with edge weights
res = max(res, {(S[i] - S[j]).dist2(), {S[i], S[j]}}); swap(endA, endB);
w(p, q) = —p.x - q.x— + —p.y - q.y—. Edges are in the form (distance,
if ((S[(j + 1) % n] - S[j]).cross(S[i + 1] - S[i]) >= 0) }
src, dst). Use a standard MST algorithm on the result to find the final MST.
break; if (res[0] == res[1]) return {res[0], -1};
Time: O (N log N )
} if (!cmpL(res[0]) && !cmpL(res[1]))
"Point.h" aa0ef5, 23 lines
return res.snd; switch ((res[0] - res[1] + SZ(poly) + 1) % SZ(poly)) {
} case 0: return {res[0], res[0]}; typedef Point<ll> P;
case 2: return {res[1], res[1]}; vector<array<ll, 3>> manhattanMST(vector<P> ps) {
} vi id(SZ(ps));
PointInsideHull.h return res; iota(ALL(id), 0);
Description: Determine whether a point t lies inside a convex hull (CCW vector<array<ll, 3>> edges;
}
order, with no collinear points). Returns true if point lies within the hull. If fore(k,0,4) {
strict is true, points on the boundary aren’t included. sort(ALL(id), [&](ll i, ll j) {
Time: O (log N ) MinkowskiSum.h return (ps[i]-ps[j]).x < (ps[j]-ps[i]).y;});
"Point.h", "sideOf.h", "OnSegment.h" a211ec, 14 lines Description: Compute Minkowski sum of two strictly convex non empty
map<ll, ll> sweep;
polygons (i.e. two hulls). Returns answer in CCW order. The Minkowski
typedef Point<ll> P; for (ll i : id) {
sum of two polygons P and Q viewed as sets of R2 is defined as {p + q : p ∈
for (auto it = sweep.lower_bound(-ps[i].y);
P, q ∈ Q}
bool inHull(const vector<P>& l, P p, bool strict = true) { it != sweep.end(); sweep.erase(it++)) {
Time: O (n log n + m log m)
ll a = 1, b = SZ(l) - 1, r = !strict; ll j = it->snd;
"Point.h", "ConvexHull.h", "sideOf.h" 19e096, 23 lines
if (SZ(l) < 3) return r && onSegment(l[0], l.back(), p); P d = ps[i] - ps[j];
if (sideOf(l[0], l[a], l[b]) > 0) swap(a, b); typedef Point<ll> P; if (d.y > d.x) break;
if (sideOf(l[0], l[a], p) >= r || sideOf(l[0], l[b], p)<= -r) edges.pb({d.y + d.x, i, j});
return false; void reorder(vector<P> &p) { }
while (abs(a - b) > 1) { if (sideOf(p[0], p[1], p[2]) < 0) reverse(ALL(p)); sweep[-ps[i].y] = i;
ll c = (a + b) / 2; rotate(p.begin(), min_element(ALL(p)), p.end()); }
(sideOf(l[0], l[c], p) > 0 ? b : a) = c; } for (P& p : ps) if (k & 1) p.x = -p.x; else swap(p.x, p.y);
} vector<P> minkowskiSum(vector<P> p, vector<P> q) { }
return sgn(l[a].cross(l[b], p)) < r; if (min(SZ(p), SZ(q)) < 3) { return edges;
} vector<P> v; }
for (P pp : p) for (P qq : q) v.pb(pp + qq);
return convexHull(v);
LineHullIntersection.h } kdTree.h
Description: Line-convex polygon intersection. The polygon must be ccw reorder(p), reorder(q); Description: KD-tree (2d, can be extended to 3d)
and have no collinear points. lineHull(line, poly) returns a pair describing fore(i, 0, 2) p.pb(p[i]), q.pb(q[i]); "Point.h" 58a1a5, 63 lines
the intersection of a line with the polygon: • (−1, −1) if no collision, • (i, −1) vector<P> r; typedef ll T;
if touching the corner i, • (i, i) if along side (i, i + 1), • (i, j) if crossing sides ll i = 0, j = 0; typedef Point<T> P;
(i, i + 1) and (j, j + 1). In the last case, if a corner i is crossed, this is treated while (i + 2 < SZ(p) || j + 2 < SZ(q)) { const T INF = numeric_limits<T>::max();
as happening on side (i, i + 1). The points are returned in the same order as r.pb(p[i] + q[j]);
the line hits the polygon. extrVertex returns the point of a hull with the ll cross = (p[i + 1] - p[i]).cross(q[j + 1] - q[j]); bool on_x(const P& a, const P& b) { return a.x < b.x; }
max projection onto a line. i += cross >= 0, j += cross <= 0; bool on_y(const P& a, const P& b) { return a.y < b.y; }
Time: O (log n) }
"Point.h" 5eb565, 39 lines return r; struct Node {
#define cmp(i,j) sgn(dir.perp().cross(poly[(i)%n]-poly[(j)%n])) } P pt; // i f t h i s i s a leaf , the single point in i t
#define extr(i) cmp(i + 1, i) >= 0 && cmp(i, i - 1 + n) < 0 T x0 = INF, x1 = -INF, y0 = INF, y1 = -INF; // bounds
template <class P> ll extrVertex(vector<P>& poly, P dir) { 8.4 Misc. Point Set Problems Node *first = 0, *second = 0;
ll n = SZ(poly), lo = 0, hi = n;
if (extr(0)) return 0; ClosestPair.h T distance(const P& p) { // min squared distance to a point
while (lo + 1 < hi) { Description: Finds the closest pair of points. T x = (p.x < x0 ? x0 : p.x > x1 ? x1 : p.x);
ll m = (lo + hi) / 2; Time: O (n log n) T y = (p.y < y0 ? y0 : p.y > y1 ? y1 : p.y);
if (extr(m)) return m; "Point.h" 4a68f8, 17 lines return (P(x,y) - p).dist2();
ll ls = cmp(lo + 1, lo), ms = cmp(m + 1, m); typedef Point<ll> P; }
(ls < ms || (ls == ms && ls == cmp(lo, m)) ? hi : lo) = m; pair<P, P> closest(vector<P> v) {
} assert(SZ(v) > 1); Node(vector<P>&& vp) : pt(vp[0]) {
return lo; set<P> S; for (P p : vp) {
} sort(ALL(v), [](P a, P b) { return a.y < b.y; }); x0 = min(x0, p.x); x1 = max(x1, p.x);
pair<ll, pair<P, P>> ret{LLONG_MAX, {P(), P()}}; y0 = min(y0, p.y); y1 = max(y1, p.y);
#define cmpL(i) sgn(a.cross(poly[i], b)) ll j = 0; }
template <class P> for (P p : v) { if (vp.size() > 1) {
array<ll, 2> lineHull(P a, P b, vector<P>& poly) { P d{1 + (ll)sqrt(ret.fst), 0}; // s p l i t on x i f width >= height (not ideal . . . )
ll endA = extrVertex(poly, (a - b).perp()); while (v[j].y <= p.y - d.x) S.erase(v[j++]); sort(ALL(vp), x1 - x0 >= y1 - y0 ? on_x : on_y);
ll endB = extrVertex(poly, (b - a).perp()); auto lo = S.lower_bound(p - d), hi = S.upper_bound(p + d); // divide by taking h a l f the array for each child (not
if (cmpL(endA) < 0 || cmpL(endB) > 0) for (; lo != hi; ++lo) // best performance with many duplicates in the middle)
return {-1, -1}; ret = min(ret, {(*lo - p).dist2(), {*lo, p}}); ll half = SZ(vp)/2;
array<ll, 2> res; S.insert(p); first = new Node({vp.begin(), vp.begin() + half});
fore(i,0,2) { } second = new Node({vp.begin() + half, vp.end()});
ll lo = endB, hi = endA, n = SZ(poly); return ret.snd; }
UNC DelaunayTriangulation FastDelaunay PolyhedronVolume Point3D PlaneDistance 2025-04-20 27
} bool circ(P p, P a, P b, P c) { // i s p in the circumcircle? #define ADD { Q c = e; do { c->mark = 1; pts.pb(c->p); \
}; lll p2 = p.dist2(), A = a.dist2()-p2, q.pb(c->r()); c = c->next(); } while (c != e); }
B = b.dist2()-p2, C = c.dist2()-p2; ADD; pts.clear();
struct KDTree { return p.cross(a,b)*C + p.cross(b,c)*A + p.cross(c,a)*B > 0; while (qi < SZ(q)) if (!(e = q[qi++])->mark) ADD;
Node* root; } return pts;
KDTree(const vector<P>& vp) : root(new Node({ALL(vp)})) {} Q makeEdge(P orig, P dest) { }
Q r = H ? H : new Quad{new Quad{new Quad{new Quad{0}}}};
pair<T, P> search(Node *node, const P& p) { H = r->o; r->r()->r() = r;
if (!node->fst) { fore(i,0,4) r = r->rot, r->p = arb, r->o = i&1 ? r : r->r();
// uncomment i f we should not find the point i t s e l f : r->p = orig; r->F() = dest; 8.5 3D
// i f (p == node−>pt ) return {INF, P()}; return r; PolyhedronVolume.h
return make_pair((p - node->pt).dist2(), node->pt); } Description: Magic formula for the volume of a polyhedron. Faces should
} void splice(Q a, Q b) { point outwards.
swap(a->o->rot->o, b->o->rot->o); swap(a->o, b->o); 3058c3, 6 lines

Node *f = node->fst, *s = node->snd; } template<class V, class L>


T bfirst = f->distance(p), bsec = s->distance(p); Q connect(Q a, Q b) { double signedPolyVolume(const V& p, const L& trilist) {
if (bfirst > bsec) swap(bsec, bfirst), swap(f, s); Q q = makeEdge(a->F(), b->p); double v = 0;
splice(q, a->next()); for (auto i : trilist) v += p[i.a].cross(p[i.b]).dot(p[i.c]);
// search c l o s e s t side f i r s t , other side i f needed splice(q->r(), b); return v / 6;
auto best = search(f, p); return q; }
if (bsec < best.fst) }
best = min(best, search(s, p));
return best; pair<Q,Q> rec(const vector<P>& s) { Point3D.h
} if (SZ(s) <= 3) { Description: Class to handle points in 3D space. T can be e.g. double or
Q a = makeEdge(s[0], s[1]), b = makeEdge(s[1], s.back()); ll. 8058ae, 32 lines
// find nearest point to a point , and i t s squared distance if (SZ(s) == 2) return { a, a->r() };
// ( requires an arbitrary operator< for Point) splice(a->r(), b); template<class T> struct Point3D {
pair<T, P> nearest(const P& p) { auto side = s[0].cross(s[1], s[2]); typedef Point3D P;
return search(root, p); Q c = side ? connect(b, a) : 0; typedef const P& R;
} return {side < 0 ? c->r() : a, side < 0 ? c : b->r() }; T x, y, z;
}; } explicit Point3D(T x=0, T y=0, T z=0) : x(x), y(y), z(z) {}
bool operator<(R p) const {
#define H(e) e->F(), e->p return tie(x, y, z) < tie(p.x, p.y, p.z); }
DelaunayTriangulation.h #define valid(e) (e->F().cross(H(base)) > 0) bool operator==(R p) const {
Description: Computes the Delaunay triangulation of a set of points. Each return tie(x, y, z) == tie(p.x, p.y, p.z); }
Q A, B, ra, rb;
circumcircle contains none of the input points. If any three points are P operator+(R p) const { return P(x+p.x, y+p.y, z+p.z); }
ll half = SZ(s) / 2;
collinear or any
 four are on the same circle, behavior is undefined. P operator-(R p) const { return P(x-p.x, y-p.y, z-p.z); }
tie(ra, A) = rec({ALL(s) - half});
Time: O n2 P operator*(T d) const { return P(x*d, y*d, z*d); }
tie(B, rb) = rec({SZ(s) - half + ALL(s)});
"Point.h", "3dHull.h" bb23ab, 8 lines P operator/(T d) const { return P(x/d, y/d, z/d); }
while ((B->p.cross(H(A)) < 0 && (A = A->next())) ||
template<class P> void delaunay(vector<P>& ps, auto f) { (A->p.cross(H(B)) > 0 && (B = B->r()->o))); T dot(R p) const { return x*p.x + y*p.y + z*p.z; }
if (SZ(ps)==3){ll d=ps[0].cross(ps[1],ps[2])<0;f(0,1+d,2-d);} Q base = connect(B->r(), A); P cross(R p) const {
vector<P3> p3; if (A->p == ra->p) ra = base->r(); return P(y*p.z - z*p.y, z*p.x - x*p.z, x*p.y - y*p.x);
for (P p : ps) p3.pb(P3{p.x, p.y, p.dist2()}); if (B->p == rb->p) rb = base; }
if (SZ(ps) > 3) for (auto [_, a, b, c] : hull3d(p3)) T dist2() const { return x*x + y*y + z*z; }
if ((p3[b]-p3[a]).cross(p3[c]-p3[a]).dot(P3(0,0,1)) < 0) #define DEL(e, init, dir) Q e = init->dir; if (valid(e)) \ double dist() const { return sqrt((double)dist2()); }
f(a, c, b); while (circ(e->dir->F(), H(base), e->F())) { \ //Azimuthal angle ( longitude ) to x−axis in interval [−pi , pi ]
} Q t = e->dir; \ double phi() const { return atan2(y, x); }
splice(e, e->prev()); \ //Zenith angle ( l a t i t u d e ) to the z−axis in interval [0 , pi ]
splice(e->r(), e->r()->prev()); \ double theta() const { return atan2(sqrt(x*x+y*y),z); }
FastDelaunay.h P unit() const { return *this/(T)dist(); } //makes d i s t ()=1
Description: Fast Delaunay triangulation. Each circumcircle contains none e->o = H; H = e; e = t; \
} //returns unit vector normal to ∗ t h i s and p
of the input points. There must be no duplicate points. If all points are on a P normal(P p) const { return cross(p).unit(); }
line, no triangles will be returned. Should work for doubles as well, though for (;;) {
DEL(LC, base->r(), o); DEL(RC, base, prev()); //returns point rotated ’ angle ’ radians ccw around axis
there may be precision issues in ’circ’. Returns triangles in order {t[0][0], P rotate(double angle, P axis) const {
t[0][1], t[0][2], t[1][0], . . . }, all counter-clockwise. if (!valid(LC) && !valid(RC)) break;
if (!valid(LC) || (valid(RC) && circ(H(RC), H(LC)))) double s = sin(angle), c = cos(angle); P u = axis.unit();
Time: O (n log n) return u*dot(u)*(1-c) + (*this)*c - cross(u)*s;
"Point.h" 55602c, 88 lines
base = connect(RC, base->r());
else }
typedef Point<ll> P; base = connect(base->r(), LC->r()); };
typedef struct Quad* Q; }
typedef __int128_t lll; // (can be l l i f coords are < 2e4) return { ra, rb };
P arb(LLONG_MAX,LLONG_MAX); // not equal to any other point } PlaneDistance.h
Description: Returns the signed distance between point p and the plane
struct Quad { vector<P> triangulate(vector<P> pts) { containing points a, b and c. a, b and c must not be collinear.
Q rot, o; P p = arb; bool mark; sort(ALL(pts)); assert(unique(ALL(pts)) == pts.end()); "Point3D.h" c94293, 5 lines
P& F() { return r()->p; } if (SZ(pts) < 2) return {}; template<class P>
Q& r() { return rot->rot; } Q e = rec(pts).fst; double planeDist(P a, P b, P c, P p) {
Q prev() { return rot->o->rot; } vector<Q> q = {e}; P n = (b-a).cross(c-a);
Q next() { return r()->prev(); } ll qi = 0; return (double)n.dot(p-a) / n.dist();
} *H; while (e->o->F().cross(e->F(), e->p) < 0) e = e->o; }
UNC sideOfPlane 3dHull sphericalDistance KMP Zfunc Manacher MinRotation SuffixArray SuffixAutomaton 2025-04-20 28
sideOfPlane.h sphericalDistance.h ll n = SZ(s);
Description: Returns at witch side of the plane defined by a, b and c the Description: Returns the shortest distance on the sphere with radius ra- array<vi,2> p = {vi(n+1), vi(n)};
point p is. If the point is on the plane 0 is returned, else 1 or -1. a, b and c dius between the points with azimuthal angles (longitude) f1 (ϕ1 ) and f2 (ϕ2 ) fore(z,0,2) for (ll i=0,l=0,r=0; i < n; i++) {
must not be collinear. For double add epsilon checks. from x axis and zenith angles (latitude) t1 (θ1 ) and t2 (θ2 ) from z axis (0 = ll t = r-i+!z;
"Point.h" b4ebf8, 5 lines north pole). All angles measured in radians. The algorithm starts by con- if (i<r) p[z][i] = min(t, p[z][l+t]);
template<class P> verting the spherical coordinates to cartesian coordinates so if that is what ll L = i-p[z][i], R = i+p[z][i]-!z;
ll sideOf(P a, P b, P c, P p) { you have you can use only the two last rows. dx*radius is then the difference while (L>=1 && R+1<n && s[L-1] == s[R+1])
ll x = (b-a).cross(c-a).dot(p-a); between the two points in the x direction and d*radius is the total distance p[z][i]++, L--, R++;
return (x > 0) - (x < 0); between the points. 611f07, 8 lines
if (R>r) l=L, r=R;
} }
double sphericalDistance(double f1, double t1, return p;
double f2, double t2, double radius) { }
double dx = sin(t2)*cos(f2) - sin(t1)*cos(f1);
double dy = sin(t2)*sin(f2) - sin(t1)*sin(f1);
3dHull.h double dz = cos(t2) - cos(t1);
Description: Computes all faces of the 3-dimension hull of a point set. *No double d = sqrt(dx*dx + dy*dy + dz*dz);
four points must be coplanar*, or else random results will be returned. All return radius*2*asin(d/2); MinRotation.h
faces will point } Description: Finds the lexicographically smallest rotation of a string.
 outwards.
Time: O n2 Usage: rotate(v.begin(), v.begin()+minRotation(v), v.end());
"Point3D.h" 235fcd, 49 lines Time: O (N )
typedef Point3D<double> P3; Strings (9) ll minRotation(string s) {
b4d34c, 11 lines

ll a=0, N=SZ(s); s += s;
struct PR { KMP.h fore(b,0,N) fore(k,0,N) {
void ins(ll x) { (a == -1 ? a : b) = x; } Description: pi[x] computes the length of the longest prefix of s that ends if (a+k == b || s[a+k] < s[b+k]) {
void rem(ll x) { (a == x ? a : b) = -1; } at x, other than s[0...x] itself (abacaba -> 0010123). Can be used to find all b += max(0ll, k-1);
ll cnt() { return (a != -1) + (b != -1); } occurrences of a string. break;
ll a, b; Time: O (n) 1bc4d4, 16 lines }
}; if (s[a+k] > s[b+k]) { a = b; break; }
vi pi(const string& s) {
vi p(SZ(s)); }
struct F { P3 q; ll a, b, c; }; return a;
fore(i,1,SZ(s)) {
ll g = p[i-1]; }
vector<F> hull3d(const vector<P3>& A) {
assert(SZ(A) >= 4); while (g && s[i] != s[g]) g = p[g-1];
vector<vector<PR>> E(SZ(A), vector<PR>(SZ(A), {-1, -1})); p[i] = g + (s[i] == s[g]);
#define E(x,y) E[f.x][f.y] }
return p;
vector<F> FS;
}
SuffixArray.h
auto mf = [&](ll i, ll j, ll k, ll l) { Description: Builds suffix array for a string. sa[i] is the starting index
P3 q = (A[j] - A[i]).cross((A[k] - A[i])); of the suffix which is i’th in the sorted suffix array. The returned vector
if (q.dot(A[l]) > q.dot(A[i])) vi match(const string& s, const string& pat) {
is of size n + 1, and sa[0] = n. The lcp array contains longest common
q = q * -1; vi p = pi(pat + ’\0’ + s), res;
prefixes for neighbouring strings in the suffix array: lcp[i] = lcp(sa[i],
F f{q, i, j, k}; fore(i,SZ(p)-SZ(s),SZ(p))
sa[i-1]), lcp[0] = 0. rank is the inverse of the suffix array: rank[sa[i]]
E(a,b).ins(k); E(a,c).ins(j); E(b,c).ins(i); if (p[i] == SZ(pat)) res.pb(i - 2 * SZ(pat));
= i. lim should be strictly larger than all elements. For larger alphabets use
FS.pb(f); return res;
basic string<ll> instead of string. The input string must not contain
}; }
any zero bytes.
fore(i,0,4) fore(j,i+1,4) fore(k,j+1,4) Time: O (n log n) 6f3b67, 17 lines
mf(i, j, k, 6 - i - j - k); Zfunc.h
Description: z[i] computes the length of the longest common prefix of s[i:] array<vi, 3> suffixArray(string& s, ll lim = ’z’ + 1) {
fore(i,4,SZ(A)) { and s, except z[0] = 0. (abacaba -> 0010301) ll n = SZ(s) + 1, k = 0, a, b;
for (ll j = 0; j < SZ(FS); j++) { Time: O (n) vi rank(ALL(s)+1), y(n), ws(max(n,lim)), sa(n), lcp(n);
9e784e, 12 lines
F f = FS[j]; iota(ALL(sa), 0);
if (f.q.dot(A[i]) > f.q.dot(A[f.a])) { vi Z(const string& S) { for (ll j = 0, p = 0; p < n; j = max(1ll, j * 2), lim = p) {
E(a,b).rem(f.c); vi z(SZ(S)); p = j, iota(ALL(y), n - j), fill(ALL(ws), 0);
E(a,c).rem(f.b); ll l = -1, r = -1; fore(i,0,n) if (ws[rank[i]]++, sa[i]>=j) y[p++] = sa[i]-j;
E(b,c).rem(f.a); fore(i,1,SZ(S)) { fore(i, 1, lim) ws[i] += ws[i - 1];
swap(FS[j--], FS.back()); z[i] = i >= r ? 0 : min(r - i, z[i - l]); for (ll i = n; i--;) sa[--ws[rank[y[i]]]] = y[i];
FS.pop_back(); while (i + z[i] < SZ(S) && S[i + z[i]] == S[z[i]]) swap(rank, y), p = 1, rank[sa[0]] = 0;
} z[i]++; fore(i, 1, n) a = sa[i - 1], b = sa[i], rank[b] =
} if (i + z[i] > r) (y[a] == y[b] && y[a + j] == y[b + j]) ? p - 1 : p++;
ll nw = SZ(FS); l = i, r = i + z[i]; }
fore(j,0,nw) { } for(ll i = 0, j; i < n - 1; lcp[rank[i++]] = k)
F f = FS[j]; return z; for(k && k--, j = sa[rank[i] - 1]; s[i+k] == s[j+k]; k++);
#define C(a, b, c) if (E(a,b).cnt() != 2) mf(f.a, f.b, i, f.c); } return {sa, lcp, rank};
C(a, b, c); C(a, c, b); C(b, c, a); }
} Manacher.h
} Description: For each position in a string, computes p[0][i] = half length
for (F& it : FS) if ((A[it.b] - A[it.a]).cross( of longest even palindrome around pos i, p[1][i] = longest odd (half rounded
A[it.c] - A[it.a]).dot(it.q) <= 0) swap(it.c, it.b); down).
return FS; Time: O (N ) SuffixAutomaton.h
c6bbec, 13 lines Description: Online algorithm for minimal deterministic finite automaton
};
array<vi, 2> manacher(const string& s) { that accepts the suffixes of a string s.
UNC SuffixTree Hashing AhoCorasick Dates 2025-04-20 29
Exactly all substrings of s are represented by the states, each state repre- } return ret;
senting one or more substrings. Let t the longest string represented by state }
v. Then v.len == SZ(t), all strings represented by v only appear in s as SuffixTree(string a) : a(a), N(2*SZ(a)+2), t(N,vi(ALPHA,-1)){
a suffix of t and they are the longest suffixes of t. The rest of the suffixes r = vi(N, SZ(a)), l = p = s = vi(N), t[1] = vi(ALPHA, 0); H hashString(string& s){H h{}; for(char c:s) h=h*C+c;return h;}
of t are found by following the suffix links v.l. p is the state representing s s[0] = 1, l[0] = l[1] = -1, r[0] = r[1] = p[0] = p[1] = 0;
so terminal states are the ones in the path from p to the root through suffix fore(i,0,SZ(a)) ukkadd(i, toi(a[i])); // hashString ( s + t ) = concat( hashString ( s ) , hashString ( t ) , pw)
links. Also suffix links form the suffix tree of reversed s. Here you can see } // Where pw i s C∗∗| t | and can be obtained from a HashInterval
the automaton for abcbc: H concat(H h0, H h1, H h1pw) { return h0 * h1pw + h1; }
// example : find longest common substring ( uses ALPHA = 28)
b c ii best;
b bc AhoCorasick.h
c b ll lcs(ll node, ll i1, ll i2, ll olen) {
if (l[node] <= i1 && i1 < r[node]) return 1; Description: AhoCorasick automaton. It consists of a trie in with each
start abcb c abcbc node except the root has a link to the longest suffix that is also a node in the
abc b if (l[node] <= i2 && i2 < r[node]) return 2;
a a c trie. That link is used for transitions that are not defined in the trie. Works
b ab ll mask = 0, len = node ? olen + (r[node] - l[node]) : 0;
fore(c,0,ALPHA) if (t[node][c] != -1) with vectors, but for lower case latin strings you can to convert it to vi and
Complexity is amortized: extend adds 1 or 2 states but can change many subtract ’a’ for each character. Use the function go to get the next state of
mask |= lcs(t[node][c], i1, i2, len);
suffix links. Up to 2N states and 3N transitions. For larger alphabets, use the automaton given the current state. Use t[v].leaf to know witch strings
if (mask == 3) best = max(best, {len, r[node] - len});
T = ll. For performance consider s.reserve(2*N), and replacing map with end in the state v.
return mask;
vector or unordered map. Time: O (N ) for constructing where N is the sum of lengths of the words
}
Time: O (N log K). and O (1) for each transition query.
ada074, 16 lines static ii LCS(string s, string t) { 072030, 30 lines
template <class T = char> struct SuffixAutomaton { SuffixTree st(s + (char)(’z’ + 1) + t + (char)(’z’ + 2)); struct AhoCorasick {
struct State { ll len = 0, l = -1; map<T, ll> t; }; st.lcs(0, SZ(s), SZ(s) + 1 + SZ(t), 0); static const ll alpha = 26; // Size of the alphabet
vector<State> s{1}; ll p = 0; return st.best; struct Node {
void extend(T c) { } array<ll, alpha> next, go; vi leaf; ll p, link, pch;
ll k = SZ(s), q; s.pb({s[p].len+1}); }; Node(ll p = -1, ll pch = -1) : p(p), link(-1), pch(pch) {
for(;p != -1 && !s[p].t.count(c); p = s[p].l)s[p].t[c] = k; next.fill(-1), go = next;
if (p == -1) s[k].l = 0; }
else if (s[p].len + 1 == s[q = s[p].t[c]].len) s[k].l = q; Hashing.h };
else { Description: Self-explanatory methods for string hashing. 088baa, 48 lines vector<Node> t;
s.pb(s[q]), s.back().len = s[p].len + 1; // Arithmetic mod 2^64−1. 2x slower than mod 2^64 and more AhoCorasick(vector<vi>& words) : t(1) {
for (; p!=-1 && s[p].t[c]==q; p=s[p].l) s[p].t[c] = k+1; // code , but works on e v i l t e s t data (e . g . Thue−Morse, where fore(i, 0, SZ(words)) {
s[q].l = s[k].l = k+1; // ABBA. . . and BAAB. . . of length 2^10 hash the same mod 2^64) . ll v = 0;
} // ”typedef u l l H;” instead i f you think t e s t data i s random, for (ll c : words[i]) {
p = k; // or work mod 10^9+7 i f the Birthday paradox i s not a problem . if (t[v].next[c]<0) t[v].next[c]=SZ(t),t.pb(Node(v,c));
} typedef uint64_t ull; v = t[v].next[c];
}; struct H { }
ull x; H(ull x=0) : x(x) {} t[v].leaf.pb(i);
H operator+(H o) { return x + o.x + (x + o.x < x); } }
SuffixTree.h H operator-(H o) { return *this + ∼o.x; } }
Description: Ukkonen’s algorithm for online suffix tree construction. Each ll getLink(ll v) {
node contains indices [l, r) into the string, and a list of child nodes. Suffixes H operator*(H o) { auto m = (__uint128_t)x * o.x;
return H((ull)m) + (ull)(m >> 64); } if (t[v].link < 0) t[v].link = v && t[v].p ?
are given by traversals of this tree, joining [l, r) substrings. The root is 0 (has go(getLink(t[v].p), t[v].pch) : 0;
l = -1, r = 0), non-existent children are -1. To get a complete tree, append ull get() const { return x + !∼x; }
bool operator==(H o) const { return get() == o.get(); } return t[v].link;
a dummy symbol – otherwise it may contain an incomplete path (still useful }
for substring matching, though). bool operator<(H o) const { return get() < o.get(); }
}; ll go(ll v, ll c) {
Time: O (26N ) 242d5e, 48 lines if (t[v].go[c] < 0) t[v].go[c] = t[v].next[c] >= 0 ?
static const H C = (ll)1e11+3; // (order ∼ 3e9 ; random also ok)
struct SuffixTree { t[v].next[c] : v ? go(getLink(v),c) : 0;
static constexpr ll ALPHA = 26; // alphabet s i z e struct HashInterval { return t[v].go[c];
ll toi(char c) { return c - ’a’; } vector<H> ha, pw; }
string a; HashInterval(string& str) : ha(SZ(str)+1), pw(ha) { };
ll N, v = 0, q = 0, m = 2; // v = cur node , q = cur position pw[0] = 1;
vector<vi> t; // transitions fore(i,0,SZ(str))
vi r, l, p, s; // a [ l [ i ] : r [ i ] ] i s substring on edge to i ha[i+1] = ha[i] * C + str[i], Various (10)
pw[i+1] = pw[i] * C;
void ukkadd(ll i, ll c) { }
if (r[v] <= q) H hashInterval(ll a, ll b) { // hash [ a , b) 10.1 Dates
if (t[v][c] == -1) return l[t[v][c] = m] = i, return ha[b] - ha[a] * pw[b - a]; Dates.h
q = r[v = s[p[m++] = v]], ukkadd(i, c); } Description: Convert dates to numbers and vice versa. Days and months
else q = l[v = t[v][c]]; }; start from 1. 1/1/1 is day number 1721426.
if (q == -1 || c == toi(a[q])) q++; Time: O (1)
else { vector<H> getHashes(string& str, ll length) { a52f52, 14 lines

l[m+1] = i, l[m] = l[v], r[m] = l[v] = q, p[m] = p[v]; if (SZ(str) < length) return {}; ll dateToInt(ll y, ll m, ll d) {
p[t[m][c] = m+1] = p[v] = t[p[m]][toi(a[l[m]])] = m; H h = 0, pw = 1; return 1461*(y+4800+(m-14)/12)/4 + 367*(m-2-(m-14)/12*12)/12
t[m][toi(a[q])] = v, v = s[p[m]], q = l[m]; fore(i,0,length) - 3*((y+4900+(m-14)/12)/100)/4 + d - 32075;
while (q < r[m]) v = t[v][toi(a[q])], q += r[v]-l[v]; h = h * C + str[i], pw = pw * C; }
if (q == r[m]) s[m] = v; vector<H> ret = {h}; tuple<ll, ll, ll> intToDate(ll jd) {
else s[m] = m + 2; fore(i,length,SZ(str)) { ll x = jd + 68569, n = 4*x/146097;
q = r[v]-(q-r[m]), m += 2, ukkadd(i, c); ret.pb(h = h * C + str[i] - pw * str[i-length]); x -= (146097*n + 3)/4;
} } ll i = (4000*(x + 1))/1461001;
UNC DayOfWeek IntervalContainer IntervalCover ConstantIntervals TernarySearch LIS FastKnapsack KnuthDP DivideAndConquerDP 2025-04-20 30
x -= 1461*i/4 - 31; if (mx.snd == -1) return {}; ll L = SZ(res), cur = res.back().snd;
ll j = 80*x/2447, d = x - 2447*j/80; cur = mx.fst; vi ans(L);
x = j/11; R.pb(mx.snd); while (L--) ans[L] = cur, cur = prev[cur];
ll m = j + 2 - 12*x, y = 100*(n - 49) + i + x; } return ans;
return {y, m, d}; return R; }
} }

DayOfWeek.h ConstantIntervals.h FastKnapsack.h


Description: Get the day of the week for a given date. Days and months Description: Split a monotone function on [from, to) into a minimal set of Description: Given N non-negative integer weights w and a non-negative
start from 1 and days of the week are returned starting on Sunday from 0. half-open intervals on which it has the same value. Runs a callback g for target t, computes the maximum S <= t such that S is the sum of some
Time: O (1) ef94b0, 5 lines
each such interval. subset of the weights.
Usage: constantIntervals(0, SZ(v), [&](ll x) {return v[x];}, Time: O (N max(wi )) 315e89, 16 lines
ll DayOfWeek(ll y, ll m, ll d) {
vi ttt = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
[&](ll lo, ll hi,  T val) {...}); ll knapsack(vi w, ll t) {
Time: O k log n k eb2579, 17 lines
y -= m < 3; ll a = 0, b = 0, x;
return (y + y/4 - y/100 + y/400 + ttt[m-1] + d) % 7; template<class T> while (b < SZ(w) && a + w[b] <= t) a += w[b++];
} void rec(ll from, ll to, auto&& f, auto&& g, ll& i, T& p, T q){ if (b == SZ(w)) return a;
if (p == q) return; ll m = *max_element(ALL(w));
10.2 Intervals if (from == to) {
g(i, to, p), i = to, p = q;
vi u, v(2*m, -1);
v[a+m-t] = b;
IntervalContainer.h } else { fore(i,b,SZ(w)) {
Description: Add and remove intervals from a set of disjoint intervals. ll mid = (from + to) >> 1; u = v;
Will merge the added interval with any overlapping intervals in the set when rec(from, mid, f, g, i, p, f(mid)); fore(x,0,m) v[x+w[i]] = max(v[x+w[i]], u[x]);
adding. Intervals are [inclusive, exclusive). rec(mid+1, to, f, g, i, p, q); for (x = 2*m; --x > m;) fore(j, max(0ll,u[x]), v[x])
Time: O (log N ) 76239e, 23 lines
} v[x-w[j]] = max(v[x-w[j]], j);
} }
set<ii>::iterator addInterval(set<ii>& is, ll L, ll R) { void constantIntervals(ll from, ll to, auto&& f, auto&& g) { for (a = t; v[a+m-t] < 0; a--) ;
if (L == R) return is.end(); if (to <= from) return; return a;
auto it = is.lower_bound({L, R}), before = it; ll i = from; auto p = f(i), q = f(to-1); }
while (it != is.end() && it->fst <= R) { rec(from, to-1, f, g, i, p, q);
R = max(R, it->snd); g(i, to, q);
before = it = is.erase(it); }
}
if (it != is.begin() && (--it)->snd >= L) { 10.4 Dynamic programming
L = min(L, it->fst); 10.3 Misc. algorithms KnuthDP.h
R = max(R, it->snd); TernarySearch.h Description: When doing DP on intervals: a[i][j] = mini<k<j (a[i][k] +
is.erase(it); Description: Find the smallest i in [a, b] that maximizes f (i), assuming a[k][j]) + f (i, j), where the (minimal) optimal k increases with both i
} that f (a) < . . . < f (i) ≥ · · · ≥ f (b). To reverse which of the sides allows and j, one can solve intervals in increasing order of length, and search
return is.insert(before, {L,R}); non-strict inequalities, change the < marked with (A) to <=, and reverse k = p[i][j] for a[i][j] only between p[i][j − 1] and p[i + 1][j]. This is
} the loop at (B). To minimize f , change it to >, also at (B). known as Knuth DP. Sufficient criteria for this are if f (b, c) ≤ f (a, d) and
Usage: ll ind = ternSearch(0,n-1,[&](ll i) {return a[i];}); f (a, c) + f (b, d) ≤ f (a, d) + f (b, c) for all a ≤ b ≤ c ≤ d. Consider also:
void removeInterval(set<ii>& is, ll L, ll R) { Time: O (log(b − a)) 310703, 10 lines LineContainer(ch. Data structures), monotone queues, ternary search.
if (L == R) return;
Time: O N 2
auto it = addInterval(is, L, R); ll ternSearch(ll a, ll b, auto&& f) {
auto r2 = it->snd; assert(a <= b);
if (it->fst == L) is.erase(it); while (b - a >= 5) {
else (ll&)it->snd = L; ll mid = (a + b) / 2;
if (R != r2) is.emplace(R, r2); if (f(mid) < f(mid+1)) a = mid; // (A) DivideAndConquerDP.h
} else b = mid+1; Description: Given a[i] = minlo(i)≤k<hi(i) (f (i, k)) where the (minimal)
} optimal k increases with i, computes a[i] for i = L..R − 1.
fore(i,a+1,b+1) if (f(a) < f(i)) a = i; // (B) Time: O ((N + (hi − lo)) log N )
IntervalCover.h return a;
64b06e, 18 lines
Description: Compute indices of smallest set of intervals covering another struct DP { // Modify at w i l l :
interval. Intervals should be [inclusive, exclusive). To support [inclusive, }
ll lo(ll ind) { return 0; }
inclusive], change (A) to add || R.empty(). Returns empty set on failure ll hi(ll ind) { return ind; }
(or if G is empty). LIS.h ll f(ll ind, ll k) { return dp[ind][k]; }
Time: O (N log N ) 9ddd82, 19 lines
Description: Compute indices for the longest increasing subsequence. void store(ll ind, ll k, ll v) { res[ind] = {k, v}; }
Time: O (N log N ) 00efff, 17 lines
template<class T>
void rec(ll L, ll R, ll LO, ll HI) {
vi cover(pair<T, T> G, vector<pair<T, T>> I) { template<class I> vi lis(const vector<I>& S) {
if (L >= R) return;
vi S(SZ(I)), R; if (S.empty()) return {};
ll mid = (L + R) >> 1;
iota(ALL(S), 0); vi prev(SZ(S));
ii best(LLONG_MAX, LO);
sort(ALL(S), [&](ll a, ll b) { return I[a] < I[b]; }); typedef pair<I, ll> p;
for (ll k = max(LO, lo(mid)); k < min(HI, hi(mid)); k++)
T cur = G.fst; vector<p> res;
best = min(best, make_pair(f(mid, k), k));
ll at = 0; fore(i,0,SZ(S)) {
store(mid, best.snd, best.fst);
while (cur < G.snd) { // (A) // change 0 −> i for longest non−decreasing subsequence
rec(L, mid, LO, best.snd+1);
pair<T, ll> mx = {cur, -1}; auto it = lower_bound(ALL(res), p{S[i], 0});
rec(mid+1, R, best.snd, HI);
while (at < SZ(I) && I[S[at]].fst <= cur) { if (it == res.end()) res.pb({}), it = res.end()-1;
}
mx = max(mx, {I[S[at]].snd, S[at]}); *it = {S[i], i}; void solve(ll L, ll R) { rec(L, R, LLONG_MIN, LLONG_MAX); }
at++; prev[i] = it == res.begin() ? 0 : (it-1)->snd;
};
} }
UNC FastMod Randin FastInput BumpAllocator SmallPtr BumpAllocatorSTL SIMD 2025-04-20 31
10.5 Debugging tricks ull b, m; explicit operator bool() const { return ind; }
FastMod(ull b) : b(b), m(-1ULL / b) {} };
• signal(SIGSEGV, [](int) { _Exit(0); }); ull reduce(ull a) { // a % b + (0 or b)
return a - (ull)((__uint128_t(m) * a) >> 64) * b;
converts segfaults into Wrong Answers. Similarly one can } BumpAllocatorSTL.h
catch SIGABRT (assertion failures) and SIGFPE (zero }; Description: BumpAllocator for STL containers.
Usage: vector<vector<ll, small<ll>>> ed(N);
divisions). _GLIBCXX_DEBUG failures generate SIGABRT bb66d4, 14 lines

(or SIGSEGV on gcc 5.4.0 apparently). Randin.h char buf[450 << 20] alignas(16);
Description: Fast and secure integer uniform random numbers. For floating size_t buf_ind = sizeof buf;
• feenableexcept(29); kills the program on NaNs (1), point numbers use uniform real distribution.
template<class T> struct small {
Time: 2x faster than rand(). 1108e7, 7 lines
0-divs (4), infinities (8) and denormals (16). typedef T value_type;
template <typename T> small() {}
• -fsanitize=address -g in compilation to detect some T randin(T a, T b) { // Random number in [ a , b) template<class U> small(const U&) {}
static random_device rd; T* allocate(size_t n) {
memory access errors at run time. static mt19937_64 gen(rd()); buf_ind -= n * sizeof(T);
uniform_int_distribution<T> dis(a, b - 1);
• Several runtime checks: return dis(gen);
buf_ind &= 0 - alignof(T);
return (T*)(buf + buf_ind);
#define _GLIBCXX_DEBUG 1 } }
#define _GLIBCXX_DEBUG_PEDANTIC 1 void deallocate(T*, size_t) {}
#define _GLIBCXX_CONCEPT_CHECKS 1 FastInput.h };
Description: Read an integer from stdin. Usage requires your program to
#define _GLIBCXX_SANITIZE_VECTOR 1 pipe in input from file.
Usage: ./a.out < input.txt SIMD.h
10.6 Optimization tricks Time: About 5x as fast as cin/scanf. d42732, 17 lines
Description: Cheat sheet of SSE/AVX intrinsics, for doing arithmetic
on several numbers at once. Can provide a constant factor improvement
__builtin_ia32_ldmxcsr(40896); disables denormals inline char gc() { // l i k e getchar () of about 4, orthogonal to loop unrolling. Operations follow the pat-
(which make floats 20x slower near their minimum value). static char buf[1 << 16]; tern " mm(256)? name (si(128|256)|epi(8|16|32|64)|pd|ps)". Not all
static size_t bc, be; are described here; grep for mm in /usr/lib/gcc/*/4.9/include/ for
10.6.1 Bit hacks if (bc >= be) { more. If AVX is unsupported, try 128-bit operations, ”emmintrin.h” and
buf[0] = 0, bc = 0; #define SSE and MMX before including it. For aligned memory use
• x & -x is the least bit in x. be = fread(buf, 1, sizeof(buf), stdin); mm malloc(size, 32) or int buf[N] alignas(32), but prefer loadu/s-
} toreu. d1ecdc, 43 lines
• for (int x = m; x; ) { --x &= m; ... } loops return buf[bc++]; // returns 0 on EOF
#pragma GCC target ("avx2") // or sse4 .1
}
over all subset masks of m (except m itself). #include "immintrin.h"
ll readInt() {
• c = x&-x, r = x+c; (((rˆx) >> 2)/c) | r is the ll a, c; typedef __m256i mi;
while ((a = gc()) < 40); #define L(x) _mm256_loadu_si256((mi*)&(x))
next number after x with the same number of bits set.
if (a == ’-’) return -readInt();
// High−l e v e l / s p e c i f i c methods :
• fore(b,0,K) fore(i,0,(1 << K)) while ((c = gc()) >= 48) a = a * 10 + c - 480;
return a - 48; // load (u)? si256 , store (u)? si256 , setzero si256 , mm malloc
if (i & 1 << b) D[i] += D[iˆ(1 << b)]; } // blendv ( epi8 | ps | pd) ( z?y : x) , movemask epi8 ( h i b i t s of bytes )
// i32gather epi32 (addr , x , 4) : map addr [ ] over 32−b parts of x
computes all sums of subsets. // sad epu8 : sum of absolute differences of u8, outputs 4xi64
BumpAllocator.h // maddubs epi16 : dot product of unsigned i7 ’ s , outputs 16xi15
10.6.2 Pragmas Description: When you need to dynamically allocate many objects and // madd epi16 : dot product of signed i16 ’ s , outputs 8xi32
don’t care about freeing them. ”new X” otherwise has an overhead of some- // extractf128 si256 ( , i ) (256−>128) , cvtsi128 si32 (128−>lo32 )
• #pragma GCC optimize ("Ofast") will make GCC thing like 0.05us + 16 bytes per allocation. // permute2f128 si256(x , x ,1) swaps 128−b i t lanes
d23557, 8 lines
auto-vectorize loops and optimizes floating points better. // Either g l o b a l l y or in a single class : // shuffle epi32 (x , 3∗64+2∗16+1∗4+0) == x for each lane
static char buf[900 << 20]; // s h u f f l e e p i 8 (x , y) takes a vector instead of an imm
• #pragma GCC target ("avx2") can double performance of void* operator new(size_t s) {
vectorized code, but causes crashes on old machines. static size_t i = sizeof buf; // Methods that work with most data types (append e . g . epi32 ) :
assert(s < i); // set1 , blend ( i8?x : y) , add , adds ( sat . ) , mullo , sub , and/or ,
// andnot , abs , min, max, sign (1 ,x) , cmp( gt | eq) , unpack( lo | hi )
• #pragma GCC optimize ("trapv") kills the program on integer return (void*)&buf[i -= s];
}
overflows (but is really slow). void operator delete(void*) {} int sumi32(mi m) { union {int v[8]; mi m;} u; u.m = m;
int ret = 0; fore(i,0,8) ret += u.v[i]; return ret; }
10.6.3 Other mi zero() { return _mm256_setzero_si256(); }
SmallPtr.h mi one() { return _mm256_set1_epi32(-1); }
• cin.exceptions(cin.failbit); will make cin throw on bad Description: A 32-bit pointer that points into BumpAllocator memory. bool all_zero(mi m) { return _mm256_testz_si256(m, m); }
"BumpAllocator.h" 2dd6c9, 10 lines bool all_one(mi m) { return _mm256_testc_si256(m, one()); }
input.
template<class T> struct ptr {
FastMod.h unsigned ind; int example_filteredDotProduct(int n, short* a, short* b) {
Description: Compute a%b about 5 times faster than usual, where b is ptr(T* p = 0) : ind(p ? unsigned((char*)p - buf) : 0) { int i = 0; int r = 0;
constant but not known at compile time. Returns a value congruent to a assert(ind < sizeof buf); mi zero = _mm256_setzero_si256(), acc = zero;
(mod b) in the range [0, 2b). } while (i + 16 <= n) {
751a02, 8 lines T& operator*() const { return *(T*)(buf + ind); } mi va = L(a[i]), vb = L(b[i]); i += 16;
typedef unsigned long long ull; T* operator->() const { return &**this; } va = _mm256_and_si256(_mm256_cmpgt_epi16(vb, va), va);
struct FastMod { T& operator[](int a) const { return (&**this)[a]; } mi vp = _mm256_madd_epi16(va, vb);
UNC 2025-04-20 32
acc = _mm256_add_epi64(_mm256_unpacklo_epi32(vp, zero),
_mm256_add_epi64(acc, _mm256_unpackhi_epi32(vp, zero)));
}
union {int v[4];mi m;} u; u.m=acc; fore(i,0,4) r += u.v[i];
for (;i<n;++i) if (a[i] < b[i]) r += a[i]*b[i]; // <− equiv
return r;
}
UNC techniques 2025-04-20 33

Techniques (A) Computation of binomial coefficients


Pigeon-hole principle
Knuth-Morris-Pratt
Tries
Inclusion/exclusion Rolling polynomial hashes
techniques.txt 159 lines
Catalan number Suffix array
Pick’s theorem Suffix tree
Recursion Number theory Aho-Corasick
Divide and conquer Integer parts Manacher’s algorithm
Finding interesting points in N log N Divisibility Letter position lists
Algorithm analysis Euclidean algorithm Combinatorial search
Master theorem Modular arithmetic Meet in the middle
Amortized time complexity
Greedy algorithm * Modular multiplication Brute-force with pruning
Scheduling * Modular inverses Best-first (A*)
Max contiguous subvector sum * Modular exponentiation by squaring Bidirectional search
Chinese remainder theorem Iterative deepening DFS / A*
Invariants Fermat’s little theorem Data structures
Huffman encoding Euler’s theorem LCA (2^k-jumps in trees in general)
Graph theory Phi function Pull/push-technique on trees
Dynamic graphs (extra book-keeping) Frobenius number Heavy-light decomposition
Breadth first search Quadratic reciprocity Centroid decomposition
Depth first search Pollard-Rho Lazy propagation
* Normal trees / DFS trees Miller-Rabin Self-balancing trees
Dijkstra’s algorithm Hensel lifting Convex hull trick (wcipeg.com/wiki/Convex_hull_trick)
MST: Prim’s algorithm Vieta root jumping Monotone queues / monotone stacks / sliding queues
Bellman-Ford Game theory Sliding queue using 2 stacks
Konig’s theorem and vertex cover Combinatorial games Persistent segment tree
Min-cost max flow Game trees
Lovasz toggle Mini-max
Matrix tree theorem Nim
Maximal matching, general graphs Games on graphs
Hopcroft-Karp Games on graphs with loops
Hall’s marriage theorem Grundy numbers
Graphical sequences Bipartite games without repetition
Floyd-Warshall General games without repetition
Euler cycles Alpha-beta pruning
Flow networks Probability theory
* Augmenting paths Optimization
* Edmonds-Karp Binary search
Bipartite matching Ternary search
Min. path cover Unimodality and convex functions
Topological sorting Binary search on derivative
Strongly connected components Numerical methods
2-SAT Numeric integration
Cut vertices, cut-edges and biconnected components Newton’s method
Edge coloring Root-finding with binary/ternary search
* Trees Golden section search
Vertex coloring Matrices
* Bipartite graphs (=> trees) Gaussian elimination
* 3^n (special case of set cover) Exponentiation by squaring
Diameter and centroid Sorting
K’th shortest path Radix sort
Shortest cycle Geometry
Dynamic programming Coordinates and vectors
Knapsack
Coin change * Cross product
Longest common subsequence * Scalar product
Convex hull
Longest increasing subsequence Polygon cut
Number of paths in a dag Closest pair
Shortest path in a dag Coordinate-compression
Dynprog over intervals Quadtrees
Dynprog over subsets KD-trees
Dynprog over probabilities All segment-segment intersection
Dynprog over trees Sweeping
3^n set cover Discretization (convert to events and sweep)
Divide and conquer Angle sweeping
Knuth optimization Line sweeping
Convex hull optimizations Discrete second derivatives
RMQ (sparse table a.k.a 2^k-jumps) Strings
Bitonic cycle Longest common substring
Log partitioning (loop over most restricted) Palindrome subsequences
Combinatorics

You might also like