板子复习

三分

P1883

注意你的目标函数必须是严格单峰的,途中不能出现平着的一段。

大体思想就是取两个三等分点。

KMP

P3375

先求出 \(\pi\) 函数。

注意完全匹配上了之后要强制让 \(j=\pi_j\)

笛卡尔树

P5854

考虑从左往右挨个加数,维护一个一直往右的右链,每次暴力往上找即可。

欧拉路径

P7771

首先有向图存在欧拉路径的充要条件是所有点都入度=出度,或者存在恰好一对点,一个入度比出度少 \(1\),另外一个相反。

对于前者可以随便选一个点当作起点;对于后者则必须选入度比出度少 \(1\) 的那个。

考虑构造一条路径。考虑每次找到一个环,然后以环上每个点作为起点继续找环。容易发现这样一定可以。

那更简单的做法是什么呢?考虑在对环回溯的时候找环。最后把整个序列 reverse,就得到了欧拉路径。

为什么正着走的时候直接找不行呢?很显然你回溯的时候经过的不是边,而是反的边。

连通性相关

你真的搞明白连通性了吗?

OI 中我们常用的连通性算法有 SCC、ECC、VCC、割点、割边。

而这些都基于 DFS 算法。通过分析 DFS 的非树边类型,就可以求解上述问题。

在这些算法中我们都定义了 \(\operatorname{dfn}_u\)\(\operatorname{low}_u\)。然而大家可能会有一个疑问:为什么在非树边时 \(\operatorname{low}_u\) 要对 \(\operatorname{dfn}_v\) chkmin,而不是 \(\operatorname{low}_v\) 呢?

经过一些测试可以发现,只有点连通性相关问题需要 \(\operatorname{dfn}_v\)。为什么?考虑一个图:

1---2---3---5---6
     \ /     \ /
      4       7

如果不严格指定只能走一条非树边,那么 \(\operatorname{low}_6=1\),而这会导致 \(\{5,6,7\}\) 不能被判定为一个点双。显然会出错。

根本原因在于,走一条非树边可能会走到这个点双的根节点,而再走是不行的。

SCC:P3387

注意需要记录一个点是否在栈中。在才能转移。这是显然的。因为这是有向图,所以只有返祖边才有用。

ECC:P8436

注意记录的是入边的编号,而且邻接表要从 \(2\) 开始存。这里就不用必须是返祖边,所以不用记录一个栈。

割点:P3388

注意要对 \(u\) 为搜索树的根特判。

VCC:P8435

注意这里也要记录一个栈,是为了快速找到一个点双里的所有节点。当然如果你边双想这么写也没问题。

注意一个孤立点的情况。注意孤立点上有自环是没用的。(实际上自环根本就没用)

注意弹栈的时候判的是栈顶不等于 \(v\),最后别忘了把 \(u\) 加进去。

Manacher

P3805

要处理长度为奇数和偶数的回文串,比较恶心。可以考虑每隔一个字符插入一个分隔符,最后在开头和末尾插入两个不一样的字符。这样只需要统计长度为奇数的回文串。

有人认为这样常数太大了,实际上完全没有影响。就算你算两遍那也还是两倍常数。

核心思想是维护一个最靠右的回文串,每次暴力往右扩展复杂度是对的。

差分约束

P5960

转化之后是单源负权最短(长)路问题。

可以使用 SPFA 解决。注意判负环时,要考虑超级源点,点个数是 \(n+1\)

Johnson 全源最短路

P5905

复杂度为 \(O(nm\log m)\)

大概是先用 SPFA 跑出来一个势能。然后在这上面跑 Dijkstra。

需要注意的是判负环时,要考虑超级源点,点个数是 \(n+1\)

单侧递归线段树

P4198

核心思想在于 pushup 需要的信息是由线段树上二分给出的。

需要注意贡献的情况。

posted @ 2025-10-30 20:31  Linge_Zzzz  阅读(8)  评论(0)    收藏  举报