蒟蒻の模板
蒟蒻 Rainbow-Automaton 的模板
只是目前会的
然而目前啥也不会…
代码注意事项
不要使用
using namespace std;min和max都可以直接std::minstd::max吧关同步
#define fastread std::ios_sync_with_stdio (false); std::cin.tie (nullptr);upd: 更为简洁的写法是
std::cin.tie(nullptr) -> sync_with_stdio(false);学习 jiangly
using i64 = long long
杂项
对拍
1 | inline bool pai () { |
毫秒级随机数
通常作为对拍时的随机数生成器
1 | std::mt19937 rng(std::chrono::steady_clock::now ().time_since_epoch ().count ()); |
计时
防止 TLE
1 | inline void getTime () { |
图论
存图
这种东西真的需要记吗
写一个神秘的封装好的图
1 | template<int maxn, int maxm> |
然而我大部分时侯都不会用到封装好的图…
一般情况下只会直接写 Graph 里面的东西
最短路
Dijkstra
1 | struct Node { |
某个广为人所知的最短路算法
判负环
不判负环最好别用
才发现我单源最短路都是用 Dijkstra 过的
甚至找不到一个SPFA的板子
1 | std::queue<int> q; |
差分约束
也许是唯一能用上SPFA的地方吧…
可以解出
自然也可以判断是否有解
实质就是
1 | inline void diff_constraints () { // 差分约束 |
Floyd
1 | int dis[maxn][maxn]; |
注意先 init() 再加边
倍增Floyd
实际上是矩阵快速幂
把
改为用
显然
然后我们发现转移的过程和矩阵乘法特别像
用快速幂求出
传递闭包
实际上就是
只是求最短路改成求连通性了
1 | std::bitset<maxn> a[maxn]; |
上面的代码是用
bitset写的, 与传统略有不同 但是其基本思想是类似的
生成树
Kruskal
1 | struct Edge { |
其中
init()就是并查集的init()并查集的写法看数据结构部分吧
欧拉回路
一定要加当前弧优化!
否则复杂度其实是假的
依然记得在mx想出正解但是欧拉回路写挂了
1 | std::vector<int> g[maxn]; |
upd: 换一个更人性的写法
1 | std::vector <int> g[maxn]; |
upd: 判断
有向图欧拉路径的判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15bool check () {
int dcnt1 = 0;
int dcnt2 = 0;
for (int i = 1; i <= tot; i++) {
if (ind[i] - otd[i] == 0) { continue; }
if (ind[i] - otd[i] == 1) { dcnt1 ++; continue; }
if (ind[i] - otd[i] == -1) { dcnt2 ++; start = i; continue; }
return false;
}
if (dcnt1 > 1 or dcnt2 > 1 or dcnt1 + dcnt2 == 1) { return false; }
}判断是否存在无向图欧拉回路 : 是否所有点入度等于出度
最后记得判断求出来的长度是否合法
Tarjan 系列
强连通分量
对于一个有向图, 一个强连通分量
1 | int low[maxn], dfn[maxn], dpos; |
2-SAT
用
用
1 | for (int i = 1; i <= 2 * n; i++) { |
割点
1 | int low[maxn], dfn[maxn], dpos; |
点双连通分量
1 | int low[maxn], dfn[maxn], dpos; |
桥
1 | int low[maxn], dfn[maxn], dpos; |
因为涉及到快速找反向边, 一定要把
cnt初始化为1!
边双连通分量
1 | int low[maxn], dfn[maxn], dpos; |
网络流
网络流的加边方式与普通图论问题的加边方式略有不同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 struct Edge {
int u, v;
int pre;
long long flow;
} es[maxm << 1];
int last[maxn], cur[maxn], cnt = 1;
int S, T;
inline void _addEdge (int u, int v, long long cap) {
es[++cnt] = Edge { u, v, last[u], cap };
last[u] = cnt;
}
inline void addEdge (int u, int v, long long cap) {
_addEdge (u, v, cap);
_addEdge (v, u, 0);
}
Dinic
1 | int dep[maxn]; |
网络单纯形
把之前写的代码粘过来了
码风可能有点不太一样
而且好像使用
然而我学网络单纯形的时候并不会lct
1 | const long long inf = 1e9; |
字符串
啥也不会
前缀函数
1 | inline std::vector<int> get_pi(const std::string &s) { |
AC 自动机
就是前缀自动机
1 | template <int maxn> |
后缀自动机
1 | struct SAM { |
Manacher
1 | f[1] = 1; |
回文自动机
1 | namespace Palindrome_Automaton { |
数学
预处理约数
才发现先前对每个数分别处理约数的做法这么唐。
考虑贡献即可。
1 | rep (d, 1, n) |
预处理质因数
其实是埃氏筛。
1 |
|
Miller-Rabin
1 | inline bool test(i64 a, i64 p) { |
快速幂
1 | i64 ksm (i64 a, i64 b, i64 mod) { |
欧拉函数
1 | i64 phi (i64 n) { |
逆元
这里使用欧拉函数求逆元
不会写exgcd导致的
你说的对, 但是
所以我们可以直接求逆元
1 | i64 inv (i64 a, i64 b) { |
exgcd
1 | i64 exgcd (i64 a, i64 b, i64 &x, i64 &y) { |
于是, 上面的逆元也可以用exgcd求
因为
所以我们很容易用exgcd求出
1 | inline i64 inv (i64 a, i64 b) { |
线性筛
1 | std::bitset<maxn> not_prime; |
筛莫比乌斯函数
用线性筛筛出莫比乌斯函数
顺便求出前缀和
1 | inline void get_mu () { |
中国剩余定理
只会大数翻倍法
所以这其实是假的中国剩余定理
orz钟神太强了%%%
1 | inline bool merge (i64 &m1, i64 &a1, i64 m2, i64 a2) { |
真的超级好写啊啊啊
upd: 判无解版本:
1 | inline bool merge (i64& m1, i64& a1, i64 m2, i64 a2) { |
扩展中国剩余定理
不用害怕, zhx的大数翻倍法本身就能合并两个同余方程
所以合并部分代码跟上面一样。
蓝的盆。我先前咋这么唐。
其实是平凡的。
骗小朋友的代数 trick 罢了。
1 | using Equation = std::pair<i64, i64>; |
高维前缀和
1 | for (int i = 0; i < 22; i++) { |
异或线性基
1 | struct Basis { |
模意义下线性基
1 | inline bool ins(Vector a) { |
高斯消元
1 | f64 a[maxn][maxn]; |
多项式
NTT
1 | namespace NTT { |
Stern–Brocot 树
1 | void dfs(f64 X, int a, int b, int c, int d) { |
Prufer 序列
1 | namespace Decoder { |
数据结构
并查集
1 | template <int maxn> |
树状数组
1 | template <int maxsiz> |
上面只给出了单点加区间求和的版本
实际上, 树状数组还可以通过神秘的技术实现区间加单点查和 区间加区间求和
甚至可以通过跳
lowbit实现 区间最值查询然而实现十分复杂, 失去了树状数组本身简洁的优势
而且复杂度好像也不是很对(曾被hzhl狠狠质疑)所以不如写线段树 👇
线段树
1 | template <int maxn, typename val_t> |
使用的时候, 只需要
SegmentTree<maxn, i64> tr就行
+*标记
1 | using tag = std::pair<i64, i64>; |
权值线段树
其实是动态开点线段树
1 | template <int maxn, typename val_t> |
可持久化线段树
可持久化数组
1 | template <int maxn, typename val_t> |
01-trie
普通 01-trie
其实就是普通 01-trie
1 | struct Trie { |
查询 k 大 01-trie
与平衡树 / 值域线段树很像
1 | struct Trie { |
可持久化 01-trie
1 | struct Trie { |
平衡树
FHQ-Treap
普通平衡树
1 | template <int maxn, typename val_t> |
文艺平衡树
其实就是维护中序遍历
1 | struct Node { |
可持久化平衡树
其实跟可持久化线段树本质相同
似乎算导上讲过数据结构可持久化的通用方法
1 | struct Node { |
树套树
树状数组套线段树
1 | struct FenwickTree { |
笛卡尔树
神秘科技
1 | inline int build () { |
树
树链剖分
核心部分代码不长
1 | int fa[maxn], siz[maxn], son[maxn], dep[maxn]; |
子树内的信息
一般会像上面注释里面一样维护一个 bottom[u] 表示以
然后就可以
1 | inline i64 subtreeQuery (int x) { |
修改同理
路径上的信息
直接跳链即可
1 | inline void chainModify (int x, int y, i64 val) { |
查询同理
lca
同样是直接跳链
1 | inline int lca (int u, int v) { |
Link-Cut Tree
1 | struct Node { |
点分治
淀粉质
1 | inline void addEdge (int u, int v, int w) { |
- Title: 蒟蒻の模板
- Author: rainbow-auto
- Created at : 2023-10-02 22:01:54
- Updated at : 2025-11-24 22:48:20
- Link: https://rainbow-auto.github.io/2023/10/02/蒟蒻の模板/
- License: This work is licensed under CC BY-NC-SA 4.0.