Loading docs/basic/prefix-sum.md +1 −1 Original line number Diff line number Diff line Loading @@ -308,7 +308,7 @@ $$ \begin{aligned} &d_s\leftarrow d_s+1\\ &d_t\leftarrow d_t+1\\ &d_{lca}\leftarrow d_{lca}-2\\ &d_{lca}\leftarrow d_{lca}-2\\ \end{aligned} $$ Loading docs/ds/divide-combine.md +1 −1 Original line number Diff line number Diff line Loading @@ -108,7 +108,7 @@ $$ 1. 我们先判断它能否成为栈顶结点的儿子,如果能就变成栈顶的儿子,然后把栈顶取出,作为当前结点。重复上述过程直到栈空或者不能成为栈顶结点的儿子。 2. 如果不能成为栈顶的儿子,就看能不能把栈顶的若干个连续的结点都合并成一个结点(判断能否合并的方法在后面),把合并后的点,作为当前结点。 3. 重复上述过程直到不能进行为止。然后结束此次增量,直接把当前结点圧栈。 3. 重复上述过程直到不能进行为止。然后结束此次增量,直接把当前结点压栈。 接下来我们仔细解释一下。 Loading docs/ds/queue.md +1 −1 Original line number Diff line number Diff line Loading @@ -48,7 +48,7 @@ int q[SIZE], ql = 1, qr; 我们使用两个栈 F,S 模拟一个队列,其中 F 是队尾的栈,S 代表队首的栈,支持 push(在队尾插入),pop(在队首弹出)操作: 1. Push:插入到栈 F 中 2. Pop:如果 S 非空,让 S 弹栈;否则把 F 的元素倒过来圧到 S 中(其实就是一个一个弹出插入,做完后是首位颠倒的),然后再让 S 弹栈。 2. Pop:如果 S 非空,让 S 弹栈;否则把 F 的元素倒过来压到 S 中(其实就是一个一个弹出插入,做完后是首位颠倒的),然后再让 S 弹栈。 容易证明,每个元素只会进入/转移/弹出一次,均摊复杂度 $O(1)$ 。 Loading docs/string/sam.md +1 −1 Original line number Diff line number Diff line Loading @@ -170,7 +170,7 @@ $$ - 如果 $\operatorname{len}(p)+1=\operatorname{len}(q)$ ,我们只要将 $\operatorname{link}(\textit{cur})$ 赋值为 $q$ 并退出。 - 否则就会有些复杂。需要 **复制** 状态 $q$ :我们创建一个新的状态 $\textit{clone}$ ,复制 $q$ 的除了 $\operatorname{len}$ 的值以外的所有信息(后缀链接和转移)。我们将 $\operatorname{len}(\textit{clone})$ 赋值为 $\operatorname{len}(p)+1$ 。 复制之后,我们将后缀链接从 $\textit{cur}$ 指向 $\textit{clone}$ ,也从 $q$ 指向 $\textit{clone}$ 。 最终我们需要使用后缀链接从状态 $p$ 往回走,只要存在一条通过 $p$ 到状态 $q$ 的转移,就将该转移重定向到状态 \\textit{ $}clone$ 。 最终我们需要使用后缀链接从状态 $p$ 往回走,只要存在一条通过 $p$ 到状态 $q$ 的转移,就将该转移重定向到状态 $\textit{clone}$ 。 - 以上三种情况,在完成这个过程之后,我们将 $\textit{last}$ 的值更新为状态 $\textit{cur}$ 。 如果我们还想知道哪些状态是 **终止状态** 而哪些不是,我们可以在为字符串 $s$ 构造完完整的 SAM 后找到所有的终止状态。为此,我们从对应整个字符串的状态(存储在变量 $\textit{last}$ 中),遍历它的后缀链接,直到到达初始状态。我们将所有遍历到的节点都标记为终止节点。容易理解这样做我们会准确地标记字符串 $s$ 的所有后缀,这些状态都是终止状态。 Loading Loading
docs/basic/prefix-sum.md +1 −1 Original line number Diff line number Diff line Loading @@ -308,7 +308,7 @@ $$ \begin{aligned} &d_s\leftarrow d_s+1\\ &d_t\leftarrow d_t+1\\ &d_{lca}\leftarrow d_{lca}-2\\ &d_{lca}\leftarrow d_{lca}-2\\ \end{aligned} $$ Loading
docs/ds/divide-combine.md +1 −1 Original line number Diff line number Diff line Loading @@ -108,7 +108,7 @@ $$ 1. 我们先判断它能否成为栈顶结点的儿子,如果能就变成栈顶的儿子,然后把栈顶取出,作为当前结点。重复上述过程直到栈空或者不能成为栈顶结点的儿子。 2. 如果不能成为栈顶的儿子,就看能不能把栈顶的若干个连续的结点都合并成一个结点(判断能否合并的方法在后面),把合并后的点,作为当前结点。 3. 重复上述过程直到不能进行为止。然后结束此次增量,直接把当前结点圧栈。 3. 重复上述过程直到不能进行为止。然后结束此次增量,直接把当前结点压栈。 接下来我们仔细解释一下。 Loading
docs/ds/queue.md +1 −1 Original line number Diff line number Diff line Loading @@ -48,7 +48,7 @@ int q[SIZE], ql = 1, qr; 我们使用两个栈 F,S 模拟一个队列,其中 F 是队尾的栈,S 代表队首的栈,支持 push(在队尾插入),pop(在队首弹出)操作: 1. Push:插入到栈 F 中 2. Pop:如果 S 非空,让 S 弹栈;否则把 F 的元素倒过来圧到 S 中(其实就是一个一个弹出插入,做完后是首位颠倒的),然后再让 S 弹栈。 2. Pop:如果 S 非空,让 S 弹栈;否则把 F 的元素倒过来压到 S 中(其实就是一个一个弹出插入,做完后是首位颠倒的),然后再让 S 弹栈。 容易证明,每个元素只会进入/转移/弹出一次,均摊复杂度 $O(1)$ 。 Loading
docs/string/sam.md +1 −1 Original line number Diff line number Diff line Loading @@ -170,7 +170,7 @@ $$ - 如果 $\operatorname{len}(p)+1=\operatorname{len}(q)$ ,我们只要将 $\operatorname{link}(\textit{cur})$ 赋值为 $q$ 并退出。 - 否则就会有些复杂。需要 **复制** 状态 $q$ :我们创建一个新的状态 $\textit{clone}$ ,复制 $q$ 的除了 $\operatorname{len}$ 的值以外的所有信息(后缀链接和转移)。我们将 $\operatorname{len}(\textit{clone})$ 赋值为 $\operatorname{len}(p)+1$ 。 复制之后,我们将后缀链接从 $\textit{cur}$ 指向 $\textit{clone}$ ,也从 $q$ 指向 $\textit{clone}$ 。 最终我们需要使用后缀链接从状态 $p$ 往回走,只要存在一条通过 $p$ 到状态 $q$ 的转移,就将该转移重定向到状态 \\textit{ $}clone$ 。 最终我们需要使用后缀链接从状态 $p$ 往回走,只要存在一条通过 $p$ 到状态 $q$ 的转移,就将该转移重定向到状态 $\textit{clone}$ 。 - 以上三种情况,在完成这个过程之后,我们将 $\textit{last}$ 的值更新为状态 $\textit{cur}$ 。 如果我们还想知道哪些状态是 **终止状态** 而哪些不是,我们可以在为字符串 $s$ 构造完完整的 SAM 后找到所有的终止状态。为此,我们从对应整个字符串的状态(存储在变量 $\textit{last}$ 中),遍历它的后缀链接,直到到达初始状态。我们将所有遍历到的节点都标记为终止节点。容易理解这样做我们会准确地标记字符串 $s$ 的所有后缀,这些状态都是终止状态。 Loading