OSDN Git Service

style: format markdown files with remark-lint
author24OI-bot <15963390+24OI-bot@users.noreply.github.com>
Wed, 21 Nov 2018 06:40:14 +0000 (14:40 +0800)
committer24OI-bot <15963390+24OI-bot@users.noreply.github.com>
Wed, 21 Nov 2018 06:40:14 +0000 (14:40 +0800)
docs/ds/persistent-balanced.md
docs/ds/sparse-table.md

index c355845..40f944e 100644 (file)
@@ -32,24 +32,24 @@ Split-Merge Treap
 
 在复制一个节点 $X_{a}$($X$ 节点的第 $a$ 个版本) 的新版本 $X_{a+1}$ ($X$ 节点的第 $a+1$ 个版本) 以后:
 
-- 如果某个儿子节点 $Y$ 不用修改信息,那么就把 $X_{a+1}$ 的指针直接指向 $Y_{a}$ ($Y$ 节点的第 $a$ 个版本) 即可。
-- 反之,如果要修改 $Y$ ,那么就在**递归到下层**时**新建** $Y_{a+1}$ ($Y$ 节点的第 $a+1$ 个版本) 这个新节点用于**存储新的信息**,同时把 $X_{a+1}$ 的指针指向 $Y_{a+1}$ ($Y$ 节点的第 $a+1$ 个版本)。
+-   如果某个儿子节点 $Y$ 不用修改信息,那么就把 $X_{a+1}$ 的指针直接指向 $Y_{a}$ ($Y$ 节点的第 $a$ 个版本) 即可。
+-   反之,如果要修改 $Y$ ,那么就在**递归到下层**时**新建** $Y_{a+1}$ ($Y$ 节点的第 $a+1$ 个版本) 这个新节点用于**存储新的信息**,同时把 $X_{a+1}$ 的指针指向 $Y_{a+1}$ ($Y$ 节点的第 $a+1$ 个版本)。
 
 ### 可持久化
 
 需要的东西:
 
-- 一个 struct 数组 存**每个节点**的信息 (一般叫做 tree 数组); (当然写**指针版**平衡树的大佬就可以考虑不用这个数组了)
+-   一个 struct 数组 存**每个节点**的信息 (一般叫做 tree 数组); (当然写**指针版**平衡树的大佬就可以考虑不用这个数组了)
 
-- 一个**根节点数组**,存每个版本的_树根_,每次查询版本信息时就从**根数组存的节点**开始;
+-   一个**根节点数组**,存每个版本的_树根_,每次查询版本信息时就从**根数组存的节点**开始;
 
-- split() 分裂 **从树中分裂出两棵树**
+-   split() 分裂 **从树中分裂出两棵树**
 
-- merge() 合并 **把两棵树按照随机权值合并**
+-   merge() 合并 **把两棵树按照随机权值合并**
 
-- newNode() 新建一个节点
+-   newNode() 新建一个节点
 
-- build() 建树
+-   build() 建树
 
 #### Split
 
@@ -59,8 +59,8 @@ std::pair &lt;int,int> split(x,k) 返回一个 std::pair;
 
 表示把 $_x$ 为根的树的前 $k$ 个元素放在**一棵树**中,剩下的节点构成在另一棵树中,返回这两棵树的根(first 是第一棵树的根,second 是第二棵树的)。
 
-- 如果 $x$ 的**左子树**的 $key ≥ k$,那么**直接递归进左子树**,把左子树分出来的第二颗树和当前的 x **右子树**合并。
-- 否则递归**右子树**。
+-   如果 $x$ 的**左子树**的 $key ≥ k$,那么**直接递归进左子树**,把左子树分出来的第二颗树和当前的 x **右子树**合并。
+-   否则递归**右子树**。
 
 ```c++
 static std::pair<int, int> _split(int _x, int k) {
@@ -121,17 +121,17 @@ static int _merge(int _x, int _y) {
 
 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):
 
-1. 插入 x 数
+1.  插入 x 数
 
-2. 删除 x 数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)
+2.  删除 x 数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)
 
-3. 查询 x 数的排名(排名定义为比当前数小的数的个数 + 1。若有多个相同的数,因输出最小的排名)
+3.  查询 x 数的排名(排名定义为比当前数小的数的个数 + 1。若有多个相同的数,因输出最小的排名)
 
-4. 查询排名为 x 的数
+4.  查询排名为 x 的数
 
-5. 求 x 的前驱(前驱定义为小于 x,且最大的数,如不存在输出 -2147483647)
+5.  求 x 的前驱(前驱定义为小于 x,且最大的数,如不存在输出 -2147483647)
 
-6. 求 x 的后继(后继定义为大于 x,且最小的数,如不存在输出 2147483647)
+6.  求 x 的后继(后继定义为大于 x,且最小的数,如不存在输出 2147483647)
 
 和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本(操作 3, 4, 5, 6 即保持原版本无变化)。
 
@@ -153,12 +153,12 @@ static int _merge(int _x, int _y) {
 
 ### 推荐的练手题
 
-1. luogu P3919 可持久化数组 (模板题)
+1.  luogu P3919 可持久化数组 (模板题)
 
-2. codeforces 702F T-shirt
+2.  codeforces 702F T-shirt
 
 ### 另外
 
-1. 可持久化平衡树可以用来维护动态凸包,仙人掌等东西,如果读者有兴趣可以阅读相应的 [**计算几何**](/geometry) 知识,再来食用。
+1.  可持久化平衡树可以用来维护动态凸包,仙人掌等东西,如果读者有兴趣可以阅读相应的 [**计算几何**](/geometry) 知识,再来食用。
 
-2. Zip Tree 作为一种新的数据结构在 2018.8 月由 Robert E. Tarjan -  Caleb C. Levy - Stephen Timmel 提出,可以去了解一下~
+2.  Zip Tree 作为一种新的数据结构在 2018.8 月由 Robert E. Tarjan -  Caleb C. Levy - Stephen Timmel 提出,可以去了解一下~
index 620b6ab..56d93c2 100644 (file)
@@ -121,23 +121,23 @@ LCA(Least Common Ancestors)表示最近公共祖先。
 
 对于一棵有根树,设 $LCA(u,v)=x$,则 $x$ 必须满足以下条件
 
-- $x$ 是 u 的祖先或 u
+-   $x$ 是 u 的祖先或 u
 
-- $x$ 是 v 的祖先或 v
+-   $x$ 是 v 的祖先或 v
 
-- $x$ 是在满足上面两个条件下深度最大的
+-   $x$ 是在满足上面两个条件下深度最大的
 
 显然,在一棵有根树内,对于任意两个节点有且仅有一个 $LCA$
 
 解决这个问题,我们通常有以下方法
 
-- 树上倍增(本文主要讲解此方法)
+-   树上倍增(本文主要讲解此方法)
 
-- 转化为 RMQ 问题
+-   转化为 RMQ 问题
 
-- 树链剖分
+-   树链剖分
 
-- Tarjan
+-   Tarjan
 
 ### 暴力做法
 
@@ -162,18 +162,16 @@ LCA(Least Common Ancestors)表示最近公共祖先。
 一遍 DFS 计算即可
 
 ```cpp
-void dfs(int u,int father)
-{
-       dep[u]=dep[father]+1; //dep[x] 表示 x 的深度,在查询时会用到
-       for (int i=0;i<=19;i++)
-           f[u][i+1]=f[f[u][i]][i];  // 预处理
-       for (int i=first[u];i;i=next[i])  // 链式前向星
-       {
-           int v=go[i];
-               if (v==father) continue;
-               f[v][0]=u;  //f[v][0] 表示 v 的父亲
-        dfs(v,u);      
-       }
+void dfs(int u, int father) {
+  dep[u] = dep[father] + 1;  // dep[x] 表示 x 的深度,在查询时会用到
+  for (int i = 0; i <= 19; i++) f[u][i + 1] = f[f[u][i]][i];  // 预处理
+  for (int i = first[u]; i; i = next[i])                      // 链式前向星
+  {
+    int v = go[i];
+    if (v == father) continue;
+    f[v][0] = u;  // f[v][0] 表示 v 的父亲
+    dfs(v, u);
+  }
 }
 ```
 
@@ -183,27 +181,26 @@ void dfs(int u,int father)
 
 只不过在跳的过程中从一步一步跳变成了 ** 一次跳多步 **。可以具体分为以下几步
 
-1. 让 $x$ 的深度比 $y$ 大(深度在预处理时已经求出)
+1.  让 $x$ 的深度比 $y$ 大(深度在预处理时已经求出)
 
-2. 将两个节点跳到同一深度。在此处我们使用二进制思想,依次尝试向上跳 $2^i,2^{i-1}\cdots 2^1,2^0$。如果发现则 $x$ 跳到了 $y$ 就说明 $LCA(x,y)=y$
+2.  将两个节点跳到同一深度。在此处我们使用二进制思想,依次尝试向上跳 $2^i,2^{i-1}\cdots 2^1,2^0$。如果发现则 $x$ 跳到了 $y$ 就说明 $LCA(x,y)=y$
 
-3. 一起往上跳。依然使用二进制思想,让他们一起往上跳 $2^i,2^{i-1}\cdots 2^1,2^0$. 如果 $f[x][i]!=f[y][i]$,说明 $x$ 和 $y$ 还未相遇。最后,$x$ 和 $y$ 必定只差一步相遇。这时 $x$ 的父亲即 $f[x][0]$ 就是他们的 LCA
+3.  一起往上跳。依然使用二进制思想,让他们一起往上跳 $2^i,2^{i-1}\cdots 2^1,2^0$. 如果 $f[x][i]!=f[y][i]$,说明 $x$ 和 $y$ 还未相遇。最后,$x$ 和 $y$ 必定只差一步相遇。这时 $x$ 的父亲即 $f[x][0]$ 就是他们的 LCA
 
 ```cpp
-int lca(int x,int y)
-{
-       if (dep[x]<dep[y]) swap(x,y);  // 步骤 1
-       for (int i=20;i>=0;i--)  // 步骤 2
-       {
-               if (dep[f[x][i]]>=dep[y]) x=f[x][i];
-               if (x==y) return x;
-       }
-       for (int i=20;i>=0;i--)  // 步骤 3
-           if (f[x][i]!=f[y][i])
-           {
-               x=f[x][i];y=f[y][i];
-               }
-    return f[x][0];
+int lca(int x, int y) {
+  if (dep[x] < dep[y]) swap(x, y);  // 步骤 1
+  for (int i = 20; i >= 0; i--)     // 步骤 2
+  {
+    if (dep[f[x][i]] >= dep[y]) x = f[x][i];
+    if (x == y) return x;
+  }
+  for (int i = 20; i >= 0; i--)  // 步骤 3
+    if (f[x][i] != f[y][i]) {
+      x = f[x][i];
+      y = f[y][i];
+    }
+  return f[x][0];
 }
 ```