Classic Wrongs
Data Structure
-
线段树 / 可并堆合并,没有写
rt[u] = merge(rt[u], rt[v])
,写了merge(rt[u], rt[v])
。 -
0-1 Trie:
next[pos][key >> i & 1]
, 不是next[pos][key & (1 << i)]
!!!
-
线段树
-
可能会出现 modify / query 操作中的 \(l > r\) 的情况,这时应小心,在线段树内写上判断或在函数调用前判断是否合法。e.g #2055. 「TJOI / HEOI2016」排序, AC & RE, 注意
check
函数的差别。 -
注意变量名!尤其是
t
和r
!最好用别的变量名!变量名很容易写错! -
如果线段树里是矩阵这类的,最好别开结构体。因为用了结构体后似乎很容易 MLE!最好 \(O(n)\) 建树!e.g. P6021 AC vs MLE.
-
动态开点如果不要紧,空间能开多大开多大。到底有几次
modify
可能会算错,或根本没算!e.g. P5163, AC vs RE. -
动态开点线段树常数极大(离散化后树状数组的效率是其的 \(10\) 倍以上),用之前看看树状数组能不能用。24/12/21 ABC384G 本机调试 sgt 6s, fwk 0.3s.
-
线段树记得
pushdown
。e.g. CF407E -
线段树清空的时候,
tag[u] = 0
的位置不要放错!e.g. CF407E -
动态开点线段树的 \(0\) 号节点的值要设成零元。e.g. QOJ 7884.
-
-
Persistent Segment Tree
-
fenwick
-
并查集
-
ST 表
- 迭代预处理时
rmq[i - 1][j + (1 << (i - 1))]
忘记写后面那个-1
。
- 迭代预处理时
-
左偏树
- 千万不要空的一个
merge(u, v)
!应该写成这样:u = merge(u, v)
!
- 千万不要空的一个
-
扫描线
- 注意线和点的添加顺序!
-
Hash
Math
-
Number Theory
-
数字批处理因数时再也不要一个一个 \(O(\sqrt{n})\) 了!要么 \(O(n \log n)\) 预处理,要么枚举倍数!
-
\(O(\sqrt{n})\) 分解质因数时要判断最后剩下的数是否是质数。
-
CRT
- 各种 CRT 最后的结果是一个同余方程的最小非负整数解,并不能代表返回的值是一个确定的数。e.g. P2480 #13
-
-
数数
-
选取顺序不影响种类的计数不能直接乘法原理,需要组合计数。
-
数数一定要注意不重不漏!
-
-
概率
- 注意考虑贡献的独立性。
-
矩阵
-
\((\min, +)\) 矩阵乘法,单位矩阵是除了对角是 \(0\) 其它都是 \(+\infty\)!千万注意到底要用 \(0\) 还是 \(+\infty\)!
-
如果开了很多矩阵,最好不要用
vector
。因为vector
的空间是预留的!e.g. P6021.
-
-
多项式
-
FFT
- 三次变两次优化,最后是
F[i].imag() / 2
。
- 三次变两次优化,最后是
-
Algorithm
-
DP
-
DP 不初始化。
-
状压 DP 检查状态与地形是否相符时应为
(sta >> i - 1) & 1)
,写成(sta >> i - 1)
。 -
分组背包注意循环顺序:先枚举组,再枚举空间,最后枚举组里的物品。
-
斜率优化时可能需要加入一个 \(0\) 号状态表示凸包的起始点。e.g. 「HNOI2008」玩具装箱 因为没这样连 WA 四发。
-
斜率优化算斜率时可能需要用
long double
把斜率算出来再比较,此时把除法改成乘法来提高精度可能会爆long long
。e.g. 「HNOI2008」玩具装箱 的 这个讨论。 -
你的 DP 在算什么?如何求出最终结果?是 \(dp_n\),还是 \(\max dp\) 之类?e.g. ABC353G
-
滚动数组记得状态的继承。
-
-
Search
-
对于 DFS,不要觉得某些变量、数组不用清零。能清零就清零!example: P1074, line 58
-
如果二分的上界达到 \(10^9\),那 \(l, r, mid\) 都要开
long long
。
-
-
Binary Lifting
-
Binary Search
- 二分范围要稍微调大一点,保证答案正确。建议至少调大 \(50\)。e.g. ABC346F 看最新 \(6\) 发提交倒数 \(10\) 来行 \(r\) 的初始值
Gragh
-
BCC & SCC
-
缩点后,CC 之间可能存在大量重边,这些重边必须去重!不然当 DFS 时,我们会因访问同一个节点多次而 TLE。example: CF1000E
-
该打标记表示已经访问过的点忘记打标记。
-
缩点后点的数量是
bcc
/scc
而不是n
。 -
缩点后做拓扑排序,如果终点确定,要不管终点的路径上不会存在的 SCC。#2590
-
对原图进行一定操作后(如删边、缩点),再进行某些统计时,不能用原图(
ve G[N]
),应该用操作后的图(如ve DAG[N]
)。
-
-
Bipartite Graph
-
MST
-
Other
-
遇到负边权要谨慎。
-
你的边数可能不是输入的 \(m\)!比如有时你除了输入的边外又加了一些边!e.g. P7624, line 5 in
check
.
-
Tree
-
LCA
-
Heavy-light Decomposition
-
树剖时忘记
siz[u] += siz[v]
。 -
有多测时,要清空
hs
数组。e.g. #2562. 「SDOI2018」战略游戏 AC & MLE, line 214(倒数 13 行)
-
-
点分树
- 点分树与原树没有丝毫关系!自顶向下就要考虑原树了!e.g. ZJOI2015 幻想乡战略游戏.
String
STL / std 函数 / 一些语法
-
vector
的下标应该从 \(0\) 开始,别手滑打成 \(1\)。 -
使用
vector
时请用fsanitize
检查越界,防止神秘问题。 普通模式下是看不出来的! -
stack
和deque
底层是一个东西,当你开 \(10^6\) 个stack
或deque
时,你将……需要4GB
的空间以及……爆零……这时,应该换成vector
或list
。 -
如果想从
priority_queue
里删掉不满足某些条件的元素,不能直接while(!Q.empty() && Q.top() ... ) Q.pop()
,这样的话可能堆顶刚好满足,但堆的其它元素却不满足,然后就寄了。 -
set
与multiset
的erase(T x)
都是把和X
相等的元素全部删除。如果要控制,需要eg.erase(eg.find(x))
。 -
memset
时,如果你想清空前 \(n\) 个数,请先想一想,你使用的是下标为 \([0, n)\) 的数组还是 \((0, n]\) 的。不然其实你没有清空干净。e.g. #2562. 「SDOI2018」战略游戏 AC & WA, line 185(倒数 11 行) -
基于范围的
for
循环一定要加上&
!不然根本做不了丝毫修改!e.g. AC vs strange error. -
检查你
sort
的cmp
有没有写错!要是比较方式错了 / 打错了字符可能导致 RE! -
注意
rbegin
的prev
和next
和正常迭代器是反过来的!
计算几何
杂项
离线
策略
-
想完一个做法不会想另一种。Turing Cup #6(2024) 因此输麻了,A 题都没过(优先队列比二分还好写)。
-
想出一个做法前一定要检验正确性!
多测
-
清空不完毕,爆零两行泪。e.g. CF2025E, AC vs WA,
val
没清空. 求求了,多memset
几下不会死的/ll -
一定要测书规模乱序的情况!e.g. 上面那个例子,把样例复制两遍后直接 WA 掉.
Other
-
三年 OI 一场梦,不开
long long
见祖宗。 -
n
与m
,i
与j
,u
与v
写反。 -
「常错」 数组开小(可能还会 \(\mathsf{ \color{red}WA}\))。数组还是很有必要开大的。
-
没测极限数据,
long long
也爆了。要测极限数据!example: P3868 -
「常错」 做法太复杂。
-
没删调试信息。
-
求 \(\min\) 要赋初值,有负数时求 \(\max\) 要先赋 \(-\infty\)。
-
不要用
read()
读long long
!记得用readl()
! -
搞随机的时候,
uniform_int_distribution < int > gen(1, (ull) - 1)
。(ull
赋值到int
) -
注意 \(<\) 还是 \(\le\)?你的写法针对了哪一种?
-
对拍完一定要测样例!不然可能爆零了!
-
如果用一个
bool
数组记录答案行不行,而且答案分很多方面计算,那么注意每一次都是ok[i] |= clause
!如果写成了ok = clause
…… e.g. ABC385D, AC vs WA. -
如果是 index-0 的数组,一些辅助数组的初始值可能是 \(-1\)。e.g. CF407E
-
变量最好要全部初始化!尤其模板里,不然你也不清楚这个变量最后是局部的还是全局的!e.g. 25/1/23 treap 模板里 ch 没初始化,调了 45min+。
-
如果要把坐标转化成 index,且一行有 \(m\) 个数,那么 \(id = (x - 1)\red m + y - 1\),而不是 \((x - 1)n + y - 1\)。e.g. P2774, AC vs WA.
-
千万不要偷懒混用
cout
和printf
!千万!不然什么输出顺序,你不知道!e.g. P6054, AC vs WA. -
「常错」 不要试图去改编某个功能的一个部分实现另一个功能(比如线段树,加个
s == t
的特判做别的事)。e.g. QOJ 7884, Code, 看void insert
旁边的字. -
取模不要忘记处理负数!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!