常见 OI 算法模板
天不遂人愿,事常逆己心。
无论如何,先继续向前走吧。
快速读入(数字) Fast Input
1 | inline int read() { |
字符串处理 String Processing
KMP
单模式串匹配算法。
1 | int n, m; |
AC 自动机 AC Automaton
KMP + Trie。多模式串匹配算法。
后缀自动机 Suffix Automaton
处理字串 (尤其是后缀) 问题的强力数据结构。
最小表示法 Minimal Expression
字符串所有循环同构串中字典序最小的一个称为该字符串的最小表示法。
1 | string getCore(string str) { |
线段树 Segment Tree
带懒标记 (lazy tag) 维护区间和的线段树。支持:
- 区间 \(+k\)
- 区间求和
1 | int n, m; |
树状数组 Fenwick Tree
可用线段树完全替代。但写法简单,时空代价低,此模板支持:
- 动态维护前缀和
1 | int a[MAX_N]; |
平衡搜索树 Balanced Search Tree
Splay
自平衡的伸展树。支持:
- 插入 \(x\)
- 删除 \(x\) (若有多个 \(x\),仅删除一个)
- 查询 \(x\) 的排名
- 查询排名为 \(k\) 的数
- 查询 \(x\) 的前驱
- 查询 \(x\) 的后继
1 | int root; |
Treap
BST Tree + Heap。这里的模板是非旋转的 FHQ Treap 版本。
最短路算法 Shortest Path
Dijkstra
堆优化的单源最短路算法。复杂度 \(O((n+m)\log{n})\),无法处理负权边。
1 | int head[MAX_N]; |
SPFA
队列优化的 Bellman-Ford-Moore 的单源最短路算法,最坏复杂度 \(O(nm)\),可以处理负权边。
SPFA 算法也可以用来判断图中是否有负权边。
1 | int dis[MAX_N]; |
Floyd
能求出任意点对间的最短路,复杂度 \(O(n^3)\)。能处理负权边。
1 | for (int k = 1; k <= n; ++k) { |
最小生成树 Minimum Spanning Tree
Kruskal
基于贪心的最小生成树算法,复杂度 \(O(m\log{m})\)。
将边按权从小到大排序,依次加入初始为空的生成树。若某次加边产生了环 (用并查集维护连通块关系),就舍弃这条边,直到成功加入了 \(n-1\) 条边。
Prim
与 Kruskal 不同,Prim 维护的是点集而不是边集。复杂度 \(O((n+m)\log{n})\)。
每次选择离点集最近的点更新距离,并将其加入点集。
最近公共祖先 Lowest Common Ancestor
倍增求 LCA。预处理复杂度 \(O(n\log{n})\),单次查询复杂度 \(O(\log{n})\)。
1 | int fa[MAX_N][15]; |
计算几何 Computational Geometry
凸包 Convex Hull
Andrew 算法求凸包,使用单调栈分开求上下凸壳,避免了 Graham 算法的精度问题。复杂度 \(O(n\log{n})\)。
该模板将输出凸包上所有的点。
1 | struct Point { |
数论 Number Theory
扩展欧几里得算法 Extended Euclidean Algorithm
对于方程 \(ax+by=d\),其中 \(d=\gcd(a,b)\),扩欧能够求出该方程的一组可行解。
1 | int Exgcd(int a, int b, int& x, int& y) { |
对于方程 \(ax+by=c \ \ (d|c)\),我们先用扩欧求出 \(ax+by=d\) 的一组解 \(x',y'\)。令 \(T=\frac{b}{d}\),原方程 \(x\) 的最小正整数解为 \(x_1=\frac{c}{d}x'\mod{T}\).
欧拉筛 Euler's Sieve
欧拉筛线性筛质数。
1 | vector<int> prime; |
欧拉函数 Euler's Totient
\(\varphi(n)\) 表示的是小于等于 \(n\) 与 \(n\) 互质的数的个数。当 \(n\) 为质数时显然有 \(\varphi(n)=n-1\)。
筛法求欧拉函数如下:
1 | vector<int> prime; |
杂项 Miscellaneous
STL::set
set 与 multiset 的用法。
insert(const g)
erase(const g/iterator pos)
count(const g)
在 set 中只有 0/1 两种结果find(const g)
返回 iterator,若没找到返回end()
lower_bound(const g)
upper_bound(const g)
STL::bitset
bitset 的用法。定义 bitset<10000>
(长度为 10000 的
bitset)。
count()
返回 true 的数量set(pos, val = true/false)
set()
[无参数] 将 bitset 重置为 truereset(pos)
相当于set(pos, val = false)
reset()
[无参数] 将 bitset 重置为 falseflip(pos)
flip()
[无参数] 翻转每一位- operators
[]
,==/!=
,&/&=
,|/|=
,^/^=
,~
,<</<<=
,>>/>>=
.
离散化 Discretization
很经典的 technique,能够有效缩小 data scale。复杂度 \(O(n\log{n})\)。
1 | for (int i = 1; i <= n; ++i) t[i] = a[i]; |