OSDN Git Service

Merge pull request #2020 from Ir1d/redirect
authorIr1dXD <sirius.caffrey@gmail.com>
Wed, 26 Feb 2020 02:39:30 +0000 (10:39 +0800)
committerGitHub <noreply@github.com>
Wed, 26 Feb 2020 02:39:30 +0000 (10:39 +0800)
add docs for _redirects

120 files changed:
.github/FUNDING.yml [new file with mode: 0644]
.github/ISSUE_TEMPLATE/-----.md [deleted file]
.github/ISSUE_TEMPLATE/---bug.md [deleted file]
.github/ISSUE_TEMPLATE/bug.md [new file with mode: 0644]
.github/ISSUE_TEMPLATE/content-bug.md [new file with mode: 0644]
.github/ISSUE_TEMPLATE/content-request.md [new file with mode: 0644]
.github/ISSUE_TEMPLATE/feature-request.md [new file with mode: 0644]
.travis.yml
CODE_OF_CONDUCT.md [new file with mode: 0644]
README.md
docs/basic/binary-acc.md
docs/basic/binary.md
docs/basic/bubble-sort.md
docs/basic/insertion-sort.md
docs/basic/prefix-sum.md
docs/dp/dynamic.md
docs/dp/knapsack.md
docs/dp/opt/binary-knapsack.md [deleted file]
docs/dp/opt/monotonous-queue-stack.md
docs/ds/bit.md
docs/ds/bst.md
docs/ds/dsu.md
docs/ds/dsu_complexy.md [new file with mode: 0644]
docs/ds/ett.md
docs/ds/images/dsu_complexy1.png [new file with mode: 0644]
docs/ds/lct.md
docs/ds/odt.md
docs/ds/persistent-heap.md
docs/geometry/pick.md
docs/graph/basic.md [deleted file]
docs/graph/bcc.md
docs/graph/bfs.md
docs/graph/bi-graph.md
docs/graph/concept.md [new file with mode: 0644]
docs/graph/cut.md [moved from docs/graph/bridge.md with 75% similarity]
docs/graph/dfs.md
docs/graph/euler.md
docs/graph/flow/bound.md
docs/graph/flow/images/flow1.png
docs/graph/flow/images/flow2.png
docs/graph/flow/images/flow3.png [deleted file]
docs/graph/flow/images/flow4.png [deleted file]
docs/graph/flow/images/flow5.png [deleted file]
docs/graph/flow/images/flow6.png [deleted file]
docs/graph/flow/images/flow7.png [deleted file]
docs/graph/flow/images/flow8.png [deleted file]
docs/graph/hld.md
docs/graph/images/bi-graph-1.png [new file with mode: 0644]
docs/graph/images/bi-graph-2.png [new file with mode: 0644]
docs/graph/images/bi-graph-3.png [new file with mode: 0644]
docs/graph/images/bi-graph-4.png [new file with mode: 0644]
docs/graph/images/bridge4.png [new file with mode: 0644]
docs/graph/images/flow1.png [deleted file]
docs/graph/images/flow2.png [deleted file]
docs/graph/index.md
docs/graph/lgv.md
docs/graph/misc.md [deleted file]
docs/graph/mst.md
docs/graph/save.md [new file with mode: 0644]
docs/graph/scc.md
docs/graph/shortest-path.md
docs/images/OI_wiki_new_year_ver.png [new file with mode: 0644]
docs/images/euler1.png [new file with mode: 0644]
docs/images/euler2.png [new file with mode: 0644]
docs/images/wordArt.png [deleted file]
docs/images/wordArt.webp [new file with mode: 0644]
docs/index.md
docs/intro/common-mistakes.md
docs/intro/hulu.md
docs/intro/images/cf-tool3.gif [new file with mode: 0644]
docs/intro/latex.md
docs/intro/oi.md
docs/intro/oj-tool.md
docs/intro/resources.md
docs/intro/thanks.md
docs/lang/array.md
docs/lang/basic.md
docs/lang/branch.md
docs/lang/class.md
docs/lang/csl/index.md
docs/lang/editor/geany.md [new file with mode: 0644]
docs/lang/editor/vim.md
docs/lang/helloworld.md
docs/lang/images/java1.png [new file with mode: 0644]
docs/lang/images/java2.png [new file with mode: 0644]
docs/lang/images/java3.png [new file with mode: 0644]
docs/lang/images/java4.png [new file with mode: 0644]
docs/lang/images/java5.png [new file with mode: 0644]
docs/lang/images/java6.png [new file with mode: 0644]
docs/lang/java.md
docs/lang/loop.md
docs/lang/struct.md
docs/lang/var.md
docs/math/bsgs.md
docs/math/combination.md
docs/math/dictionary.md
docs/math/du.md
docs/math/euler.md
docs/math/fermat.md
docs/math/gauss.md
docs/math/gcd.md
docs/math/mobius.md
docs/math/newton.md
docs/math/poly/fft.md
docs/math/poly/ln-exp.md
docs/math/poly/ntt.md
docs/misc/frac-programming.md
docs/misc/mo-algo.md
docs/string/images/pam3.png [new file with mode: 0644]
docs/string/images/pam4.png [new file with mode: 0644]
docs/string/images/pam5.png [new file with mode: 0644]
docs/string/images/pam6.png [new file with mode: 0644]
docs/string/minimal-string.md
docs/string/pam.md
docs/string/sa.md
docs/string/sam.md
docs/topic/rmq.md
mkdocs.yml
package-lock.json
package.json

diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644 (file)
index 0000000..ffbbe56
--- /dev/null
@@ -0,0 +1,2 @@
+open_collective: oi-wiki
+custom: "https://oi-wiki.org/intro/thanks/"
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/-----.md b/.github/ISSUE_TEMPLATE/-----.md
deleted file mode 100644 (file)
index dadf301..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
----
-name: 添加新内容
-about: 申请添加某个 topic
-
----
-
-首先,十分欢迎你来给 OI WIki 开 issue,在提交之前,请花时间阅读一下这个模板的内容,谢谢合作!
-
-- 希望添加的是什么?
-
-
-- 英文叫什么?
-
-
-- 有什么参考资料?
-
-
-issue 标题请写为 'add ' + 要添加的内容
diff --git a/.github/ISSUE_TEMPLATE/---bug.md b/.github/ISSUE_TEMPLATE/---bug.md
deleted file mode 100644 (file)
index b22cf30..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
----
-name: 汇报 bug
-about: 指出出现的问题
-
----
-
-首先,十分欢迎你来给 OI WIki 开 issue,在提交之前,请花时间阅读一下这个模板的内容,谢谢合作!
-
-- [ ] 请确认已经读过了 [F.A.Q.](https://oi-wiki.org/intro/faq/)(确认过后请将选项打钩 / 填为 `[x]`)
-
-- 是出现了什么问题?(最好截图)
-
-- 你是否正在着手修复?
-
-- 如何复现?
-
-issue 标题请写为 要汇报的主要内容
diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md
new file mode 100644 (file)
index 0000000..607ddf3
--- /dev/null
@@ -0,0 +1,21 @@
+---
+name: 内容无关的 bug
+about: 指出出现的问题
+title: "[BUG]"
+labels: Other Bug / 内容无关的 Bug
+assignees: ''
+
+---
+
+<!-- 
+首先,十分欢迎你来给 OI WIki 开 issue,在提交之前,请花时间阅读一下这个模板的内容,谢谢合作!
+- issue 标题请写为 要汇报的主要内容
+- (确认过后请将选项打钩 / 填为 `[x]`)
+-->
+
+- [ ] 我已经读过了 [F.A.Q.](https://oi-wiki.org/intro/faq/),进行了搜索,但没有得到答案
+- [ ] 我正在着手修复这个问题
+
+## 我遇到了这样的问题(最好截图)
+
+## 我确认这个问题可以这样复现
diff --git a/.github/ISSUE_TEMPLATE/content-bug.md b/.github/ISSUE_TEMPLATE/content-bug.md
new file mode 100644 (file)
index 0000000..acefa18
--- /dev/null
@@ -0,0 +1,21 @@
+---
+name: 页面内容有误
+about: 指出出现的问题
+title: "[BUG]"
+labels: Content Bug / 页面内容有误, help wanted / 需要帮助
+assignees: ''
+
+---
+
+<!-- 
+首先,十分欢迎你来给 OI WIki 开 issue,在提交之前,请花时间阅读一下这个模板的内容,谢谢合作!
+- issue 标题请写为 要汇报的主要内容
+- (确认过后请将选项打钩 / 填为 `[x]`)
+-->
+
+- [ ] 我正在着手修复这个问题
+
+## 我正在访问这个页面(最好带链接)
+
+## 我发现页面有这样的问题
+
diff --git a/.github/ISSUE_TEMPLATE/content-request.md b/.github/ISSUE_TEMPLATE/content-request.md
new file mode 100644 (file)
index 0000000..8107cac
--- /dev/null
@@ -0,0 +1,18 @@
+---
+name: 添加新内容
+about: 申请添加某个 topic
+title: add
+labels: Content Request / 内容请求, help wanted / 需要帮助
+assignees: ''
+
+---
+
+<!-- 
+首先,十分欢迎你来给 OI WIki 开 issue,在提交之前,请花时间阅读一下这个模板的内容,谢谢合作!
+- issue 标题请写清 'add ' + 要添加的内容
+- 如果涉及到添加新页面的,建议顺便注明英文名称
+-->
+
+## 我希望能添加的内容是
+
+## 我了解到的相关参考资料有
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
new file mode 100644 (file)
index 0000000..7bc4e6a
--- /dev/null
@@ -0,0 +1,20 @@
+---
+name: 添加新功能
+about: 申请添加某个新功能
+title: add
+labels: Feature Request / 功能请求, help wanted / 需要帮助
+assignees: ''
+
+---
+
+<!-- 
+首先,十分欢迎你来给 OI WIki 开 issue,在提交之前,请花时间阅读一下这个模板的内容,谢谢合作!
+- issue 标题请写清 'add ' + 要添加的内容
+- 如果涉及到添加新页面的,建议顺便注明英文名称
+-->
+
+## 我遇到的问题是
+
+## 我希望能有这样的解决方案
+
+## 我觉得其他这些方案也可以接受
index b39a998..4c8c651 100644 (file)
@@ -34,7 +34,7 @@ after_deploy:
   - cd /tmp
   - git clone https://github.com/OI-wiki/OI-wiki.git
   - cd OI-wiki
-  - git remote add coding https://$CODING_USER:$CODING_KEY@git.coding.net/scaffrey/OI-wiki.git
+  - git remote add coding https://$CODING_USER:$CODING_KEY@e.coding.net/scaffrey/OI-wiki.git
   - git push coding master:master -f
   - git fetch origin gh-pages
   - git checkout -b gh-pages origin/gh-pages
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644 (file)
index 0000000..2b80e04
--- /dev/null
@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at hi@oi-wiki.org. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
index dca8a08..6e344ab 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[![Word Art](https://raw.githubusercontent.com/24OI/OI-wiki/master/docs/images/wordArt.png)](https://oi-wiki.org/)
+[![Word Art](docs/images/wordArt.webp)](https://oi-wiki.org/)
 
 # 欢迎来到 **OI Wiki**!
 
@@ -67,7 +67,7 @@ mkdocs --help
 
 ```bash
 # Coding 上的镜像仓库和 GitHub 仓库的内容相同
-git clone https://git.dev.tencent.com/scaffrey/OI-wiki.git
+git clone https://e.coding.net/scaffrey/OI-wiki.git
 ```
 
 ### 离线版
@@ -75,7 +75,7 @@ git clone https://git.dev.tencent.com/scaffrey/OI-wiki.git
 可以使用 `gh-pages` 分支的内容(CODING 上面的分支名叫 `coding-pages`)
 
 ```bash
-git clone https://git.dev.tencent.com/scaffrey/OI-wiki.git -b coding-pages
+git clone https://e.coding.net/scaffrey/OI-wiki.git -b coding-pages
 ```
 
 本地启动一个 http 服务器可能会更方便一些。
index c4bf8f8..72d6160 100644 (file)
@@ -1,12 +1,99 @@
-author: Ir1d, ShadowsEpic, Fomalhauthmj, siger-young, MingqiHuang, Xeonacid, hsfzLZH1
+author: Ir1d, ShadowsEpic, Fomalhauthmj, siger-young, MingqiHuang, Xeonacid, hsfzLZH1, orzAtalod
 
 倍增法,通过字面意思来看就是翻倍。这个方法在很多算法中均有应用,其中最常用的就是 RMQ 问题和求 LCA 了。
 
+## 例题
+
+???+note "例题"
+    给出一个长度为 $n$ 的环和一个常数 $k$ ,每次会从第 $i$ 个点跳到第 $(i+k)\bmod n+1$ 个点,总共跳了 $m$ 次。每个点都有一个权值,记为 $a_i$ ,求 $m$ 次跳跃的起点的权值之和对 $10^9+7$ 取模的结果。
+
+    数据范围: $1\leq n\leq 10^6$ , $1\leq m\leq 10^{18}$ , $1\leq k\leq n$ , $0\le a_i\le 10^9$ 。
+
+这里显然不能暴力模拟跳 $m$ 次。因为 $m$ 最大可到 $10^{18}$ 级别,如果暴力模拟的话,时间承受不住。
+
+所以就需要进行一些预处理,提前整合一些信息,以便于在查询的时候更快得出结果。如果记录下来每一个可能的跳跃次数的结果的话,不论是时间还是空间都难以承受。
+
+那么应该如何预处理呢?先看另一道例题:
+
+???+note "例题"
+    如何用尽可能少的砝码称量出 $[0,31]$ 之间的所有重量?(只能在天平的一端放砝码)
+
+答案是使用 1 2 4 8 16 这五个砝码,可以称量出 $[0,31]$ 之间的所有重量。同样,如果要称量 $[0,127]$ 之间的所有重量,可以使用 1 2 4 8 16 32 64 这七个砝码。每次我们都选择 2 的整次幂作砝码的重量,就可以使用极少的砝码个数量出任意我们所需要的重量。
+
+为什么说是极少呢?因为如果我们要量出 $[0,1023]$ 之间的所有重量,只需要 9 个砝码,需要量出 $[0,1048575]$ 之间的所有重量,只需要 19 个。如果我们的目标重量翻倍,砝码个数只需要增加 1。这叫“对数级”的增长速度,因为砝码的所需个数与目标重量的范围的对数成正比。
+
+回到上面的题。我们要预处理一些信息,然后用预处理的信息尽量快的整合出答案。同时预处理的信息也不能太多。所以可以预处理出以 2 的整次幂为单位的信息,这样的话在预处理的时候只需要处理少量信息,在整合的时候也不需要大费周章。
+
+在这题上,就是我们预处理出从每个点开始跳 1、2、4、8 等等步之后的结果(所处点和点权和),然后如果要跳 13 步,只需要跳 1+4+8 步就好了。也就是说先在起始点跳 1 步,然后再在跳了之后的终点跳 4 步,再接着跳 8 步,同时统计一下预先处理好的点权和,就可以知道跳 13 步的点权和了。
+
+对于每一个点开始的 $2^i$ 步,记录一个 `go[i][x]` 表示第 $x$ 个点跳 $2^i$ 步之后的终点,而 `sum[i][x]` 表示第 $x$ 个点跳 $2^i$ 步之后能获得的点权和。预处理的时候,开两重循环,对于跳 $2^i$ 步的信息,我们可以看作是先跳了 $2^{i-1}$ 步,再跳 $2^{i-1}$ 步,因为显然有 $2^{i-1}+2^{i-1}=2^i$ 。即我们有 `sum[i][x] = sum[i-1][x]+sum[i-1][go[i-1][x]]` ,且 `go[i][x] = go[i-1][go[i-1][x]]` 。
+
+当然还有一些实现细节需要注意。为了保证统计的时候不重不漏,我们一般预处理出“左闭右开”的点权和。亦即,对于跳 1 步的情况,我们只记录该点的点权和;对于跳 2 步的情况,我们只记录该点及其下一个点的点权和。相当于总是不将终点的点权和计入 sum。这样在预处理的时候,只需要将两部分的点权和直接相加就可以了,不需要担心第一段的终点和第二段的起点会被重复计算。
+
+??? note "例题代码"
+    ```cpp
+    #include <cstdio>
+    using namespace std;
+    
+    const int mod = 1000000007;
+    
+    int modadd(int a, int b) {
+      if (a + b >= mod) return a + b - mod;  // 减法代替取模,加快运算
+      return a + b;
+    }
+    
+    int vi[1000005];
+    
+    int go[75][1000005];  // 将数组稍微开大以避免越界,小的一维尽量定义在前面
+    int sum[75][1000005];
+    
+    int main() {
+      int n, k;
+      scanf("%d%d", &n, &k);
+      for (int i = 1; i <= n; ++i) {
+        scanf("%d", vi + i);
+      }
+    
+      for (int i = 1; i <= n; ++i) {
+        go[0][i] = (i + k) % n + 1;
+        sum[0][i] = vi[i];
+      }
+    
+      int logn = 31 - __builtin_clz(n);  // 一个快捷的取对数的方法
+      for (int i = 1; i <= logn; ++i) {
+        for (int j = 1; j <= n; ++j) {
+          go[i][j] = go[i - 1][go[i - 1][j]];
+          sum[i][j] = modadd(sum[i - 1][j], sum[i - 1][go[i - 1][j]]);
+        }
+      }
+    
+      long long m;
+      scanf("%lld", &m);
+    
+      int ans = 0;
+      int curx = 1;
+      for (int i = 0; m; ++i) {
+        if (m & (1 << i))  // 参见位运算的相关内容,意为 m 的第 i 位是否为 1
+        {
+          ans = modadd(ans, sum[i][curx]);
+          curx = go[i][curx];
+          m ^= 1ll << i;  // 将第 i 位置零
+        }
+      }
+    
+      printf("%d\n", ans);
+    }
+    ```
+
+这题的 $m\leq 10^{18}$ ,虽然看似恐怖,但是实际上只需要预处理出 $65$ 以内的 $i$ ,就可以轻松解决,比起暴力枚举快了很多。用行话讲,这个做法的 [时间复杂度](../misc/complexity.md) 是预处理 $\Theta(n\log m)$ ,查询每次 $\Theta(\log m)$ 。
+
+倍增除了作为一种独立的思想以外,还经常被应用到各种算法里面,例如 LCA 和 RMQ 问题,可以在下面查看。
+
 ## RMQ 问题
 
 RMQ 是英文 Range Maximum/Minimum Query 的缩写,表示区间最大(最小)值。
 
-解决 RMQ 问题的主要方法有两种,分别是 ST 表和线段树,具体请参见 [ST 表](/ds/sparse-table) 页面和 [线段树](/ds/seg) 页面
+使用倍增思想解决 RMQ 问题的方法是 [ST 表](../ds/sparse-table.md) ,解决 RMQ 问题的其它方法还可以参见 [RMQ 专题](../topic/rmq.md) 
 
 ## 树上倍增求 LCA
 
index b43be23..c89e249 100644 (file)
@@ -72,7 +72,7 @@ bool check(int k) {  //检查可行性,k为锯片高度
       sum += (long long)(a[i] - k);  //累加树木长度
   return sum >= m;                   //如果满足最少长度代表可行
 }
-int find(int x) {
+int find() {
   int l = 1, r = 1000000001;  //因为是左闭右开的,所以10亿要加1
   while (l + 1 < r) {         //如果两点不相邻
     int mid = (l + r) / 2;    //取中间值
@@ -86,7 +86,7 @@ int find(int x) {
 int main() {
   cin >> n >> m;
   for (int i = 1; i <= n; i++) cin >> a[i];
-  cout << find(m);
+  cout << find();
   return 0;
 }
 ```
index 0e81de5..5c2ce98 100644 (file)
@@ -26,6 +26,7 @@ $$
 C++ 代码:
 
 ```cpp
+// 假设数组的大小是n+1,冒泡排序从数组下标1开始
 void bubble_sort(int *a, int n) {
   bool flag = true;
   while (flag) {
index d1c27d3..7caf2a9 100644 (file)
@@ -25,6 +25,7 @@ C++ 代码:
 
 ```cpp
 void insertion_sort(int* a, int n) {
+  //对 a[1],a[2],...,a[n] 进行插入排序
   for (int i = 2; i <= n; ++i) {
     int key = a[i];
     int j = i - 1;
index 4e123d1..c00ce27 100644 (file)
@@ -132,7 +132,8 @@ int main() {
 ### 习题
 
 -    [CodeVS 1373. 射命丸文](http://www.joyoi.cn/problem/codevs-1373) 
--    [洛谷 P1387 最大正方形](https://www.luogu.org/problemnew/show/P1387) 
+-    [洛谷 P1387 最大正方形](https://www.luogu.com.cn/problem/P1387) 
+-    [「HNOI2003」激光炸弹](https://www.luogu.com.cn/problem/P2280) 
 
 ### 基于 DP 计算高维前缀和
 
@@ -176,7 +177,8 @@ int main() {
 ### 习题
 
 -    [树状数组 3:区间修改,区间查询](https://loj.ac/problem/132) 
--    [P3397 地毯](https://www.luogu.org/problemnew/show/P3397) 
+-    [P3397 地毯](https://www.luogu.com.cn/problem/P3397) 
+-    [「Poetize6」IncDec Sequence](https://www.luogu.com.cn/problem/P4552) 
 
 ## 树上差分
 
index 82cac9c..a4530a6 100644 (file)
@@ -80,167 +80,166 @@ $$
 
 4.  查询时就是 1 到其所在的重链末尾的区间乘,最后取一个 $\max$ 即可。
 
-#### 代码
-
-```c++
-#include <bits/stdc++.h>
-
-using namespace std;
-
-#define REP(i, a, b) for (int i = (a), _end_ = (b); i <= _end_; ++i)
-#define mem(a) memset((a), 0, sizeof(a))
-#define str(a) strlen(a)
-#define lson root << 1
-#define rson root << 1 | 1
-typedef long long LL;
-
-const int maxn = 500010;
-const int INF = 0x3f3f3f3f;
-
-int Begin[maxn], Next[maxn], To[maxn], e, n, m;
-int size[maxn], son[maxn], top[maxn], fa[maxn], dis[maxn], p[maxn], id[maxn],
-    End[maxn];
-// p[i]表示i树剖后的编号,id[p[i]] = i
-int cnt, tot, a[maxn], f[maxn][2];
-
-struct matrix {
-  int g[2][2];
-  matrix() { memset(g, 0, sizeof(g)); }
-  matrix operator*(const matrix &b) const  // 重载矩阵乘
-  {
-    matrix c;
-    REP(i, 0, 1)
-    REP(j, 0, 1) REP(k, 0, 1) c.g[i][j] = max(c.g[i][j], g[i][k] + b.g[k][j]);
-    return c;
-  }
-} Tree[maxn], g[maxn];  // Tree[]是建出来的线段树,g[]是维护的每个点的矩阵
-
-inline void PushUp(int root) { Tree[root] = Tree[lson] * Tree[rson]; }
-
-inline void Build(int root, int l, int r) {
-  if (l == r) {
-    Tree[root] = g[id[l]];
-    return;
-  }
-  int Mid = l + r >> 1;
-  Build(lson, l, Mid);
-  Build(rson, Mid + 1, r);
-  PushUp(root);
-}
-
-inline matrix Query(int root, int l, int r, int L, int R) {
-  if (L <= l && r <= R) return Tree[root];
-  int Mid = l + r >> 1;
-  if (R <= Mid) return Query(lson, l, Mid, L, R);
-  if (Mid < L) return Query(rson, Mid + 1, r, L, R);
-  return Query(lson, l, Mid, L, R) * Query(rson, Mid + 1, r, L, R);
-  // 注意查询操作的书写
-}
-
-inline void Modify(int root, int l, int r, int pos) {
-  if (l == r) {
-    Tree[root] = g[id[l]];
-    return;
-  }
-  int Mid = l + r >> 1;
-  if (pos <= Mid)
-    Modify(lson, l, Mid, pos);
-  else
-    Modify(rson, Mid + 1, r, pos);
-  PushUp(root);
-}
-
-inline void Update(int x, int val) {
-  g[x].g[1][0] += val - a[x];
-  a[x] = val;
-  // 首先修改x的g矩阵
-  while (x) {
-    matrix last = Query(1, 1, n, p[top[x]], End[top[x]]);
-    // 查询top[x]的原本g矩阵
-    Modify(1, 1, n,
-           p[x]);  // 进行修改(x点的g矩阵已经进行修改但线段树上的未进行修改)
-    matrix now = Query(1, 1, n, p[top[x]], End[top[x]]);
-    // 查询top[x]的新g矩阵
-    x = fa[top[x]];
-    g[x].g[0][0] +=
-        max(now.g[0][0], now.g[1][0]) - max(last.g[0][0], last.g[1][0]);
-    g[x].g[0][1] = g[x].g[0][0];
-    g[x].g[1][0] += now.g[0][0] - last.g[0][0];
-    // 根据变化量修改fa[top[x]]的g矩阵
-  }
-}
-
-inline void add(int u, int v) {
-  To[++e] = v;
-  Next[e] = Begin[u];
-  Begin[u] = e;
-}
-
-inline void DFS1(int u) {
-  size[u] = 1;
-  int Max = 0;
-  f[u][1] = a[u];
-  for (int i = Begin[u]; i; i = Next[i]) {
-    int v = To[i];
-    if (v == fa[u]) continue;
-    dis[v] = dis[u] + 1;
-    fa[v] = u;
-    DFS1(v);
-    size[u] += size[v];
-    if (size[v] > Max) {
-      Max = size[v];
-      son[u] = v;
+??? note "代码实现"
+    ```c++
+    #include <bits/stdc++.h>
+    
+    using namespace std;
+    
+    #define REP(i, a, b) for (int i = (a), _end_ = (b); i <= _end_; ++i)
+    #define mem(a) memset((a), 0, sizeof(a))
+    #define str(a) strlen(a)
+    #define lson root << 1
+    #define rson root << 1 | 1
+    typedef long long LL;
+    
+    const int maxn = 500010;
+    const int INF = 0x3f3f3f3f;
+    
+    int Begin[maxn], Next[maxn], To[maxn], e, n, m;
+    int size[maxn], son[maxn], top[maxn], fa[maxn], dis[maxn], p[maxn], id[maxn],
+        End[maxn];
+    // p[i]表示i树剖后的编号,id[p[i]] = i
+    int cnt, tot, a[maxn], f[maxn][2];
+    
+    struct matrix {
+      int g[2][2];
+      matrix() { memset(g, 0, sizeof(g)); }
+      matrix operator*(const matrix &b) const  // 重载矩阵乘
+      {
+        matrix c;
+        REP(i, 0, 1)
+        REP(j, 0, 1) REP(k, 0, 1) c.g[i][j] = max(c.g[i][j], g[i][k] + b.g[k][j]);
+        return c;
+      }
+    } Tree[maxn], g[maxn];  // Tree[]是建出来的线段树,g[]是维护的每个点的矩阵
+    
+    inline void PushUp(int root) { Tree[root] = Tree[lson] * Tree[rson]; }
+    
+    inline void Build(int root, int l, int r) {
+      if (l == r) {
+        Tree[root] = g[id[l]];
+        return;
+      }
+      int Mid = l + r >> 1;
+      Build(lson, l, Mid);
+      Build(rson, Mid + 1, r);
+      PushUp(root);
     }
-    f[u][1] += f[v][0];
-    f[u][0] += max(f[v][0], f[v][1]);
-    // DFS1过程中同时求出f[i][0/1]
-  }
-}
-
-inline void DFS2(int u, int t) {
-  top[u] = t;
-  p[u] = ++cnt;
-  id[cnt] = u;
-  End[t] = cnt;
-  g[u].g[1][0] = a[u];
-  g[u].g[1][1] = -INF;
-  if (!son[u]) return;
-  DFS2(son[u], t);
-  for (int i = Begin[u]; i; i = Next[i]) {
-    int v = To[i];
-    if (v == fa[u] || v == son[u]) continue;
-    DFS2(v, v);
-    g[u].g[0][0] += max(f[v][0], f[v][1]);
-    g[u].g[1][0] += f[v][0];
-    // g矩阵根据f[i][0/1]求出
-  }
-  g[u].g[0][1] = g[u].g[0][0];
-}
-
-int main() {
-#ifndef ONLINE_JUDGE
-  freopen("input.txt", "r", stdin);
-  freopen("output.txt", "w", stdout);
-#endif
-  scanf("%d%d", &n, &m);
-  REP(i, 1, n) scanf("%d", &a[i]);
-  REP(i, 1, n - 1) {
-    int u, v;
-    scanf("%d%d", &u, &v);
-    add(u, v);
-    add(v, u);
-  }
-  dis[1] = 1;
-  DFS1(1);
-  DFS2(1, 1);
-  Build(1, 1, n);
-  REP(i, 1, m) {
-    int x, val;
-    scanf("%d%d", &x, &val);
-    Update(x, val);
-    matrix ans = Query(1, 1, n, 1, End[1]);  // 查询1所在重链的矩阵乘
-    printf("%d\n", max(ans.g[0][0], ans.g[1][0]));
-  }
-  return 0;
-}
-```
+    
+    inline matrix Query(int root, int l, int r, int L, int R) {
+      if (L <= l && r <= R) return Tree[root];
+      int Mid = l + r >> 1;
+      if (R <= Mid) return Query(lson, l, Mid, L, R);
+      if (Mid < L) return Query(rson, Mid + 1, r, L, R);
+      return Query(lson, l, Mid, L, R) * Query(rson, Mid + 1, r, L, R);
+      // 注意查询操作的书写
+    }
+    
+    inline void Modify(int root, int l, int r, int pos) {
+      if (l == r) {
+        Tree[root] = g[id[l]];
+        return;
+      }
+      int Mid = l + r >> 1;
+      if (pos <= Mid)
+        Modify(lson, l, Mid, pos);
+      else
+        Modify(rson, Mid + 1, r, pos);
+      PushUp(root);
+    }
+    
+    inline void Update(int x, int val) {
+      g[x].g[1][0] += val - a[x];
+      a[x] = val;
+      // 首先修改x的g矩阵
+      while (x) {
+        matrix last = Query(1, 1, n, p[top[x]], End[top[x]]);
+        // 查询top[x]的原本g矩阵
+        Modify(1, 1, n,
+               p[x]);  // 进行修改(x点的g矩阵已经进行修改但线段树上的未进行修改)
+        matrix now = Query(1, 1, n, p[top[x]], End[top[x]]);
+        // 查询top[x]的新g矩阵
+        x = fa[top[x]];
+        g[x].g[0][0] +=
+            max(now.g[0][0], now.g[1][0]) - max(last.g[0][0], last.g[1][0]);
+        g[x].g[0][1] = g[x].g[0][0];
+        g[x].g[1][0] += now.g[0][0] - last.g[0][0];
+        // 根据变化量修改fa[top[x]]的g矩阵
+      }
+    }
+    
+    inline void add(int u, int v) {
+      To[++e] = v;
+      Next[e] = Begin[u];
+      Begin[u] = e;
+    }
+    
+    inline void DFS1(int u) {
+      size[u] = 1;
+      int Max = 0;
+      f[u][1] = a[u];
+      for (int i = Begin[u]; i; i = Next[i]) {
+        int v = To[i];
+        if (v == fa[u]) continue;
+        dis[v] = dis[u] + 1;
+        fa[v] = u;
+        DFS1(v);
+        size[u] += size[v];
+        if (size[v] > Max) {
+          Max = size[v];
+          son[u] = v;
+        }
+        f[u][1] += f[v][0];
+        f[u][0] += max(f[v][0], f[v][1]);
+        // DFS1过程中同时求出f[i][0/1]
+      }
+    }
+    
+    inline void DFS2(int u, int t) {
+      top[u] = t;
+      p[u] = ++cnt;
+      id[cnt] = u;
+      End[t] = cnt;
+      g[u].g[1][0] = a[u];
+      g[u].g[1][1] = -INF;
+      if (!son[u]) return;
+      DFS2(son[u], t);
+      for (int i = Begin[u]; i; i = Next[i]) {
+        int v = To[i];
+        if (v == fa[u] || v == son[u]) continue;
+        DFS2(v, v);
+        g[u].g[0][0] += max(f[v][0], f[v][1]);
+        g[u].g[1][0] += f[v][0];
+        // g矩阵根据f[i][0/1]求出
+      }
+      g[u].g[0][1] = g[u].g[0][0];
+    }
+    
+    int main() {
+    #ifndef ONLINE_JUDGE
+      freopen("input.txt", "r", stdin);
+      freopen("output.txt", "w", stdout);
+    #endif
+      scanf("%d%d", &n, &m);
+      REP(i, 1, n) scanf("%d", &a[i]);
+      REP(i, 1, n - 1) {
+        int u, v;
+        scanf("%d%d", &u, &v);
+        add(u, v);
+        add(v, u);
+      }
+      dis[1] = 1;
+      DFS1(1);
+      DFS2(1, 1);
+      Build(1, 1, n);
+      REP(i, 1, m) {
+        int x, val;
+        scanf("%d%d", &x, &val);
+        Update(x, val);
+        matrix ans = Query(1, 1, n, 1, End[1]);  // 查询1所在重链的矩阵乘
+        printf("%d\n", max(ans.g[0][0], ans.g[1][0]));
+      }
+      return 0;
+    }
+    ```
index de74763..33574d6 100644 (file)
@@ -82,15 +82,13 @@ for (int i = 1; i <= n; i++)
 
 可以考虑一个朴素的做法:对于第 $i$ 件物品,枚举其选了多少个来转移。这样做的时间复杂度是 $O(n^3)$ 的。
 
-尽管è¿\99æ ·ç\9c\8bèµ·æ\9d¥å¾\88è ¢ï¼\8cæ\88\91们è¿\98æ\98¯å\86\99ä¸\80ä¸\8b dp æ\96¹ç¨\8bï¼\9a
+ç\8a¶æ\80\81转移æ\96¹ç¨\8bå¦\82ä¸\8bï¼\9a
 
 $$
 f_{i,j}=\max_{k=0}^{+\infty}(f_{i-1,j-k\times w_i}+v_i\times k)
 $$
 
-然而这样显然不够优秀,我们要对它进行优化。
-
-可以发现,对于 $f_{i,j}$ ,只要通过 $f_{i,j-w_i}$ 转移就可以了。dp 方程为:
+考虑做一个简单的优化。可以发现,对于 $f_{i,j}$ ,只要通过 $f_{i,j-w_i}$ 转移就可以了。因此状态转移方程为:
 
 $$
 f_{i,j}=\max(f_{i-1,j},f_{i,j-w_i}+v_i)
@@ -121,15 +119,21 @@ $$
 
 ## 多重背包
 
-多重背包也是 0-1 背包的一个变式。与 0-1 背包的区别在于每种物品可以选 $k_i$ 次,而非 $1$ 次。
+多重背包也是 0-1 背包的一个变式。与 0-1 背包的区别在于每种物品 y 有 $k_i$ 个,而非 $1$ 个。
+
+一个很朴素的想法就是:把“每种物品选 $k_i$ 次”等价转换为“有 $k_i$ 个相同的物品,每个物品选一次”。这样就转换成了一个 0-1 背包模型,套用上文所述的方法就可已解决。状态转移方程如下:
 
-一个很朴素的想法就是:把“每种物品选 $k_i$ 次”等价转换为“有 $k_i$ 个相同的物品,每个物品选一次”。这样就转换成了一个 0-1 背包模型,套用上文所述的方法就可已解决。时间复杂度: $O(nW\sum k_i)$ ,可以轻松 TLE。
+$$
+f_{i,j}=\max_{k=0}^{k_i}(f_{i-1,j-k\times w_i}+v_i\times k)
+$$
 
-虽然我们失败了,但是这个朴素的想法可以给我们的思路提供一些借鉴——我们可以把多重背包转化成 0-1 背包模型来求解
+时间复杂度 $O(nW\sum k_i)$ 
 
-显然,复杂度中的 $O(nW)$ 部分无法再优化了,我们只能从 $O(\sum k_i)$ 处入手。
+### 二进制分组优化
 
-为了表述方便,我们用 $A_{i,j}$ 代表第 $i$ 种物品拆分出的第 $j$ 个物品。
+考虑优化。我们仍考虑把多重背包转化成 0-1 背包模型来求解。
+
+显然,复杂度中的 $O(nW)$ 部分无法再优化了,我们只能从 $O(\sum k_i)$ 处入手。为了表述方便,我们用 $A_{i,j}$ 代表第 $i$ 种物品拆分出的第 $j$ 个物品。
 
 在朴素的做法中, $\forall j\le k_i$ , $A_{i,j}$ 均表示相同物品。那么我们效率低的原因主要在于我们进行了大量重复性的工作。举例来说,我们考虑了“同时选 $A_{i,1},A_{i,2}$ ”与“同时选 $A_{i,2},A_{i,3}$ ”这两个完全等效的情况。这样的重复性工作我们进行了许多次。那么优化拆分方式就成为了解决问题的突破口。
 
@@ -146,7 +150,7 @@ $$
 
 显然,通过上述拆分方式,可以表示任意 $\le k_i$ 个物品的等效选择方式。将每种物品按照上述方式拆分后,使用 0-1 背包的方法解决即可。
 
-时间复杂度 $O(nW\sum\log k_i)$ 
+时间复杂度 $O(W\sum_{i=1}^n\log_2k_i)$ 
 
 ??? 二进制分组代码
     ```cpp
@@ -165,8 +169,11 @@ $$
     }
     ```
 
-??? note "[「Luogu P1776」宝物筛选\_NOI 导刊 2010 提高(02)](https://www.luogu.org/problemnew/show/P1776)"
-    题意概要:有 $n$ 种物品和一个容量为 $W$ 的背包,每种物品有 $m_v{i}$ 个,同时每个物品有两种属性:重量 $w_{i}$ 和价值 $v_{i}$ 。要求选若干个物品放入背包使背包中物品的总价值最大且背包中物品的总重量不超过背包的容量。有一点需要注意的是本题数据范围较大,情况较多。
+### 单调队列优化
+
+见 [单调队列/单调栈优化](opt/monotonous-queue-stack.md) 。
+
+习题: [「Luogu P1776」宝物筛选\_NOI 导刊 2010 提高(02)](https://www.luogu.org/problemnew/show/P1776) 
 
 ## 混合背包
 
diff --git a/docs/dp/opt/binary-knapsack.md b/docs/dp/opt/binary-knapsack.md
deleted file mode 100644 (file)
index 043f9ff..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-author: TrisolarisHD, hsfzLZH1, greyqz, Ir1d, abc1763613206, tigerruanyifan
-
-## 介绍
-
-??? note " 例题[经典问题 - 多重背包](../knapsack.md#_2)"
-    题目大意:有 $n$ 种物品,每种物品有 $a_i$ 件,购买一件这种物品的费用为 $c_i$ ,价值为 $v_i$ 。有一个容量为 $t$ 的背包,现在让你找到最优的一种方案,使得装入背包的物品的总价值最大。
-
-考虑常规的动规方式,定义 $f_{i,j}$ 为当前考虑到第 $i$ 个物品,背包容量为 $j$ 所能获得的最大价值。
-
-状态转移方程为, $f_{i,j}=\max\{f_{i-1,j},f_{i-1,j-c_i}+v_i\}$ 。
-
-对于 **每件** 物品,都要这样循环一次,时间复杂度为 $t\times \sum_{i=1}^n a_i$ ,某些时候可能不可接受,需要优化。
-
-考虑这样一种情况,如果我们有 $17$ 个硬币,要去买 $1$ 到 $17$ 元钱的物品,只需将这些硬币打包成 $1,2,4,8$ 和 $2$ 这样的几包。前面的 $4$ 包能保证覆盖 $1$ 到 $15$ 所有的情况,最后一包在之前的基础上再加上一个值,能保证实现支付的时候取整包,肯定能保证支付。这就是二进制优化的原理和基本思想。
-
-用上述的方法,就可以把 $k$ 件相同的物品看作是 $O(\log k)$ 件物品了。优化后
-
-代码实现:
-
-```cpp
-for (int i = 1; i <= n; i++) {
-  scanf("%d", a + i);
-  tot += c[i] * a[i];
-  for (int j = 1; j <= a[i]; j *= 2)
-    if (a[i] >= j) a[i] -= j, v[++cur] = c[i] * j;
-  if (a[i]) v[++cur] = c[i] * a[i];
-}
-for (int i = 1; i <= cur; i++)
-  for (int j = m; j >= v[i]; j--)
-    if (f[j - v[i]]) f[j] = true;
-```
-
-## 习题
-
- [HDU 2844 Coins](http://acm.hdu.edu.cn/showproblem.php?pid=2844) 
index 0804bd9..44da8d2 100644 (file)
@@ -31,6 +31,33 @@ author: TrisolarisHD, hsfzLZH1, Ir1d, greyqz, Anguei, billchenchina, Chrogeek, C
 
 讲完了,让我们归纳一下单调队列优化动态规划问题的基本形态:当前状态的所有值可以从上一个状态的某个连续的段的值得到,要对这个连续的段进行 RMQ 操作,相邻状态的段的左右区间满足非降的关系。
 
+## 单调队列优化多重背包
+
+???+note "问题描述"
+    你有 $n$ 个物品,每个物品重量为 $w_i$ ,价值为 $v_i$ ,数量为 $k_i$ 。你有一个承重上限为 $m$ 的背包,现在要求你在不超过重量上限的情况下选取价值和尽可能大的物品放入背包。求最大价值。
+
+不了解背包 DP 的请先阅读 [背包 DP](../knapsack.md) 。设 $f_{i,j}$ 表示前 $i$ 个物品装入承重为 $j$ 的背包的最大价值,朴素的转移方程为
+
+$$
+f_{i,j}=\max_{k=0}^{k_i}(f_{i-1,j-k\times w_i}+v_i\times k)
+$$
+
+时间复杂度 $O(nW\sum k_i)$ 。
+
+考虑优化 $f_i$ 的转移。为方便表述,设 $g_{x,y}=f_{i,x\times w_i+y},g'_{x,y}=f_{i-1,x\times w_i+y}$ ,则转移方程可以表示为:
+
+$$
+g_{x,y}=\max_{k=0}^{k_i}(g'_{x-k,y}+v_i\times k)
+$$
+
+设 $G_{x,y}=g'_{x,y}-v_i\times x$ 。则方程可以表示为:
+
+$$
+g_{x,y}=\max_{k=0}^{k_i}(G_{x-k,y})+v_i\times x
+$$
+
+这样就转化为一个经典的单调队列优化形式了。 $G_{x,y}$ 可以 $O(1)$ 计算,因此对于固定的 $y$ ,我们可以在 $O\left( \left\lfloor \dfrac{W}{w_i} \right\rfloor \right)$ 的时间内计算出 $g_{x,y}$ 。因此求出所有 $g_{x,y}$ 的复杂度为 $O\left( \left\lfloor \dfrac{W}{w_i} \right\rfloor \right)\times O(w_i)=O(W)$ 。这样转移的总复杂度就降为 $O(nW)$ 。
+
 ## 习题
 
  [「Luogu P1886」滑动窗口](https://loj.ac/problem/10175) 
index b116d79..665d9a6 100644 (file)
@@ -18,6 +18,8 @@ author: HeRaNO, Zhoier
 
 ![](./images/bit1.png)
 
+这个结构的思想和线段树有些类似:用一个大节点表示一些小节点的信息,进行查询的时候只需要查询一些大节点而不是更多的小节点。
+
 最下面的八个方块就代表存入 $a$ 中的八个数,现在都是十进制。
 
 他们上面的参差不齐的剩下的方块就代表 $a$ 的上级—— $c$ 数组。
@@ -137,7 +139,11 @@ long long getsum1(int l, int r) {
 }
 ```
 
-树状数组还有一些 trick,如 $O(n)$ 建树、 $O(\log n)$ 查询第 $k$ 小/大元素等,下附代码。
+## Tricks
+
+ $O(n)$ 建树:
+
+每一个节点的值是由所有与自己直接相连的儿子的值求和得到的。因此可以倒着考虑贡献,即每次确定完儿子的值后,用自己的值更新自己的直接父亲。
 
 ```cpp
 // O(n)建树
@@ -148,19 +154,40 @@ void init() {
     if (j <= n) t[j] += t[i];
   }
 }
+```
+
+ $O(\log n)$ 查询第 $k$ 小/大元素。在此处只讨论第 $k$ 小,第 $k$ 大问题可以通过简单计算转化为第 $k$ 小问题。
+
+参考 "可持久化线段树" 章节中,关于求区间第 $k$ 小的思想。将所有数字看成一个可重集合,即定义数组 $a$ 表示值为 $i$ 的元素在整个序列重出现了 $a_i$ 次。找第 $k$ 大就是找到最小的 $x$ 恰好满足 $\sum_{i=1}^{x}a_i \geq k$ 
+
+因此可以想到算法:如果已经找到 $x$ 满足 $\sum_{i=1}^{x}a_i \le k$ ,考虑能不能让 $x$ 继续增加,使其仍然满足这个条件。找到最大的 $x$ 后, $x+1$ 就是所要的值。
+在树状数组中,节点是根据 2 的幂划分的,每次可以扩大 2 的幂的长度。令 $sum$ 表示当前的 $x$ 所代表的前缀和,有如下算法找到最大的 $x$ :
 
-int kth(int k) {  //权值树状数组查询第k小
+1.  求出 $depth=\left \lfloor log_2n \right \rfloor$ 
+2.  计算 $t=\sum_{i=x+1}^{x+2^{depth}}a_i$ 
+3.  如果 $sum+t \le k$ ,则此时扩展成功,将 $2^{depth}$ 累加到 $x$ 上;否则扩展失败,对 $x$ 不进行操作
+4.  将 $depth$ 减 1,回到步骤 2,直至 $depth$ 为 0
+
+```cpp
+//权值树状数组查询第k小
+int kth(int k) {
   int cnt = 0, ret = 0;
-  for (int i = log2(n); ~i; --i) {
-    ret += 1 << i;
-    if (ret >= n || cnt + t[ret] >= k)
+  for (int i = log2(n); ~i; --i) {      // i与上文depth含义相同
+    ret += 1 << i;                      //尝试扩展
+    if (ret >= n || cnt + t[ret] >= k)  //如果扩展失败
       ret -= 1 << i;
     else
-      cnt += t[ret];
+      cnt += t[ret];  //扩展成功后 要更新之前求和的值
   }
   return ret + 1;
 }
+```
 
+时间戳优化:
+
+对付多组数据很常见的技巧。如果每次输入新数据时,都暴力清空树状数组,就可能会造成超时。因此使用 $tag$ 标记,存储当前节点上次使用时间(即最近一次是被第几组数据使用)。每次操作时判断这个位置 $tag$ 中的时间和当前时间是否相同,就可以判断这个位置应该是 0 还是数组内的值。
+
+```cpp
 //时间戳优化
 int tag[MAXN], t[MAXN], Tag;
 void reset() { ++Tag; }
index a1bccd8..4bc65b4 100644 (file)
@@ -14,6 +14,8 @@
 
 ## 基本操作
 
+在接下来的代码块中,我们约定 $n$ 为结点个数, $h$ 为高度, `val[x]` 为结点 $x$ 处存的数值, `cnt[x]` 为结点 $x$ 存的值所出现的次数, `lc[x]` 和 `rc[x]` 分别为结点 $x$ 的左子结点和右子结点。
+
 ### 遍历二叉搜索树
 
 由二叉搜索树的递归定义可得,二叉搜索树的中序遍历权值的序列为非降的序列。时间复杂度为 $O(n)$ 。
 遍历一棵二叉搜索树的代码如下:
 
 ```cpp
-void print(int o)  //遍历以 o 为根节点的二叉搜索树
-{
-  if (!o) return;          //遇到空树,返回
-  print(lc[o]);            //递归遍历左子树
-  printf("%d\n", val[o]);  //输出根节点信息
-  print(rc[o]);            //递归遍历右子树
+void print(int o) {
+  //遍历以 o 为根节点的二叉搜索树
+  if (!o) return;  //遇到空树,返回
+  print(lc[o]);    //递归遍历左子树
+  for (int i = 1; i <= cnt[o]; i++) printf("%d\n", val[o]);  //输出根节点信息
+  print(rc[o]);  //递归遍历右子树
 }
 ```
 
@@ -34,13 +36,15 @@ void print(int o)  //遍历以 o 为根节点的二叉搜索树
 
 由二叉搜索树的性质可得,二叉搜索树上的最小值为二叉搜索树左链的顶点,最大值为二叉搜索树右链的顶点。时间复杂度为 $O(h)$ 。
 
+findmin 和 findmax 函数分别返回最小值和最大值所对应的结点编号 $o$ ,用 `val[o]` 可以获得相应的最小/最大值。
+
 ```cpp
 int findmin(int o) {
-  if (!lc[o]) return val[o];
+  if (!lc[o]) return o;
   return findmin(lc[o]);  //一直向左儿子跳
 }
 int findmax(int o) {
-  if (!rc[o]) return val[o];
+  if (!rc[o]) return o;
   return findmax(rc[o]);  //一直向右儿子跳
 }
 ```
@@ -53,37 +57,39 @@ int findmax(int o) {
 
 若 $o$ 为空,直接返回一个值为 $v$ 的新节点。
 
-若 $o$ 的权值大于 $v$ ,在 $o$ 的左子树中插入权值为 $v$ 的节点。
-
 若 $o$ 的权值等于 $v$ ,该节点的附加域该值出现的次数自增 $1$ 。
 
+若 $o$ 的权值大于 $v$ ,在 $o$ 的左子树中插入权值为 $v$ 的节点。
+
 若 $o$ 的权值小于 $v$ ,在 $o$ 的右子树中插入权值为 $v$ 的节点。
 
 时间复杂度为 $O(h)$ 。
 
 ```cpp
-void insert(int o, int v) {
+void insert(int& o, int v) {
   if (!o) {
     val[o = ++sum] = v;
     cnt[o] = siz[o] = 1;
     return;
   }
   siz[o]++;
-  if (val[o] > v) insert(lc[o], v);
   if (val[o] == v) {
     cnt[o]++;
     return;
   }
+  if (val[o] > v) insert(lc[o], v);
   if (val[o] < v) insert(rc[o], v);
 }
 ```
 
 ### 删除一个元素
 
-定义 `delete(o,v)` 为在以 $o$ 为根节点的二叉搜索树中删除一个值为 $v$ 的节点。
+定义 `del(o,v)` 为在以 $o$ 为根节点的二叉搜索树中删除一个值为 $v$ 的节点。
 
 先在二叉搜索树中找到权值为 $v$ 的节点,分类讨论如下:
 
+若该节点的附加 $cnt$ 大于 $1$ ,只需要减少 $cnt$ 。
+
 若该节点的附加 $cnt$ 为 $1$ :
 
 若 $o$ 为叶子节点,直接删除该节点即可。
@@ -95,23 +101,33 @@ void insert(int o, int v) {
 时间复杂度 $O(h)$ 。
 
 ```cpp
-int deletemin(int o) {
-  if (!lc[o])
-    int ret = val[o], o = rc[o], return ret;
-  else
-    return deletemin(lc[o]);
+int deletemin(int& o) {
+  if (!lc[o]) {
+    int u = o;
+    o = rc[o];
+    return u;
+  } else {
+    int u = deletemin(lc[o]);
+    siz[o] -= cnt[u];
+    return u;
+  }
 }
-void delete (int& o, int v) {
+void del(int& o, int v) {
+  // 注意 o 有可能会被修改
   siz[o]--;
   if (val[o] == v) {
-    if (lc[o] && rc[o])
-      o = deletemin(rc[o]);
+    if (cnt[o] > 1) {
+      cnt[o]--;
+      return;
+    }
+    if (lc[o] && rc[o]) o = deletemin(rc[o]);
+    // 这里以找右子树的最小值为例
     else
       o = lc[o] + rc[o];
     return;
   }
-  if (val[o] > v) delete (lc[o], v);
-  if (val[o] < v) delete (rc[o], v);
+  if (val[o] > v) del(lc[o], v);
+  if (val[o] < v) del(rc[o], v);
 }
 ```
 
@@ -137,17 +153,18 @@ int queryrnk(int o, int v) {
 
 若其左子树的大小大于等于 $k$ ,则该元素在左子树中;
 
-若其左子树的大小在区间 $[k-1,k+cnt-1]$ 中,则该元素为子树的根节点;
+若其左子树的大小在区间 $[k-cnt,k-1]$ ( $cnt$ 为当前结点的值的出现次数)中,则该元素为子树的根节点;
 
-若其左子树的大小小于 $k+cnt-1$ ,则该元素在右子树中。
+若其左子树的大小小于 $k-cnt$ ,则该元素在右子树中。
 
 时间复杂度 $O(h)$ 。
 
 ```cpp
 int querykth(int o, int k) {
   if (siz[lc[o]] >= k) return querykth(lc[o], k);
-  if (siz[lc[o]] < k + cnt - 1)
+  if (siz[lc[o]] < k - cnt[o])
     return querykth(rc[o], k - siz[lc[o]] - cnt[o] + 1);
-  return o;
+  return val[o];
+  // 如要找排名为 k 的元素所对应的结点,直接 return o 即可
 }
 ```
index 015e6be..8da2f39 100644 (file)
@@ -7,7 +7,8 @@ author: HeRaNO, JuicyMio, Xeonacid, sailordiary, ouuan
 
 -   合并(Union):将两个子集合并成一个集合。
 
-\*也就是说,不支持集合的分离、删除。
+!!! warning
+    并查集不支持集合的分离、删除。
 
 ## 初始化
 
@@ -68,12 +69,12 @@ int find(int x) {
 
 ```cpp
 void unionSet(int x, int y) {
-  // x与y所在家族合并
+  // x 与 y 所在家族合并
   x = find(x);
   y = find(y);
   if (x == y)  //原本就在一个家族里就不管了
     return;
-  fa[x] = y;  //把x的祖先变成y的祖先的儿子
+  fa[x] = y;  //把 x 的祖先变成 y 的祖先的儿子
 }
 ```
 
@@ -81,7 +82,7 @@ void unionSet(int x, int y) {
 
 一个祖先突然抖了个机灵:「你们家族人比较少,搬家到我们家族里比较方便,我们要是搬过去的话太费事了。」
 
-由于需要我们支持的只有集合的合并、查询操作,当我们需要将两个集合合二为一时,无论将哪一个集合连接到另一个集合的下面,都能得到正确的结果。但不同的连接方法存在时间复杂度的差异。具体来说,如果我们将一棵点数与深度都较小的集合树连接到一棵更大的集合树下,显然相比于另一种连接方案,其期望复杂度更优(也会带来更优的最坏复杂度)。
+由于需要我们支持的只有集合的合并、查询操作,当我们需要将两个集合合二为一时,无论将哪一个集合连接到另一个集合的下面,都能得到正确的结果。但不同的连接方法存在时间复杂度的差异。具体来说,如果我们将一棵点数与深度都较小的集合树连接到一棵更大的集合树下,显然相比于另一种连接方案,接下来执行查找操作的用时更小(也会带来更优的最坏时间复杂度)。
 
 当然,我们不总能遇到恰好如上所述的集合————点数与深度都更小。鉴于点数与深度这两个特征都很容易维护,我们常常从中择一,作为估价函数。而无论选择哪一个,时间复杂度都为 $\Theta (m\alpha(m,n))$ ,具体的证明可参见 References 中引用的论文。
 
@@ -92,7 +93,7 @@ void unionSet(int x, int y) {
 此处给出一种 C++ 的参考实现,其选择点数作为估价函数:
 
 ```cpp
-int size[N];  //记录子树的大小
+std::vector<int> size(N, 1);  //记录并初始化子树的大小为 1
 void unionSet(int x, int y) {
   int xx = find(x), yy = find(y);
   if (xx == yy) return;
@@ -107,7 +108,15 @@ void unionSet(int x, int y) {
 
 ### 时间复杂度
 
-同时使用路径压缩和启发式合并之后,并查集的每个操作平均时间仅为 $O(\alpha(n))$ ,其中 $\alpha$ 为 [阿克曼函数](https://en.wikipedia.org/wiki/Ackermann_function) 的反函数,其增长极其缓慢,也就是说其单次操作的平均运行时间可以认为是一个很小的常数。
+同时使用路径压缩和启发式合并之后,并查集的每个操作平均时间仅为 $O(\alpha(n))$ ,其中 $\alpha$ 为阿克曼函数的反函数,其增长极其缓慢,也就是说其单次操作的平均运行时间可以认为是一个很小的常数。
+
+ [Ackermann 函数](https://en.wikipedia.org/wiki/Ackermann_function)  $A(n, m)$ 的定义是这样的:
+
+ $A(m, n) = \begin{cases}n+1&\text{if }m=0\\A(m-1,1)&\text{if }m>0\text{ and }n=0\\A(m-1,A(m,n-1))&\text{otherwise}\end{cases}$ 
+
+而反 Ackermann 函数 $\alpha(n)$ 的定义是阿克曼函数的反函数,即为最大的整数 $m$ 使得 $A(m, m) \leqslant n$ 。
+
+时间复杂度的证明 [在这个页面中](./dsu_complexy.md) 。
 
 ### 空间复杂度
 
diff --git a/docs/ds/dsu_complexy.md b/docs/ds/dsu_complexy.md
new file mode 100644 (file)
index 0000000..46212d1
--- /dev/null
@@ -0,0 +1,143 @@
+## 并查集时间复杂度证明
+
+本部分内容转载并修改自 [时间复杂度 - 势能分析浅谈](https://www.luogu.com.cn/blog/Atalod/shi-jian-fu-za-du-shi-neng-fen-xi-qian-tan) ,已取得原作者授权同意。
+
+这里,先给出 $\alpha(n)$ 的定义。为了给出这个定义,先给出 $A_k(j)$ 的定义。
+
+定义 $A_k(j)$ 为:
+
+$$
+A_k(j)=\left\{
+\begin{aligned}
+&j+1& &k=0&\\
+&A_{k-1}^{(j+1)}(j)& &k\geq1&
+\end{aligned}
+\right.
+$$
+
+即阿克曼函数。
+
+这里, $f^i(x)$ 表示将 $f$ 连续应用在 $x$ 上 $i$ 次,即 $f^0(x)=x$ , $f^i(x)=f(f^{i-1}(x))$ 。
+
+再定义 $\alpha(n)$ 为使得 $A_{\alpha(n)}(1)\geq n$ 的最小整数值。注意,我们之前将它描述为 $A_{\alpha(n)}(\alpha(n))\geq n$ ,反正他们的增长速度都很慢,值都不超过 4。
+
+## 基础定义
+
+每个节点都有一个 rank。这里的 rank 不是节点个数,而是深度。节点的初始 rank 为 0,在合并的时候,如果两个节点的 rank 不同,则将 rank 小的节点合并到 rank 大的节点上,并且不更新大节点的 rank 值。否则,随机将某个节点合并到另外一个节点上,将根节点的 rank 值 +1。这里根节点的 rank 给出了该树的高度。记 x 的 rank 为 $rnk(x)$ ,类似的,记 x 的父节点为 $fa(x)$ 。我们总有 $rnk(x)+1\leq rnk(fa(x))$ 。
+
+为了定义势函数,需要预先定义一个辅助函数 $level(x)$ 。其中, $level(x)=\max(k:rnk(fa(x))\geq A_k(rnk(x)))$ 。当 $rnk(x)\geq1$ 的时候,再定义一个辅助函数 $iter(x)=\max(i:rnk(fa(x))\geq A_{level(x)}^i(rnk(x))$ 。这些函数定义的 $x$ 都满足 $rnk(x)>0$ 且 $x$ 不是某个树的根。
+
+上面那些定义可能让你有点头晕。再理一下,对于一个 $x$ 和 $fa(x)$ ,如果 $rnk(x)>0$ ,总是可以找到一对 $i,k$ 令 $rnk(fa(x))\geq A_k^i(rnk(x))$ ,而 $level(x)=\max(k)$ ,在这个前提下, $iter(x)=\max(i)$ 。 $level$ 描述了 $A$ 的最大迭代级数,而 $iter$ 描述了在最大迭代级数时的最大迭代次数。
+
+对于这两个函数, $level(x)$ 总是随着操作的进行而增加或不变,如果 $level(x)$ 不增加, $iter(x)$ 也只会增加或不变。并且,它们总是满足以下两个不等式:
+
+$$
+0\leq level(x)<\alpha(n)
+$$
+
+$$
+1\leq iter(x)\leq rnk(x)
+$$
+
+考虑 $level(x)$ 、 $iter(x)$ 和 $A_k^j$ 的定义,这些很容易被证明出来,就留给读者用于熟悉定义了。
+
+定义势能函数 $\Phi(S)=\sum\limits_{x\in S}\Phi(x)$ ,其中 $S$ 表示一整个并查集,而 $x$ 为并查集中的一个节点。定义 $\Phi(x)$ 为:
+
+$$
+\Phi(x)=\left\{
+\begin{aligned}
+&\alpha(n)\times rnk(x)& &rnk(x)=0\text{ 或 x为某棵树的根节点}&\\
+&(\alpha(n)-level(x))\times rnk(x)-iter(x)& &otherwise&
+\end{aligned}\right.
+$$
+
+然后就是通过操作引起的势能变化来证明摊还时间复杂度为 $\Theta(\alpha(n))$ 啦。注意,这里我们讨论的 $union(x,y)$ 操作保证了 $x$ 和 $y$ 都是某个树的根,因此不需要额外执行 $find(x)$ 和 $find(y)$ 。
+
+可以发现,势能总是个非负数。另,在开始的时候,并查集的势能为 $0$ 。
+
+## union(x,y) 操作
+
+其花费的时间为 $\Theta(1)$ ,因此我们考虑其引起的势能的变化。
+
+这里,我们假设 $rnk(x)\leq rnk(y)$ ,即 $x$ 被接到 $y$ 上。这样,势能增加的节点仅有 $x$ (从树根变成非树根), $y$ (秩可能增加)和操作前 $y$ 的子节点(父节点的秩可能增加)。我们先证明操作前 $y$ 的子节点 $c$ 的势能不可能增加,并且如果减少了,至少减少 $1$ 。
+
+设操作前 $c$ 的势能为 $\Phi(c)$ ,操作后为 $\Phi(c')$ ,这里 $c$ 可以是任意一个 $rnk(c)>0$ 的非根节点,操作可以是任意操作,包括下面的 find 操作。我们分三种情况讨论。
+
+1.   $iter(c)$ 和 $level(c)$ 并未增加。显然有 $\Phi(c)=\Phi(c')$ 。
+2.   $iter(c)$ 增加了, $level(c)$ 并未增加。这里 $iter(c)$ 至少增加一,即 $\Phi(c')\leq \Phi(c)-1$ ,势能函数减少了,并且至少减少 1。
+3.   $level(c)$ 增加了, $iter(c)$ 可能减少。但是由于 $0<iter(c)\leq rnk(c)$ , $iter(c)$ 最多减少 $rnk(c)-1$ ,而 $level(c)$ 至少增加 $1$ 。由定义 $\Phi(c)=(\alpha(n)-level(c))\times rnk(c)-iter(c)$ ,可得 $\Phi(c')\leq\Phi(c)-1$ 。
+4.  其他情况。由于 $rnk(c)$ 不变, $rnk(fa(c))$ 不减,所以不存在。
+
+所以,势能增加的节点仅可能是 $x$ 或 $y$ 。而 $x$ 从树根变成了非树根,如果 $rnk(x)=0$ ,则一直有 $\Phi(x)=\Phi(x')=0$ 。否则,一定有 $\alpha(x)\times rnk(x)\geq(\alpha(n)-level(x))\times rnk(x)-iter(x)$ 。即, $\Phi(x')\leq \Phi(x)$ 。
+
+因此,唯一势能可能增加的点就是 $y$ 。而 $y$ 的势能最多增加 $\alpha(n)$ 。因此,可得 $union$ 操作均摊后的时间复杂度为 $\Theta(\alpha(n))$ 。
+
+## find(a) 操作
+
+如果查找路径包含 $\Theta(s)$ 个节点,显然其查找的时间复杂度是 $\Theta(s)$ 。如果由于查找操作,没有节点的势能增加,且至少有 $s-\alpha(n)$ 个节点的势能至少减少 $1$ ,就可以证明 $find(a)$ 操作的时间复杂度为 $\Theta(\alpha(n))$ 。为了避免混淆,这里用 $a$ 作为参数,而出现的 $x$ 都是泛指某一个并查集内的结点。
+
+首先证明没有节点的势能增加。很显然,我们在上面证明过所有非根节点的势能不增,而根节点的 $rnk$ 没有改变,所以没有节点的势能增加。
+
+接下来证明至少有 $s-\alpha(n)$ 个节点的势能至少减少 $1$ 。我们上面证明过了,如果 $level(x)$ 或者 $iter(x)$ 有改变的话,它们的势能至少减少 $1$ 。所以,只需要证明至少有 $s-\alpha(n)$ 个节点的 $level(x)$ 或者 $iter(x)$ 有改变即可。
+
+回忆一下非根节点势能的定义, $\Phi(x)=(\alpha(n)-level(x))\times rnk(x)-iter(x)$ ,而 $level(x)$ 和 $iter(x)$ 是使 $rnk(fa(x))\geq A_{level(x)}^{iter(x)}(rnk(x))$ 的最大数。
+
+所以,如果 $root_x$ 代表 $x$ 所处的树的根节点,只需要证明 $rnk(root_x)\geq A_{level(x)}^{iter(x)+1}(rnk(x))$ 就好了。根据 $A_k^i$ 的定义, $A_{level(x)}^{iter(x)+1}(rnk(x))=A_{level(x)}(A_{level(x)}^{iter(x)}(rnk(x)))$ 。
+
+注意,我们可能会用 $k(x)$ 代表 $level(x)$ , $i(x)$ 代表 $iter(x)$ 以避免式子过于冗长。这里,就是 $rnk(root_x)\geq A_{k(x)}(A_{k(x)}^{i(x)}(x))$ 。
+
+当你看到这的时候,可能会有一种“这啥玩意”的感觉。这意味着你可能需要多看几遍,或者跳过一些内容以后再看。
+
+这里,我们需要一个外接的 $A_{k(x)}$ ,意味着我们可能需要再找一个点 $y$ 。令 $y$ 是搜索路径上在 $x$ 之后的满足 $k(y)=k(x)$ 的点,这里“搜索路径之后”相当于“是 $x$ 的祖先”。显然,不是每一个 $x$ 都有这样一个 $y$ 。很容易证明,没有这样的 $y$ 的 $x$ 不超过 $\alpha(n)-2$ 个。因为只有每个 $k$ 的最后一个 $x$ 和 $a$ 以及 $root_a$ 没有这样的 $y$ 。
+
+我们再强调一遍 $fa(x)$ 指的是路径压缩 **之前**  $x$ 的父节点,路径压缩 **之后**  $x$ 的父节点一律用 $root_x$ 表示。对于每个存在 $y$ 的 $x$ ,总是有 $rnk(y)\geq rnk(fa(x))$ 。同时,我们有 $rnk(fa(x))\geq A_{k(x)}^{i(x)}(rnk(x))$ 。由于 $k(x)=k(y)$ ,我们用 $k$ 来统称,即, $rnk(fa(x))\geq A_k^{i(x)}(rnk(x))$ 。我们需要造一个 $A_k$ 出来,所以我们可以不关注 $iter(y)$ 的值,直接使用弱化版的 $rnk(fa(y))\geq A_k(rnk(y))$ 。
+
+如果我们将不等式组合起来,神奇的事情就发生了。我们发现, $rnk(fa(y))\geq A_k^{i(x)+1}(rnk(x))$ 。也就是说,为了从 $rnk(x)$ 迭代到 $rnk(fa(y))$ ,至少可以迭代 $A_k$ 不少于 $i(x)+1$ 次而不超过 $rnk(fa(y))$ 。
+
+显然,有 $rnk(root_y)\geq rnk(fa(y))$ ,且 $rnk(x)$ 在路径压缩时不变。因此,我们可以得到 $rnk(root_x)\geq A_k^{i(x)+1}(rnk(x))$ ,也就是说 $iter(x)$ 的值至少增加 1,如果 $rnk(x)$ 没有增加,一定是 $level(x)$ 增加了。
+
+所以, $\Phi(x)$ 至少减少了 1。由于这样的 $x$ 节点至少有 $s-\alpha(n)-2$ 个,所以最后 $\Phi(S)$ 至少减少了 $s-\alpha(n)-2$ ,均摊后的时间复杂度即为 $\Theta(\alpha(n)+2)=\Theta(\alpha(n))$ 。
+
+## 为何并查集会被卡
+
+这个问题也就是问,如果我们不按秩合并,会有哪些性质被破坏,导致并查集的时间复杂度不能保证为 $\Theta(m\alpha(n))$ 。
+
+如果我们在合并的时候, $rnk$ 较大的合并到了 $rnk$ 较小的节点上面,我们就将那个 $rnk$ 较小的节点的 $rnk$ 值设为另一个节点的 $rnk$ 值加一。这样,我们就能保证 $rnk(fa(x))\geq rnk(x)+1$ ,从而不会出现类似于满地 complie error 一样的性质不符合。
+
+显然,如果这样子的话,我们破坏的就是 $union(x,y)$ 函数「y 的势能最多增加 $\alpha(n)$ 」这一句。
+
+存在一个能使路径压缩并查集时间复杂度降至 $\Omega(m\log_{1+\frac{m}{n}}n)$ 的结构,定义如下:
+
+二项树(实际上和一般的二项树不太一样),其中 j 是常数, $T_k$ 为一个 $T_{k-1}$ 加上一个 $T_{k-j}$ 作为根节点的儿子。
+
+![我们的二项树](./images/dsu_complexy1.png)
+
+边界条件, $T_1$ 到 $T_j$ 都是一个单独的点。
+
+令 $rnk(T_k)=r_k$ ,这里我们有 $r_k=(k-1)/j$ (证明略)。每轮操作,我们将它接到一个单节点上,然后查询底部的 $j$ 个节点。也就是说,我们接到单节点上的时候,单节点的势能提高了 $(k-1)/j+1$ 。在 $j=\lfloor\frac{m}{n}\rfloor$ , $i=\lfloor\log_{j+1}\frac{n}{2}\rfloor$ , $k=ij$ 的时候,势能增加量为:
+
+$$
+\alpha(n)\times((ij-1)/j+1)=\alpha(n)\times((\lfloor\log_{\lfloor\frac{m}{n}\rfloor+1}\frac{n}{2}\rfloor\times \lfloor\frac{m}{n}\rfloor-1)/\lfloor\frac{m}{n}\rfloor+1)
+$$
+
+变换一下,去掉所有的取整符号,就可以得出,势能增加量 $\geq \alpha(n)\times(\log_{1+\frac{m}{n}}n-\frac{n}{m})$ ,m 次操作就是 $\Omega(m\log_{1+\frac{m}{n}}n-n)=\Omega(m\log_{1+\frac{m}{n}}n)$ 。
+
+## 关于启发式合并
+
+由于按秩合并比启发式合并难写,所以很多 dalao 会选择使用启发式合并来写并查集。具体来说,则是对每个根都维护一个 $size(x)$ ,每次将 $size$ 小的合并到大的上面。
+
+所以,启发式合并会不会被卡?
+
+首先,~~手推一下我们就可以发现那个数据卡不掉启发式合并~~可以从秩参与证明的性质来说明。如果 $size$ 可以代替 $rnk$ 的地位,则可以使用启发式合并。快速总结一下,秩参与证明的性质有以下三条:
+
+1.  每次合并,最多有一个节点的秩上升,而且最多上升 1。
+2.  总有 $rnk(fa(x))\geq rnk(x)+1$ 。
+3.  节点的秩不减。
+
+关于第二条和第三条, $siz$ 显然满足,然而第一条不满足,如果将 $x$ 合并到 $y$ 上面,则 $siz(y)$ 会增大 $siz(x)$ 那么多。
+
+所以,可以考虑使用 $\log_2 siz(x)$ 代替 $rnk(x)$ 。
+
+关于第一条性质,由于节点的 $siz$ 最多翻倍,所以 $\log_2 siz(x)$ 最多上升 1。关于第二三条性质,~~既得易见平凡~~。
+
+所以说,如果不想写按秩合并,就写启发式合并好了,时间复杂度仍旧是 $\Theta(m\alpha(n))$ 。
index 790f179..ea09815 100644 (file)
@@ -25,3 +25,5 @@
 用块状链表后除了单点修改是 $O(1)$ 外其他都是 $O(n^{\frac{1}{2}})$ 的。
 
  `ETT` 不支持换根操作。对于链(区间)修改,分为两种情况,一是贡献相同(如 $\operatorname{xor}$ ) 是可以的,二是贡献不同(如 $\operatorname{sum}$ ) 是不行的。现在的主流做法毕竟是 `LCT` ,所以这些操作比较多,在避开这种操作的情况下运用这种做法还是不错的。
+
+注:标准的 ETT(用欧拉回路而不是 dfs 括号序实现)是支持换根操作的,但是实现较为复杂。
diff --git a/docs/ds/images/dsu_complexy1.png b/docs/ds/images/dsu_complexy1.png
new file mode 100644 (file)
index 0000000..f2c2442
Binary files /dev/null and b/docs/ds/images/dsu_complexy1.png differ
index ebfe409..3bb5450 100644 (file)
@@ -25,7 +25,6 @@
 ## 动态树问题
 
 -   维护一个<font color="red">森林</font>, 支持删除某条边,加⼊某条边,并保证加边,删边之后仍是森林。我们要维护这个森林的一些信息。
-
 -   一般的操作有两点连通性,两点路径权值和,连接两点和切断某条边、修改信息等。
 
 * * *
 ### 从 LCT 的角度回顾一下树链剖分
 
 -   对整棵树按子树⼤小进⾏剖分,并重新标号。
-
 -   我们发现重新标号之后,在树上形成了一些以链为单位的连续区间,并且可以用线段树进⾏区间操作。
 
 ### 转向动态树问题
 
 -   我们发现我们刚刚讲的树剖是以子树⼤小作为划分条件。
-
 -   那我们能不能重定义一种剖分,使它更适应我们的动态树问题呢?
-
 -   考虑动态树问题需要什么链。
-
 -   由于动态维护⼀个森林,显然我们希望这个链是我们指定的链,以便利⽤来求解。
 
 ## <font color = "red">实链剖分</font>
 
 -   对于⼀个点连向它所有⼉子的边 , 我们⾃己选择⼀条边进行剖分,我们称被选择的边为实边,其他边则为虚边。
-
 -   对于实边,我们称它所连接的⼉子为实⼉子。
-
 -   对于⼀条由实边组成的链,我们同样称之为实链。
-
 -   请记住我们选择实链剖分的最重要的原因:它是我们选择的,灵活且可变。
-
 -   正是它的这种灵活可变性,我们采用 Splay Tree 来维护这些实链。
 
 ## LCT!
@@ -69,7 +60,6 @@
 ## - 辅助树
 
 -   我们先来看⼀看辅助树的一些性质,再通过一张图实际了解一下辅助树的具体结构。
-
 -   在本文里,你可以认为一些 Splay 构成了一个辅助树,每棵辅助树维护的是一棵树,一些辅助树构成了 LCT,其维护的是整个森林。
 
 1.  辅助树由多棵 Splay 组成,每棵 Splay 维护原树中的一条路径,且中序遍历这棵 Splay 得到的点序列,从前到后对应原树“从上到下”的一条路径。
 ### 考虑原树和辅助树的结构关系
 
 -   原树中的实链 : 在辅助树中节点都在一棵 Splay 中。
-
 -   原树中的虚链 : 在辅助树中,子节点所在 Splay 的 Father 指向父节点,但是父节点的两个儿子都不指向子节点。
-
 -   注意:原树的根不等于辅助树的根。
-
 -   原树的 Father 指向不等于辅助树的 Father 指向。
-
 -   辅助树是可以在满足辅助树、Splay 的性质下任意换根的。
-
 -   虚实链变换可以轻松在辅助树上完成,这也就是实现了动态维护树链剖分。
 
 ### 接下来要用到的变量声明
 
 -    `ch[N][2]` 左右⼉子
-
 -    `f[N]` ⽗亲指向
-
 -    `sum[N]` 路径权值和
-
 -    `val[N]` 点权
-
 -    `tag[N]` 翻转标记
-
 -    `laz[N]` 权值标记
-
 -    `siz[N]` 辅助树上子树大小
-
 -   Other_Vars
 
 ### 函数声明
@@ -246,13 +224,11 @@ inline int Access(int x) {
 ![pic](./images/lct5.png)
 
 -   下一步,我们把 $N$ 指向的 Father $I$ 也旋转到 $I$ 的 Splay 树根。
-
 -   原来的实边 $I$ — $K$ 要去掉,这时候我们把 $I$ 的右儿子指向 $N$ , 就得到了 $I$ — $L$ 这样一棵 Splay。
 
 ![pic](./images/lct8.png)
 
 -   接下来,按照刚刚的操作步骤,由于 $I$ 的 Father 指向 $H$ , 我们把 $H$ 旋转到他所在 Splay Tree 的根,然后把 $H$ 的 rs 设为 $I$ 。
-
 -   之后的树是这样的。
 
 ![pic](./images/lct6.png)
@@ -283,7 +259,6 @@ inline int Access(int x) {
 这里提供的 Access 还有一个返回值。这个返回值相当于最后一次虚实链变换时虚边父亲节点的值。该值有两个含义:
 
 -   连续两次 Access 操作时,第二次 Access 操作的返回值等于这两个节点的 LCA.
-
 -   表示 $x$ 到根的链所在的 Splay 树的根。这个节点一定已经被旋转到了根节点,且父亲一定为空。
 
 ###  `Update()` 
@@ -359,11 +334,13 @@ inline void Cut(int x, int p) {
 
 -    `Find()` 其实就是找到当前辅助树的根。在 `Access(p)` 后,再 `Splay(p)` 。这样根就是树里最小的那个,一直往 ls 走,沿途 `PushDown` 即可。
 -   一直走到没有 ls, 非常简单。
+-   注意,每次查询之后需要把查询到的答案对应的结点 `Splay` 上去以保证复杂度。
 
 ```cpp
 inline int Find(int p) {
   Access(p), Splay(p);
   while (ls) pushDown(p), p = ls;
+  Splay(p);
   return p;
 }
 ```
index 34f61ed..e7d6c49 100644 (file)
@@ -19,6 +19,7 @@
 
 如果要保证复杂度正确,必须保证数据随机。
 证明在 [此](http://codeforces.com/blog/entry/56135?#comment-398940) 。
+补充一个更详细的严格证明: [看这里](https://zhuanlan.zhihu.com/p/102786071) 。对于 add,assign 和 sum 操作,用 set 实现的珂朵莉树的复杂度为 $O(n \log \log n)$ ,而用链表实现的复杂度为 $O(n \log n)$ 。
 
 ## 正文
 
index 5e64312..bffe3eb 100644 (file)
@@ -1,6 +1,6 @@
 可持久化可并堆一般用于求解 $k$ 短路问题。
 
-å¦\82æ\9e\9cä¸\80ç§\8då\8f¯å¹¶å \86ç\9a\84æ\97¶é\97´å¤\8dæ\9d\82度ä¸\8dæ\98¯å\9d\87æ\91\8aç\9a\84ï¼\8cé\82£ä¹\88å®\83å°±å\8f¯ä»¥å\8f¯æ\8c\81ä¹\85化。
+å¦\82æ\9e\9cä¸\80ç§\8då\8f¯å¹¶å \86ç\9a\84æ\97¶é\97´å¤\8dæ\9d\82度ä¸\8dæ\98¯å\9d\87æ\91\8aç\9a\84ï¼\8cé\82£ä¹\88å®\83å\9c¨å\8f¯æ\8c\81ä¹\85å\8c\96å\90\8eå\8d\95次æ\93\8dä½\9cç\9a\84æ\97¶é\97´å¤\8dæ\9d\82度就ä¿\9dè¯\81æ\98¯ $O(\log n)$ ç\9a\84ï¼\8cå\8d³ä¸\8dä¼\9aå\9b ä¸ºç\89¹æ®\8aæ\95°æ\8d®è\80\8c使å¤\8dæ\9d\82度é\80\80化。
 
 ## 可持久化左偏树
 
index e22bc6d..cf9d46c 100644 (file)
@@ -1,6 +1,6 @@
 ## Pick 定理
 
-Pick å®\9aç\90\86ï¼\9aç»\99å®\9a顶ç\82¹åº§标均是整点(或正方形格子点)的简单多边形,皮克定理说明了其面积 ${\displaystyle A}$ 和内部格点数目 ${\displaystyle i}$ 、边上格点数目 ${\displaystyle b}$ 的关系: ${\displaystyle A=i+{\frac {b}{2}}-1}$ 。
+Pick å®\9aç\90\86ï¼\9aç»\99å®\9a顶ç\82¹å\9d\90标均是整点(或正方形格子点)的简单多边形,皮克定理说明了其面积 ${\displaystyle A}$ 和内部格点数目 ${\displaystyle i}$ 、边上格点数目 ${\displaystyle b}$ 的关系: ${\displaystyle A=i+{\frac {b}{2}}-1}$ 。
 
 具体证明: [Pick's theorem](https://en.wikipedia.org/wiki/Pick%27s_theorem) 
 
@@ -44,18 +44,18 @@ int main() {
     int n, dx, dy, x, y, num = 0, sum = 0;
     scanf("%d", &n);
     p[0].x = 0, p[0].y = 0;
-    for (int i = 1; i &lt; = n; i++) {
+    for (int i = 1; i <= n; i++) {
       scanf("%d%d", &x, &y);
       p[i].x = x + p[i - 1].x, p[i].y = y + p[i - 1].y;
       dx = x, dy = y;
-      if (x & lt; 0) dx = -x;
-      if (y & lt; 0) dy = -y;
+      if (x < 0) dx = -x;
+      if (y < 0) dy = -y;
       num += gcd(dx, dy);
       sum += area(i - 1, i);
     }
-    if (sum & lt; 0) sum = -sum;
-    printf("Scenario #%d:\\n", ncase++);
-    printf("%d %d %.1f\\n\\n", (sum - num + 2) >> 1, num, sum \* 0.5);
+    if (sum < 0) sum = -sum;
+    printf("Scenario #%d:\n", ncase++);
+    printf("%d %d %.1f\n\n", (sum - num + 2) >> 1, num, sum * 0.5);
   }
   return 0;
 }
diff --git a/docs/graph/basic.md b/docs/graph/basic.md
deleted file mode 100644 (file)
index 09ac384..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-## 图是怎么存的?
-
-### 直接存边
-
-什么意思呢?我们开一个数组,数组里每个元素是图的一条边。
-
-这样做有个缺点,每次想要知道两个点之间是否有连边(或者说一条边是否存在),都需要在数组里进行一番查找。而且如果没有对边事先排序的话,就不能使用二分查找的方法( $O(\log n)$ ),而是每次只能按顺序找( $O(n)$ ),成本较高。
-
-什么时候会用到这个方法呢?最简单的一个例子是使用 Kruskal 算法求 [最小生成树](/graph/mst) 的时候。
-
-### 邻接矩阵
-
-邻接矩阵的英文名是 adjacency matrix。它的形式是 `bool adj[n][n]` ,这里面 $n$ 是节点个数, $adj[i][j]$ 表示 $i$ 和 $j$ 之间是否有边。
-
-如果边有权值,也可以直接用 `int adj[n][n]` ,直接把边权存进去。
-
-它的优点是可以在 $O(1)$ 时间内得到一条边是否存在,缺点是需要占用 $O(n^2)$ 的空间。对于一个稀疏的图(边相对于点数的平方比较少)来说,用邻接矩阵来存的话,成本偏高。
-
-### 邻接表
-
-邻接表英文名是 adjacency list。它的形式是 `vector adj[n]` ,用 `adj[i]` 存以 $i$ 为起点的边。
-
-用 `vector` 无法科学地删除,所以常用 `list` 实现。
-
-它的特点是可以用来按顺序访问一个结点的出边(或者入边)。
-
-### 前向星
-
-为什么它搜不到英文名呢?因为是中国玩家乱搞出来的。
-
-首先介绍一下链式前向星,本质上是用单向链表实现的邻接表。
-
-形式上是一个结构体: `struct edge {edge *pre, int to;} *head[N], edge[M]` 
-
-这个结构广泛出现于算法竞赛选手的代码中,编写简洁而且对于大多数题目效率足够高。
-
-其中 `head[i]` 用来存以 $i$ 为起点的边, `edge` 数组是边表。
-
-那么什么是前向星呢?事先把 `edge` 数组排个序即可。这里可以使用 [基数排序](/basic/radix-sort) 做到 $O(m)$ 。
-
-## 图的基本概念
-
-### 路径
-
-path,是指一个边的序列,其中的边首尾相连。
-
-### 简单路径
-
-simple path,是每条边只经过了一次的路径。
-
-### 回路
-
-cycle,也称为 `环` ,是起点和终点相同的路径。
-
-### 简单回路
-
-图的定点序列中,除了起点和终点相同外,其余顶点不重复的回路。
-
-### 可达
-
-有向图中点 $u$ 到 $v$ 可达是指存在一条 $u$ 到 $v$ 的路径。
-
-### 连通
-
-#### 两个点连通
-
-图中点 $u$ 和 $v$ 连通是指两点互相可达。
-
-#### 图连通
-
-如果无向图 $G$ 中任意两个节点连通,称其为是连通的。
-
-###  [强连通](/graph/scc) 
-
-有向图 $G$ 强连通是指, $G$ 中任意两个节点连通。
-
-###  [弱连通](/graph/bcc) 
-
-有向图 $G$ 弱连通是指, $G$ 中的所有边替换为无向边后, $G$ 为连通图。
-
-### 点连通度
-
-一张图的点连通度的大小等于最小点割集的大小。
-
-### 边连通度
-
-一张图的边连通度的大小等于最小边割集的大小。
-
-### 点割集
-
-设图 $G = <V, E>$ ,若存在 $V' \subset V$ 且 $V' \neq \emptyset$ ,使得 $p(G-V') > p(G)$ ,而对于任意的 $V'' \subset V'$ ,均有 $p(G-V'')=p(G)$ ,则称 $V'$ 是 $G$ 的点割集。特别地,若 $V'$ 是 $G$ 的点割集,且 $V'$ 是单元集,即 $V'=\{v\}$ ,则称 $v$ 为 [割点](./bridge.md) 。
-
-( $p(G)$ 表示图 G 的连通分支(连通块)的个数)
-
-### 边割集
-
-设图 $G = <V, E>$ ,若存在 $E' \subset E$ 且 $E' \neq \emptyset$ ,使得 $ps(G-E') > p(G)$ ,而对于任意的 $E'' \subset E'$ ,均有 $p(G-E'')=p(G)$ ,则称 $E'$ 是 $G$ 的边割集(或简称为割集)。特别地,若 $E'$ 是 $G$ 的边割集,且 $E'$ 是单元集,即 $E'=\{e\}$ ,则称 $e$ 为 [桥](./bridge.md) 。
-
-( $p(G)$ 表示图 G 的连通分支(连通块)的个数)
-
-### 子图
-
-选取一个节点的子集和边的子集构成的图。
-
-#### 生成子图
-
-选取的子图的节点和原图一样。
-
-#### 导出子图
-
-选取一个节点的子集,再选取这些节点相关联的边的集合构成的图。
-
-#### 边导出子图
-
-选取一个边的子集,再选取这些边相关联的节点的集合,构成的图。
-
-#### 连通子图
-
-(一个无向图的)连通的子图。
-
-#### 连通分量
-
-(一个无向图的)极大的连通子图。
-
-【注】:极大是指添加任何节点或者边后都不再满足。
-
-### 稀疏图
-
- $m = \Theta(n)$ 的图,或者指 $m$ 相对较小的图。
-
-### 稠密图
-
- $m = \Theta(n^2)$ 的图,或者指 $m$ 相对较大的图。
-
-### 完全图
-
-设 $D$ 为 $n (n \geq 1)$ 阶无向简单图,弱 $G$ 中每个顶点均与其余的 $n-1$ 个顶点相邻,则称 $D$ 为 $n$ 阶无向完全图。
-
-无向完全图的点数和边数满足这样的关系: $m = \frac{n(n-1)}{2}$ 。
-
-设 $D$ 为 $n (n \geq 1)$ 阶有向简单图,若对于任意的 $v_i, v_j \in V(D)(v_i \neq v_j)$ ,有向边 $<v_i, v_j>$ 和 $<v_j, v_i>$ 均属于 $E(D)$ ,则称 $D$ 为 $n$ 阶有向完全图。
-
-### 竞赛图
-
-设 $D$ 为 $n (n \geq 1)$ 阶有向简单图,若对于任意的 $v_i, v_j \in V(D)(v_i \neq v_j)$ ,有向边 $<v_i, v_j>$ 和 $<v_j, v_i>$ 中有且仅有一个属于 $E(D)$ ,则称 $D$ 为 $n$ 阶竞赛图。
-
-### 正则图
-
-各顶点的度均相同的无向简单图。
-
-### 路径的长度
-
-一般来说,路径的长度在数值上等于路径的边数,或者如果边是带权的,则是路径的边权和。
-
-###  [最短路径](/graph/shortest-path) 
-
-两个节点之间,长度最小的路径。
-
-【注】:不一定存在,不一定唯一。
-
-### 图论基本定理
-
-又称握手定理。设 $G=<V, E>$ 为一个无向图, $V= \{v_1, v_2, \cdots, v_n\}, |E| = m$ ,则 $\sum_{i=1}^n{d(v_i)}=2m$ 。其中 $d(v)$ 表示 v 的度数。
-
-### 可图化
-
-如果给定一个序列 a,可以找到一个图 G,以其为度数列,则称 a 是可图化的。
-
-如果给定一个序列 a,可以找到一个简单图 G,以其为度数列,则称 a 是可简单图化的。
-
-#### 判别法
-
- $a=(a_1, a_2, \cdots, a_n)$ 可图化当且仅当 $\sum_{i=1}^n{d_i} = 0 \pmod 2$ 
-
- $a=(a_1, a_2, \cdots, a_n)$ 可简单图化当且仅当 $a'=(a_2 - 1, a_3 - 1, \cdots, a_{a_1+1} - 1, a_{a_1+2} - 1, \cdots, a_n)$ 是可简单图化的。
-
-### Whitney 定理
-
-对任意的图 $G$ ,有 $\kappa \leq \lambda \leq \delta$ 。其中 $\kappa, \lambda, \delta$ 分别为 $G$ 的点连通度,边连通度和最小度。
index 3f78d35..b6b5e9f 100644 (file)
@@ -1,12 +1,12 @@
 ## 简介
 
-在阅读下列内容之前,请务必了解 [图论基础](./basic.md) 部分。
+在阅读下列内容之前,请务必了解 [图论相关概念](./concept.md) 部分。
 
-相关阅读: [割点和桥](./bridge.md) 
+相关阅读: [割点和桥](./cut.md) 
 
 ## 定义
 
-割点和桥更严谨的定义参见 [图论基础](./basic.md) 。
+割点和桥更严谨的定义参见 [图论相关概念](./concept.md) 。
 
 在一张连通的无向图中,对于两个点 $u$ 和 $v$ ,如果无论删去哪条边(只能删去一条)都不能使它们不连通,我们就说 $u$ 和 $v$  **边双连通** 。
 
@@ -16,7 +16,7 @@
 
 点双连通 **不** 具有传递性,反例如下图, $A,B$ 点双连通, $B,C$ 点双连通,而 $A,C$  **不** 点双连通。
 
-![bcc-counterexample.png](images/bcc-0.svg)
+![bcc-counterexample.png](./images/bcc-0.svg)
 
 ## DFS
 
@@ -38,7 +38,7 @@ void DFS(int p) {
 
 首先,对原图进行 DFS。
 
-![bcc-1.png](images/bcc-1.svg)
+![bcc-1.png](./images/bcc-1.svg)
 
 如上图所示,黑色与绿色边为树边,红色边为非树边。每一条非树边连接的两个点都对应了树上的一条简单路径,我们说这条非树边 **覆盖** 了这条树上路径上所有的边。绿色的树边 **至少** 被一条非树边覆盖,黑色的树边不被 **任何** 非树边覆盖。
 
@@ -52,7 +52,7 @@ void DFS(int p) {
 
 ## DFS 找割点并判断点双连通
 
-![bcc-2.png](images/bcc-2.svg)
+![bcc-2.png](./images/bcc-2.svg)
 
 如上图所示,黑色边为树边,红色边为非树边。每一条非树边连接的两个点都对应了树上的一条简单路径。
 
index c3f9f04..713aa3d 100644 (file)
@@ -43,14 +43,14 @@ void bfs(int u) {
   d[u] = 0;
   p[u] = -1;
   while (!Q.empty()) {
-    u = Q.pop() {
-      for (int i = head[u]; i; i = e[i].x) {
-        if (!vis[e[i].t]) {
-          Q.push(e[i].t);
-          vis[e[i].t] = 1;
-          d[e[i].t] = d[u] + 1;
-          p[e[i].t] = u;
-        }
+    u = Q.front();
+    Q.pop();
+    for (int i = head[u]; i; i = e[i].x) {
+      if (!vis[e[i].t]) {
+        Q.push(e[i].t);
+        vis[e[i].t] = 1;
+        d[e[i].t] = d[u] + 1;
+        p[e[i].t] = u;
       }
     }
   }
@@ -168,14 +168,15 @@ while (队列不为空) {
 ```cpp
 #include <bits/stdc++.h>
 using namespace std;
+
 #define INF (1 << 29)
 int n, m;
 char grid[1001][1001];
 int dist[1001][1001][4];
-int vis[1001][1001][4];
 int fx[] = {1, -1, 0, 0};
 int fy[] = {0, 0, 1, -1};
 deque<int> q;
+
 void add_front(int x, int y, int dir, int d) {
   if (d < dist[x][y][dir]) {
     dist[x][y][dir] = d;
@@ -184,6 +185,7 @@ void add_front(int x, int y, int dir, int d) {
     q.push_front(x);
   }
 }
+
 void add_back(int x, int y, int dir, int d) {
   if (d < dist[x][y][dir]) {
     dist[x][y][dir] = d;
@@ -192,6 +194,7 @@ void add_back(int x, int y, int dir, int d) {
     q.push_back(dir);
   }
 }
+
 int main() {
   cin >> n >> m;
   for (int i = 0; i < n; i++) cin >> grid[i];
@@ -207,8 +210,6 @@ int main() {
     q.pop_front();
     q.pop_front();
     q.pop_front();
-    if (vis[x][y][dir]) continue;
-    vis[x][y][dir] = true;
     int d = dist[x][y][dir];
     int nx = x + fx[dir], ny = y + fy[dir];
     if (nx >= 0 && nx < n && ny >= 0 && ny < m) add_front(nx, ny, dir, d);
index f6050b4..84eb827 100644 (file)
 
 ### 二分图匹配
 
+#### 匹配
+
+设 $G$ 为二分图,若在 $G$ 的子图 $M$ 中,任意两条边都没有公共节点,那么称 $M$ 为二分图 $G$ 的一个匹配,且 $M$ 的边数为匹配数。
+
+#### 完备匹配
+
+设 $G=<V_1, V_2, E>$ 为二分图, $|V_1| \leq |V_2|$ , $M$ 为 $G$ 中一个最大匹配,且 $|M|=2|V_1|$ ,则称 $M$ 为 $V_1$ 到 $V_2$ 的完备匹配。
+
 #### 霍尔定理
 
-设二图 $G=<V_1, V_2, E>, |V_1| \leq |V_2|$ ,则 $G$ 中存在 $V_1$ 到 $V_2$ 的完备匹配当且仅当对于任意的 $S \subset V_1$ ,均有 $|S|\leq|N(S)|$ ,其中 $N(S)=\Cup_{v_i \in S}{N(V_i)}$ ,是 $S$ 的邻域。
+设二图 $G=<V_1, V_2, E>, |V_1| \leq |V_2|$ ,则 $G$ 中存在 $V_1$ 到 $V_2$ 的完备匹配当且仅当对于任意的 $S \subset V_1$ ,均有 $|S|\leq|N(S)|$ ,其中 $N(S)=\Cup_{v_i \in S}{N(V_i)}$ ,是 $S$ 的邻域。
 
 #### 最大匹配
 
+寻找二分图边数最大的匹配称为最大匹配问题。
+
+对此,有解决此问题的 **匈牙利算法** ,时间复杂度为 $O(NM)$ 。
+
+算法步骤大致如下:
+
+1.  首先从任意一个未配对的点 $u$ 开始,选择他的任意一条边( $u$ - $v$ ),如此时 $v$ 还未配对,则配对成功,配对数加一,若 $v$ 已经配对,则尝试寻找 $v$ 的配对的另一个配对(该步骤可能会被递归的被执行多次),若该尝试成功,则配对成功,配对数加一。
+
+2.  若果上一步配对不成功,那么选择重新选择一条未被选择过的边,重复上一步。
+
+3.  对剩下每一个没有被配对的点执行步骤 1,直到所有的点都尝试完毕。
+
+用下面的二分图为例:
+
+![](./images/bi-graph-1.png)
+
+先对节点 1 和 2 尝试匹配,假设他们分别找到了 4 和 5。
+
+![](./images/bi-graph-2.png)
+
+接下来对节点 3 尝试匹配,选择边(3-4),但发现 4 已经有匹配了,我们尝试寻找 4 的匹配的其他匹配,即 1 的其他匹配。
+这个匹配显然只能从未被选择的边里找(灰色的),我们可以遍历 1 的所有边,寻找未被选择的,很容易找到边(1-5)。
+
+我们发现 5 已经被匹配了,所以我们尝试寻找 5 的匹配的其他匹配,即 2 的其他匹配。类似的,可以找到 6。
+
+![](./images/bi-graph-3.png)
+
+于是我们得到了新的匹配方案,且该方案比之前的匹配数多一。
+
+![](./images/bi-graph-4.png)
+
+可以发现,当尝试对节点 3 进行匹配时,走过了一条路径(3-4-1-5-2-6),最后找到了新的匹配方案,我们把这样的道路叫做 **增广路** ,其本质是一条起点和终点都是未匹配节点的路径。
+
+匈牙利算法执行的过程也可以看作是不断寻找增广路的过程,当在当前匹配方案下再也找不到增广路,那么当前匹配方案便是最大匹配了。
+
+代码如下:
+
+```cpp
+#include <bits/stdc++.h>
+using namespace std;
+const int N = 2e3 + 10;
+int n, m, e;
+vector<int> G[N];  //使用邻接表来储存边
+int match[N], vis[N];
+bool dfs(int u) {
+  int len = G[u].size();
+  for (int i = 0; i < len; i++) {  //遍历每一条边
+    int v = G[u][i];
+    if (vis[v]) continue;
+    vis[v] = 1;
+    if (!match[v] ||
+        dfs(match[v])) {  //如果v没有匹配,或者v的匹配找到了新的匹配
+      match[v] = u;
+      match[u] = v;  //更新匹配信息
+      return 1;
+    }
+  }
+  return 0;
+}
+int main() {
+  scanf("%d %d %d", &n, &m, &e);
+  for (int i = 1; i <= e; i++) {
+    int a, b;
+    scanf("%d %d", &a, &b);
+    if (a > n || b > m) continue;
+    G[a].push_back(n + b);
+    G[n + b].push_back(a);
+  }
+  int ans = 0;
+  for (int i = 1; i <= n; i++) {  //对每一个点尝试匹配
+    for (int j = 1; j <= n + m; j++) vis[j] = 0;
+    if (dfs(i)) ans++;
+  }
+  printf("%d", ans);
+  return 0;
+}
+```
+
+除此之外,该问题还可以转化为 [最大流](graph/flow/max-flow) 问题解决。
+
+设 $G=<V_1, V_2, E>$ 是一个二分图,不妨在图中添加源点 $s$ 和汇点 $t$ ,从 $s$ 向 $V_1$ 中的所有节点连一条流量为 1 的边, $V_2$ 中的所有节点也向 $t$ 连一条流量为 1 的边,并且将 $V_1$ 和 $V_2$ 之间的边改成从 $V_1$ 指向 $V_2$ ,流量为 1 的边。此时该图的最大流量即为最大匹配数,流量流过的边和点构成的子图即为 $G$ 的最大匹配。
+
+若使用 Dinic 算法,则时间复杂度为 $O(N \sqrt{M+N})$ 。
+
+例题参考:
+
+ [洛谷 P3386【模板】二分图匹配](https://www.luogu.com.cn/problem/P3386) 
+
 #### 最大权匹配
 
-## 一般图匹配
+设 $G$ 为带边权的二分图,寻找 $G$ 边权和最大的匹配称为最大权匹配问题。
+
+该问题可以转化为 [费用流](graph/flow/min-cost) 问题解决。
+
+设 $G=<V_1, V_2, E>$ 是一个带边权的二分图,不妨在图中添加源点 $s$ 和汇点 $t$ ,从 $s$ 向 $V_1$ 中的所有节点连一条流量为 1,费用为 0 的边,从 $V_1$ 和 $V_2$ 的所有节点向 $t$ 连一条流量为 1,费用为 0 的边,并且将 $V_1$ 和 $V_2$ 之间的边改成从 $V_1$ 指向 $V_2$ ,流量为 1,费用为边权的边。此时该图的最大费最大流的费用即为最大权匹配的边权和,流量流过的边和点构成的子图(删去新添加的点和边后)即为 $G$ 的最大权匹配。
+
+### 一般图匹配
+
+对于一个图 $G(V, E)$ ,它的匹配 $M$ 是二元组 $(u, v)$ 组成的集合,其中 $u, v \in V, (u, v) \in E$ ,并且 $M$ 中不存在重复的点。
+
+当 $|M|$ 最大的时候,我们称 $M$ 为 $G$ 的最大匹配。
+
+该问题可以使用带花树算法或 Tutte 矩阵来解决。
diff --git a/docs/graph/concept.md b/docs/graph/concept.md
new file mode 100644 (file)
index 0000000..16be512
--- /dev/null
@@ -0,0 +1,319 @@
+本页面概述了图论中的一些概念,这些概念并不全是在 OI 中常见的,对于 OIer 来说,只需掌握本页面中的基础部分即可,如果在学习中碰到了不懂的概念,可以再来查阅。
+
+!!! warning
+    图论相关定义在不同教材中往往会有所不同,遇到的时候需根据上下文加以判断。
+
+## 图
+
+ **图 (Graph)** 是一个二元组 $(V, E)$ ,其中 $V$ 和 $E$ 为集合(多重集)。图常用 $G$ , $H$ 等表示,如: $G = (V, E)$ 。
+
+图分为 **无向图 (Undirected graph)** 和 **有向图 (Directed graph)** 两种,若 $G$ 为无向图,则 $E$ 中的每个元素为一个无序二元组 $(u, v)$ ,称作 **无向边 (Undirected edge)** ,简称 **边 (Edge)** ,其中 $u, v \in V$ 。设 $e = (u, v)$ ,则 $u$ 和 $v$ 称为 $e$ 的 **端点 (Endpoint)** 。
+
+若 $G$ 为有向图,则 $E$ 中的每一个元素为一个有序二元组 $(u, v)$ ,有时也写作 $u \to v$ ,称作 **有向边 (Directed edge)** 或 **弧 (Arc)** ,在不引起混淆的情况下也可以称作 **边 (Edge)** 。设 $e = u \to v$ ,则此时 $u$ 称为 $e$ 的 **起点 (Tail)** , $v$ 称为 $e$ 的 **终点 (Head)** ,起点和终点也称为 $e$ 的 **端点 (Endpoint)** 。
+
+???+note "为什么起点是 Tail,终点是 Head?"
+    边通常用箭头表示,而箭头是从“尾”指向“头”的。
+
+对于 $V$ 中的每个元素,我们称其为 **顶点 (Vertex)** 或 **节点 (Node)** ,简称 **点** ,顶点的集合称为 **点集 (Vertex set)** ,边的集合称为 **边集 (Edge set)** 。
+
+图 $G$ 的点集和边集可以表示为 $V(G)$ 和 $E(G)$ ,在不引起混淆的情况下,也能表示成 $V$ 和 $E$ 。图 $G$ 的点数 $\left| V(G) \right|$ 也被称作图 $G$ 的 **阶 (Order)** 。
+
+形象地说,图是由若干点以及连接点与点的边构成的。
+
+## 简单图
+
+ **自环 (Loop)** :对 $E$ 中的边 $e = (u, v)$ ,若 $u = v$ ,则 $e$ 被称作一个自环。
+
+ **重边 (Multiple edge)** :若 $E$ 中存在两个完全相同的元素(边) $e_1, e_2$ ,则它们被称作(一组)重边。
+
+ **简单图 (Simple graph)** :若一个图中没有自环和重边,它被称为简单图。
+
+如果一张图中有自环或重边,则称它为 **重图 (Multigraph)** 。
+
+!!! warning
+    在无向图中 $(u, v)$ 和 $(v, u)$ 算一组重边,而在有向图中, $u \to v$ 和 $v \to u$ 不为重边。
+
+!!! warning
+    在题目中,如果没有特殊说明,是可以存在自环和重边的,在做题时需特殊考虑。
+
+## 相邻
+
+在无向图 $G = (V, E)$ 中,若点 $v$ 是边 $e$ 的一个端点,则称 $v$ 和 $e$ 是 **关联的 (Incident)** 或 **相邻的 (Adjacent)** 。对于两顶点 $u$ 和 $v$ ,若存在边 $(u, v)$ ,则称 $u$ 和 $v$ 是 **相邻的 (Adjacent)** 。
+
+一个顶点 $v \in V$ 的 **邻域 (Neighborhood)** 是所有与之相邻的顶点所构成的集合,记作 $N(v)$ 。
+
+一个点集 $S$ 的邻域是所有与 $S$ 中至少一个点相邻的点所构成的集合,记作 $N(S)$ ,即:
+
+$$
+N(S) = \bigcup_{v \in S} N(v)
+$$
+
+## 度数
+
+与一个顶点 $v$ 关联的边的条数称作该顶点的 **度 (Degree)** ,记作 $d(v)$ 。特别地,对于边 $(v, v)$ ,则每条这样的边要对 $d(v)$ 产生 $2$ 的贡献。
+
+对于无向简单图,有 $d(v) = \left| N(v) \right|$ 。
+
+握手定理(又称图论基本定理):对于任何无向图 $G = (V, E)$ ,有 $\sum_{v \in V} d(v) = 2 \left| E \right|$ 。
+
+推论:在任意图中,度数为奇数的点必然有偶数个。
+
+若 $d(v) = 0$ ,则称 $v$ 为 **孤立点 (Isolated vertex)** 。
+
+若 $d(v) = 1$ ,则称 $v$ 为 **叶节点 (Leaf vertex)** / **悬挂点 (Pendant vertex)** 。
+
+若 $2 \mid d(v)$ ,则称 $v$ 为 **偶点 (Even vertex)** 。
+
+若 $2 \nmid d(v)$ ,则称 $v$ 为 **奇点 (Odd vertex)** 。图中奇点的个数是偶数。
+
+若 $d(v) = \left| V \right| - 1$ ,则称 $v$ 为 **支配点 (Universal vertex)** 。
+
+对一张图,所有节点的度数的最小值称为 $G$ 的 **最小度 (Minimum degree)** ,记作 $\delta (G)$ ;最大值称为 **最大度 (Maximum degree)** ,记作 $\Delta (G)$ 。即: $\delta (G) = \min_{v \in G} d(v)$ , $\Delta (G) = \max_{v \in G} d(v)$ 。
+
+在有向图 $G = (V, E)$ 中,以一个顶点 $v$ 为起点的边的条数称为该顶点的 **出度 (Out-degree)** ,记作 $d^+(v)$ 。以一个顶点 $v$ 为终点的边的条数称为该节点的 **入度 (In-degree)** ,记作 $d^-(v)$ 。
+
+对于任何有向图 $G = (V, E)$ ,有:
+
+$$
+\sum_{v \in V} d^+(v) = \sum_{v \in V} d^-(v) = \left| E \right|
+$$
+
+若对一张无向图 $G = (V, E)$ ,每个顶点的度数都是一个固定的常数 $k$ ,则称 $G$ 为 ** $k$ - 正则图 ( $k$ -Regular Graph)** 。
+
+如果给定一个序列 a,可以找到一个图 G,以其为度数列,则称 a 是 **可图化** 的。
+
+如果给定一个序列 a,可以找到一个简单图 G,以其为度数列,则称 a 是 **可简单图化** 的。
+
+## 路径
+
+ **途径 (Walk)** / **链 (Chain)** :一个点和边的交错序列,其中首尾是点—— $v_0, e_1, v_1, e_2, v_2, \ldots, e_k, v_k$ ,有时简写为 $v_0 \to v_1 \to v_2 \to \cdots \to v_k$ 。其中 $e_i$ 的两个端点分别为 $v_{i-1}$ 和 $v_i$ 。通常来说,边的数量 $k$ 被称作这条途径的 **长度** (如果边是带权的,长度通常指路径上的边权之和,题目中也可能另有定义)。(以下设 $w = \left[ v_0, e_1, v_1, e_2, v_2, \cdots, e_k, v_k \right]$ 。)
+
+ **迹 (Trail)** :对于一条途径 $w$ ,若 $e_1, e_2, \cdots, e_k$ 两两互不相同,则称 $w$ 是一条迹。
+
+ **路径 (Path)** (又称 **简单路径 (Simple path)** ):对于一条迹 $w$ ,除了 $v_0$ 和 $v_k$ 允许相同外,其余点两两互不相同,则称 $w$ 是一条路径。
+
+ **回路 (Circuit)** :对于一个迹 $w$ ,若 $v_0 = v_k$ ,则称 $w$ 是一个回路。
+
+ **环/圈 (Cycle)** (又称 **简单回路/简单环 (Simple circuit)** ):对于一条简单路径 $w$ ,若 $v_0 = v_k$ ,则称 $w$ 是一个环。
+
+!!! warning
+    关于路径的定义在不同地方可能有所不同,如,“路径”可能指本文中的“途径”,“环”可能指本文中的“回路”。如果在题目中看到类似的词汇,且没有“简单路径”/“非简单路径”(即本文中的“途径”)等特殊说明,最好询问一下具体指什么。
+
+## 子图
+
+对一张图 $G = (V, E)$ ,若存在另一张图 $H = (V', E')$ 满足 $V' \subseteq V$ 且 $E' \subseteq E$ ,则称 $H$ 是 $G$ 的 **子图 (Subgraph)** ,记作 $H \subseteq G$ 。
+
+若对 $H \subseteq G$ ,满足 $\forall u, v \in V'$ ,只要 $(u, v) \in E$ ,均有 $(u, v) \in E'$ ,则称 $H$ 是 $G$ 的 **导出子图/诱导子图 (Induced subgraph)** 。
+
+容易发现,一个图的导出子图仅由子图的点集决定,因此点集为 $V'$ ( $V' \subseteq V$ ) 的导出子图称为 $V'$ 导出的子图,记作 $G \left[ V' \right]$ 。
+
+若 $H \subseteq G$ 满足 $V' = V$ ,则称 $H$ 为 $G$ 的 **生成子图/支撑子图 (Spanning subgraph)** 。
+
+如果一张无向图 $G$ 的某个生成子图 $F$ 为 $k$ - 正则图,则称 $F$ 为 $G$ 的一个 ** $k$ - 因子 ( $k$ -Factor)** 。
+
+如果有向图 $G = (u, v)$ 的导出子图 $H = G \left[ V^* \right]$ 满足 $\forall v \in V^*, (v, u) \in E$ ,就有 $u \in V^*$ ,则称 $H$ 为 $G$ 的一个 **闭合子图 (Closed subgraph)** 。
+
+## 连通
+
+### 无向图
+
+对于一张无向图 $G = (V, E)$ ,对于 $u, v \in V$ ,若存在一条途径使得 $v_0 = u, v_k = v$ ,则称 $u$ 和 $v$ 是 **连通的 (Connected)** 。由定义,任意一个顶点和自身连通,任意一条边的两个端点连通。
+
+若无向图 $G = (V, E)$ ,满足其中任意两个顶点均连通,则称 $G$ 是 **连通图 (Connected graph)** , $G$ 的这一性质称作 **连通性 (Connectivity)** 。
+
+若 $H$ 是 $G$ 的一个连通子图,且不存在 $F$ 满足 $H\subsetneq F \subseteq G$ 且 $F$ 为连通图,则 $H$ 是 $G$ 的一个 **连通块/连通分量 (Connected component)** (极大连通子图)。
+
+### 有向图
+
+对于一张有向图 $G = (V, E)$ ,对于 $u, v \in V$ ,若存在一条途径使得 $v_0 = u, v_k = v$ ,则称 $u$  **可达**  $v$ 。由定义,任意一个顶点可达自身,任意一条边的起点可达终点。(无向图中的连通也可以视作双向可达。)
+
+若一张有向图的节点两两互相可达,则称这张图是 **强连通的 (Strongly connected)** 。
+
+若一张有向图的边替换为无向边后可以得到一张连通图,则称原来这张有向图是 **弱连通的 (Weakly connected)** 。
+
+与连通分量类似,也有 **弱连通分量 (Weakly connected component)** (极大弱连通子图)和 **强连通分量 (Strongly Connected component)** (极大强连通子图)。
+
+相关算法请参见 [强连通分量](./scc.md) 。
+
+### 割
+
+相关算法请参见 [割点和桥](./cut.md) 以及 [双连通分量](./bcc.md) 。
+
+在本部分中,有向图的“连通”一般指“强连通”。
+
+对于连通图 $G = (V, E)$ ,若 $V'\subseteq V$ 且 $G\left[V\setminus V'\right]$ (即从 $G$ 中删去 $V'$ 中的点)不是连通图,则 $V'$ 是图 $G$ 的一个 **点割集 (Vertex cut/Separating set)** 。大小为一的点割集又被称作 **割点 (Cut vertex)** 。
+
+对于连通图 $G = (V, E)$ 和整数 $k$ ,若 $|V|\ge k+1$ 且 $G$ 不存在大小为 $k-1$ 的点割集,则称图 $G$ 是 ** $k$ - 点连通的 ( $k$ -vertex-connected)** ,而使得上式成立的最大的 $k$ 被称作图 $G$ 的 **点连通度 (Vertex connectivity)** ,记作 $\kappa(G)$ 。(对于非完全图,点连通度即为最小点割集的大小,而完全图 $K_n$ 的点连通度为 $n-1$ 。)
+
+对于图 $G = (V, E)$ 以及 $u, v\in V$ 满足 $u\ne v$ , $u$ 和 $v$ 不相邻, $u$ 可达 $v$ ,若 $V'\subseteq V$ , $u, v\notin V'$ ,且在 $G\left[V\setminus V'\right]$ 中 $u$ 和 $v$ 不连通,则 $V'$ 被称作 $u$ 到 $v$ 的点割集。 $u$ 到 $v$ 的最小点割集的大小被称作 $u$ 到 $v$ 的 **局部点连通度 (Local connectivity)** ,记作 $\kappa(u, v)$ 。
+
+还可以在边上作类似的定义:
+
+对于连通图 $G = (V, E)$ ,若 $E'\subseteq E$ 且 $G' = (V, E\setminus E')$ (即从 $G$ 中删去 $E'$ 中的边)不是连通图,则 $E'$ 是图 $G$ 的一个 **边割集 (Edge cut)** 。大小为一的边割集又被称作 **桥 (Bridge)** 。
+
+对于连通图 $G = (V, E)$ 和整数 $k$ ,若 $G$ 不存在大小为 $k-1$ 的边割集,则称图 $G$ 是 ** $k$ - 边连通的 ( $k$ -edge-connected)** ,而使得上式成立的最大的 $k$ 被称作图 $G$ 的 **边连通度 (Edge connectivity)** ,记作 $\lambda(G)$ 。(对于任何图,边连通度即为最小边割集的大小。)
+
+对于图 $G = (V, E)$ 以及 $u, v\in V$ 满足 $u\ne v$ , $u$ 可达 $v$ ,若 $E'\subseteq E$ ,且在 $G'=(V, E\setminus E')$ 中 $u$ 和 $v$ 不连通,则 $E'$ 被称作 $u$ 到 $v$ 的边割集。 $u$ 到 $v$ 的最小边割集的大小被称作 $u$ 到 $v$ 的 **局部边连通度 (Local edge-connectivity)** ,记作 $\lambda(u, v)$ 。
+
+ **点双连通 (Biconnected)** 几乎与 $2$ - 点连通完全一致,除了一条边连接两个点构成的图,它是点双连通的,但不是 $2$ - 点连通的。换句话说,没有割点的连通图是点双连通的。
+
+ **边双连通 ( $2$ -edge-connected)** 与 $2$ - 边双连通完全一致。换句话说,没有桥的连通图是边双连通的。
+
+与连通分量类似,也有 **点双连通分量 (Biconnected component)** (极大点双连通子图)和 **边双连通分量 ( $2$ -edge-connected component)** (极大边双连通子图)。
+
+ **Whitney 定理** :对任意的图 $G$ ,有 $\kappa(G)\le \lambda(G)\le \delta(G)$ 。(不等式中的三项分别为点连通度、边连通度、最小度。)
+
+## 稀疏图/稠密图
+
+若一张图的边数远小于其点数的平方,那么它是一张 **稀疏图 (Sparse graph)** 。
+
+若一张图的边数接近其点数的平方,那么它是一张 **稠密图 (Dense graph)** 。
+
+这两个概念并没有严格的定义,一般用于讨论 [时间复杂度](../misc/complexity.md) 为 $O(|V|^2)$ 的算法与 $O(|E|)$ 的算法的效率差异(在稠密图上这两种算法效率相当,而在稀疏图上 $O(|E|)$ 的算法效率明显更高)。
+
+## 补图
+
+对于无向简单图 $G = (V, E)$ ,它的 **补图 (Complement graph)** 指的是这样的一张图:记作 $\bar G$ ,满足 $V \left( \bar G \right) = V \left( G \right)$ ,且对任意节点对 $(u, v)$ , $(u, v) \in E \left( G \right)$ 当且仅当 $(u, v) \notin E \left( G' \right)$ 。
+
+## 反图
+
+对于有向图 $G = (V, E)$ ,它的 **反图 (Transpose Graph)** 指的是点集不变,每条边反向得到的图,即:若 $G$ 的反图为 $G'=(V, E')$ ,则 $E'=\{(v, u)|(u, v)\in E\}$ 。
+
+## 特殊的图
+
+若无向简单图 $G$ 满足任意不同两点间均有边,则称 $G$ 为 **完全图 (Complete graph)** , $n$ 阶完全图记作 $K_n$ 。若有向图 $G$ 满足任意不同两点间都有两条方向不同的边,则称 $G$ 为 **有向完全图 (Complete digraph)** 。
+
+边集为空的图称为 **零图 (Null graph)** , $n$ 阶零图记作 $N_n$ 。易知, $N_n$ 为 $K_n$ 互为补图。
+
+若有向简单图 $G$ 满足任意不同两点间都有恰好一条边(单向),则称 $G$ 为 **竞赛图 (Tournament graph)** 。
+
+若无向简单图 $G = \left( V, E \right)$ 的所有边恰好构成一个圈,则称 $G$ 为 **环图/圈图 (Cycle graph)** , $n$ ( $n \geq 3$ ) 阶圈图记作 $C_n$ 。易知,一张图为圈图的充分必要条件是,它是 $2$ - 正则连通图。
+
+若无向简单图 $G = \left( V, E \right)$ 满足,存在一个点 $v$ 为支配点,其余点之间没有边相连,则称 $G$ 为 **星图/菊花图 (Star graph)** , $n + 1$ ( $n \geq 1$ ) 阶星图记作 $S_n$ 。
+
+若无向简单图 $G = \left( V, E \right)$ 满足,存在一个点 $v$ 为支配点,其它点之间构成一个圈,则称 $G$ 为 **轮图 (Wheel Graph)** , $n + 1$ ( $n \geq 3$ ) 阶轮图记作 $W_n$ 。
+
+若无向简单图 $G = \left( V, E \right)$ 的所有边恰好构成一条简单路径,则称 $G$ 为 **链 (Chain/Path Graph)** , $n$ 阶的链记作 $P_n$ 。易知,一条链由一个圈图删去一条边而得。
+
+如果一张无向连通图不含环,则称它是一棵 **树 (Tree)** 。相关内容详见 [树基础](./tree-basic.md) 。
+
+如果一张无向连通图包含恰好一个环,则称它是一棵 **基环树** 。
+
+如果一张有向弱连通图每个点的入度都为 $1$ ,则称它是一棵 **基环外向树** 。
+
+如果一张有向弱连通图每个点的出度都为 $1$ ,则称它是一棵 **基环内向树** 。
+
+多棵树可以组成一个 **森林 (Forest)** ,多棵基环树可以组成 **基环森林** ,多棵基环外向树可以组成 **基环外向树森林** ,多棵基环内向树可以组成 **基环内向森林 (Functional graph)** 。
+
+如果一张无向连通图的每条边最多在一个环内,则称它是一棵 **仙人掌 (Cactus)** 。多棵仙人掌可以组成 **沙漠** 。
+
+如果一张图的点集可以被分为两部分,每一部分的内部都没有连边,那么这张图是一张 **二分图 (Bipartite graph)** 。如果二分图中任何两个不在同一部分的点之间都有连边,那么这张图是一张 **完全二分图 (Complete bipartite graph/Biclique)** ,一张两部分分别有 $n$ 个点和 $m$ 个点的完全二分图记作 $K_{n, m}$ 。相关内容详见 [二分图](./bi-graph.md) 。
+
+如果一张图可以画在一个平面上,且没有两条边在非端点处相交,那么这张图是一张 **平面图 (Planar graph)** 。一张图的任何子图都不是 $K_5$ 或 $K_{3, 3}$ 是其为一张平面图的充要条件。对于简单连通平面图 $G=(V, E)$ 且 $V\ge 3$ , $|E|\le 3|V|-6$ 。
+
+## 同构
+
+对两个阶数相等的简单图 $G$ 和 $H$ ,如果存在一个双射 $f : V(G) \to V(H)$ ,满足对于两个顶点 $u$ 和 $v$ ( $u \neq v$ ), $u$ 和 $v$ 在 $G$ 中相邻当且仅当 $f(u)$ 和 $f(V)$ 在 $H$ 中相邻,则我们称 $f$ 为 $G$ 到 $H$ 的一个 **同构 (Isomorphism)** ,且图 $G$ 与图 $H$ 是 **同构的 (Isomorphic)** ,记作 $G \cong H$ 。
+
+## 无向简单图的二元运算
+
+对于无向简单图,我们可以定义如下二元运算:
+
+ **交 (Intersection)** :两张图 $G = \left( V_1, E_1 \right), H = \left( V_2, E_2 \right)$ 的交定义成图 $G \cap H = \left( V_1 \cap V_2, E_1 \cap E_2 \right)$ 。
+
+容易证明两个无向简单图的交还是无向简单图。
+
+ **并 (Union)** :两张图 $G = \left( V_1, E_1 \right), H = \left( V_2, E_2 \right)$ 的并定义成图 $G \cup H = \left( V_1 \cup V_2, E_1 \cup E_2 \right)$ 。
+
+ **和 (Sum)/直和 (Direct sum)** :对于 $G = \left( V_1, E_1 \right), H = \left( V_2, E_2 \right)$ ,任意构造 $H' \cong H$ 使得 $V \left( H' \right) \cap V_1 = \varnothing$ ( $H'$ 可以等于 $H$ )。此时与 $G \cup H'$ 同构的任何图称为 $G$ 和 $H$ 的和/直和/不交并,记作 $G + H$ 或 $G \oplus H$ 。
+
+若 $G$ 与 $H$ 的点集本身不相交,则 $G \cup H = G + H$ 。
+
+比如,森林可以定义成若干棵树的和。
+
+???+note "并与和的区别"
+    可以理解为,“并”会让两张图中“名字相同”的点、边合并,而“和”则不会。
+
+## 特殊的点集/边集
+
+### 支配集
+
+对于无向图 $G=(V, E)$ ,若 $V'\subseteq V$ 且 $\forall v\in(V\setminus V')$ 存在边 $(u, v)\in E$ 满足 $u\in V'$ ,则 $V'$ 是图 $G$ 的一个 **支配集 (Dominating set)** 。
+
+无向图 $G$ 最小的支配集的大小记作 $\gamma(G)$ 。求一张图的最小支配集是 [NP 困难](../misc/cc-basic.md#np-hard) 的。
+
+对于有向图 $G=(V, E)$ ,若 $V'\subseteq V$ 且 $\forall v\in(V\setminus V')$ 存在边 $(u, v)\in E$ 满足 $u\in V'$ ,则 $V'$ 是图 $G$ 的一个 **出 - 支配集 (Out-dominating set)** 。类似地,可以定义有向图的 **入 - 支配集 (In-dominating set)** 。
+
+有向图 $G$ 最小的出 - 支配集大小记作 $\gamma^+(G)$ ,最小的入 - 支配集大小记作 $\gamma^-(G)$ 。
+
+### 边支配集
+
+对于图 $G=(V, E)$ ,若 $E'\subseteq E$ 且 $\forall e\in(E\setminus E')$ 存在 $E'$ 中的边与其有公共点,则称 $E'$ 是图 $G$ 的一个 **边支配集 (Edge dominating set)** 。
+
+求一张图的最小边支配集是 [NP 困难](../misc/cc-basic.md#np-hard) 的。
+
+### 独立集
+
+对于图 $G=(V, E)$ ,若 $V'\subseteq V$ 且 $V'$ 中任意两点都不相邻,则 $V'$ 是图 $G$ 的一个 **独立集 (Independent set)** 。
+
+图 $G$ 最大的独立集的大小记作 $\alpha(G)$ 。求一张图的最大独立集是 [NP 困难](../misc/cc-basic.md#np-hard) 的。
+
+### 匹配
+
+对于图 $G=(V, E)$ ,若 $E'\in E$ 且 $E'$ 中任意两条不同的边都没有公共的端点,且 $E'$ 中任意一条边都不是自环,则 $E'$ 是图 $G$ 的一个 **匹配 (Matching)** ,也可以叫作 **边独立集 (Independent edge set)** 。如果一个点是匹配中某条边的一个端点,则称这个点是 **被匹配的 (matched)/饱和的 (saturated)** ,否则称这个点是 **不被匹配的 (unmatched)** 。
+
+边数最多的匹配被称作一张图的 **最大匹配 (Maximum-cardinality matching)** 。图 $G$ 的最大匹配的大小记作 $\nu(G)$ 。
+
+如果边带权,那么权重之和最大的匹配被称作一张图的 **最大权匹配 (Maximum-weight matching)** 。
+
+如果一个匹配在加入任何一条边后都不再是一个匹配,那么这个匹配是一个 **极大匹配 (Maximal matching)** 。最大的极大匹配就是最大匹配,任何最大匹配都是极大匹配。极大匹配一定是边支配集,但边支配集不一定是匹配。最小极大匹配和最小边支配集大小相等,但最小边支配集不一定是匹配。求最小极大匹配是 NP 困难的。
+
+如果在一个匹配中所有点都是被匹配的,那么这个匹配是一个 **完美匹配 (Perfect matching)** 。如果在一个匹配中只有一个点不被匹配,那么这个匹配是一个 **准完美匹配 (Near-perfect matching)** 。
+
+求一张普通图或二分图的匹配或完美匹配个数都是 [#P 完全](../misc/cc-basic.md#p_1) 的。
+
+对于一个匹配 $M$ ,若一条路径以非匹配点为起点,每相邻两条边的其中一条在匹配中而另一条不在匹配中,则这条路径被称作一条 **交替路径 (Alternating path)** ;一条在非匹配点终止的交替路径,被称作一条 **增广路径 (Augmenting path)** 。
+
+ **托特定理** : $n$ 阶无向图 $G$ 有完美匹配当且仅当对于任意的 $V' \subset V(G)$ , $p_{奇}(G-V')\leq |V'|$ ,其中 $p_{奇}$ 表示奇数阶连通分支数。
+
+ **托特定理(推论)** :任何无桥 3 - 正则图都有完美匹配。
+
+### 点覆盖
+
+对于图 $G=(V, E)$ ,若 $V'\subseteq V$ 且 $\forall e\in E$ 满足 $e$ 的至少一个端点在 $V'$ 中,则称 $V'$ 是图 $G$ 的一个 **点覆盖 (Vertex cover)** 。
+
+点覆盖集必为支配集,但极小点覆盖集不一定是极小支配集。
+
+一个点集是点覆盖的充要条件是其补集是独立集,因此最小点覆盖的补集是最大独立集。求一张图的最小点覆盖是 [NP 困难](../misc/cc-basic.md#np-hard) 的。
+
+一张图的任何一个匹配的大小都不超过其任何一个点覆盖的大小。完全二分图 $K_{n, m}$ 的最大匹配和最小点覆盖大小都为 $\min(n, m)$ 。
+
+### 边覆盖
+
+对于图 $G=(V, E)$ ,若 $E'\subseteq E$ 且 $\forall v\in V$ 满足 $v$ 与 $E'$ 中的至少一条边相邻,则称 $E'$ 是图 $G$ 的一个 **边覆盖 (Edge cover)** 。
+
+最小边覆盖的大小记作 $\rho(G)$ ,可以由最大匹配贪心扩展求得:对于所有非匹配点,将其一条邻边加入最大匹配中,即得到了一个最小边覆盖。
+
+最大匹配也可以由最小边覆盖求得:对于最小边覆盖中每对有公共点的边删去其中一条。
+
+一张图的最小边覆盖的大小加上最大匹配的大小等于图的点数,即 $\rho(G)+\nu(G)=|V(G)|$ 。
+
+一张图的最大匹配的大小不超过最小边覆盖的大小,即 $\nu(G)\le\rho(G)$ 。特别地,完美匹配一定是一个最小边覆盖,这也是上式取到等号的唯一情况。
+
+一张图的任何一个独立集的大小都不超过其任何一个边覆盖的大小。完全二分图 $K_{n, m}$ 的最大独立集和最小边覆盖大小都为 $\max(n, m)$ 。
+
+### 团
+
+对于图 $G=(V, E)$ ,若 $V'\subseteq V$ 且 $V'$ 中任意两个不同的顶点都相邻,则 $V'$ 是图 $G$ 的一个 **团 (Clique)** 。团的导出子图是完全图。
+
+如果一个团在加入任何一个顶点后都不再是一个团,则这个团是一个 **极大团 (Maximal clique)** 。
+
+一张图的最大团的大小记作 $\omega(G)$ ,最大团的大小等于其补图最大独立集的大小,即 $\omega(G)=\alpha(\bar{G})$ 。求一张图的最大团是 [NP 困难](../misc/cc-basic.md#np-hard) 的。
+
+## 参考资料
+
+ [OI 中转站 - 图论概念梳理](https://yhx-12243.github.io/OI-transit/memos/14.html) 
+
+ [Wikipedia](https://en.wikipedia.org/wiki/Glossary_of_graph_theory_terms) (以及相关概念的对应词条)
+
+离散数学(修订版),田文成 周禄新 编著,天津文学出版社,P184-187
similarity index 75%
rename from docs/graph/bridge.md
rename to docs/graph/cut.md
index a9c701c..a71127c 100644 (file)
@@ -1,6 +1,8 @@
+author: Ir1d, sshwy, GavinZhengOI, Planet6174, ouuan, TrisolarisHD, ylxmf2005
+
 相关阅读: [双连通分量](./bcc.md) ,
 
-割点和桥更严谨的定义参见 [图论基础](./basic.md) 。
+割点和桥更严谨的定义参见 [图论相关概念](./concept.md) 。
 
 ## 割点
 
 
 首先,我们上一个图:
 
-![](images/bridge1.png)
+![](./images/bridge1.png)
 
 很容易的看出割点是 2,而且这个图仅有这一个割点。
 
 首先,我们按照 DFS 序给他打上时间戳(访问的顺序)。
 
-![](images/bridge2.png)
+![](./images/bridge2.png)
 
 这些信息被我们保存在一个叫做 `num` 的数组中。
 
@@ -30,7 +32,7 @@
 
 另外,如果搜到了自己(在环中),如果他有两个及以上的儿子,那么他一定是割点了,如果只有一个儿子,那么把它删掉,不会有任何的影响。比如下面这个图,此处形成了一个环,从树上来讲它有 2 个儿子:
 
-![](images/bridge3.png)
+![](./images/bridge3.png)
 
 我们在访问 1 的儿子时候,假设先 DFS 到了 2,然后标记用过,然后递归往下,来到了 4,4 又来到了 3,当递归回溯的时候,会发现 3 已经被访问过了,所以不是割点。
 
@@ -107,16 +109,21 @@ low[u] = min(low[u], num[v]);
       cout << res << endl;
       for (int i = 1; i <= n; i++)
         if (flag[i]) cout << i << " ";  // 输出结果
-      for (int i = 1; i <= n; i++) cout << low[i] << endl;
       return 0;
     }
     ```
 
 ## 割边
 
-和割点差不多,还叫做割桥。
+和割点差不多,叫做桥。
+
+> 对于一个无向图,如果删掉一条边后图中的连通分量数增加了,则称这条边为桥或者割边。严谨来说,就是:假设有连通图 $G=\{V,E\}$ , $e$ 是其中一条边(即 $e \in E$ ),如果 $G-e$ 是不连通的,则边 $e$ 是图 $G$ 的一条割边(桥)。
+
+比如说,下图中,
+
+![割边示例图](./images/bridge4.png)
 
-> 对于一个无向图,如果删掉一条边后图中的连通分量数增加了,则称这条边为桥或者割边。
+红色箭头指向的就是割边。
 
 ### 实现
 
@@ -124,4 +131,42 @@ low[u] = min(low[u], num[v]);
 
 割边是和是不是根节点没关系的,原来我们求割点的时候是指点 $v$ 是不可能不经过父节点 $u$ 为回到祖先节点(包括父节点),所以顶点 $u$ 是割点。如果 $low_v=num_u$ 表示还可以回到父节点,如果顶点 $v$ 不能回到祖先也没有另外一条回到父亲的路,那么 $u-v$ 这条边就是割边。
 
+### 代码实现
+
+下面代码实现了求割边,其中,当 `isbridge[x]` 为真时, `(father[x],x)` 为一条割边。
+
+```cpp
+int low[MAXN], dfn[MAXN], iscut[MAXN], dfs_clock;
+bool isbridge[MAXN];
+vector<int> G[MAXN];
+int cnt_bridge;
+int father[MAXN];
+
+void tarjan(int u, int fa) {
+  father[u] = fa;
+  low[u] = dfn[u] = ++dfs_clock;
+  for (int i = 0; i < G[u].size(); i++) {
+    int v = G[u][i];
+    if (!dfn[v]) {
+      tarjan(v, u);
+      low[u] = min(low[u], low[v]);
+      if (low[v] > dfn[u]) {
+        isbridge[v] = true;
+        ++cnt_bridge;
+      }
+    } else if (dfn[v] < dfn[u] && v != fa) {
+      low[u] = min(low[u], dfn[v]);
+    }
+  }
+}
+```
+
+## 练习
+
+-    [P3388【模板】割点(割顶)](https://www.luogu.org/problem/P3388) 
+-    [POJ2117 Electricity](https://vjudge.net/problem/POJ-2117) 
+-    [HDU4738 Caocao's Bridges](https://vjudge.net/problem/HDU-4738) 
+-    [HDU2460 Network](https://vjudge.net/problem/HDU-2460) 
+-    [POJ1523 SPF](https://vjudge.net/problem/POJ-1523) 
+
 Tarjan 算法还有许多用途,常用的例如求强连通分量,缩点,还有求 2-SAT 的用途等。
index 0fc2c78..6b629ff 100644 (file)
@@ -14,7 +14,7 @@ DFS 最显著的特征在于其 **递归调用自身** 。同时与 BFS 类似
       在 v 上打访问标记
       for u in v 的相邻节点
         if u 没有打过访问标记 then
-          DFS(i)
+          DFS(u)
         end
       end
     end
index 5c03d1d..c996cf4 100644 (file)
 ## 定义
 
-通过图中所有边一次且仅一次行遍所有顶点的通路称为欧拉通路。
+通过图中所有边恰好一次且行遍所有顶点的通路称为欧拉通路。
 
-通过图中所有边一次且仅一次行遍所有顶点的回路称为欧拉回路。
+通过图中所有边恰好一次且行遍所有顶点的回路称为欧拉回路。
 
-具有欧拉回路的图称为欧拉图。
+具有欧拉回路的无向图称为欧拉图。
 
-具有欧拉通路图称为半欧拉图。
+具有欧拉通路但不具有欧拉回路的无向图称为半欧拉图。
 
-有向图的时候可以类似地定义。
+有向图也可以有类似的定义。
+
+非形式化地讲,欧拉图就是从任意一个点开始都可以一笔画完整个图,半欧拉图必须从某个点开始才能一笔画完整个图。
 
 ## 性质
 
 欧拉图中所有顶点的度数都是偶数。
 
-若 $G$ 是欧拉图,则它若干个边不重的圈的并。
+若 $G$ 是欧拉图,则它为若干个边不重的圈的并。
+
+若 $G$ 是半欧拉图,则它为若干个边不重的圈和一条简单路径的并。
 
 ## 判别法
 
- $G$ 是欧拉图当且仅当 $G$ 是连通的且没有奇度点。
+ $G$ 是欧拉图当且仅当 $G$ 是连通的且没有奇度点。
 
- $G$ 是半欧拉图当且仅当 $G$ 中恰有两个奇度点。
+ $G$ 是半欧拉图当且仅当 $G$ 中恰有两个奇度点。
 
-## 求欧拉回路
+## 求欧拉回路或欧拉路
 
-### Fleury 算法
+例题: [Luogu P2731 骑马修栅栏](https://www.luogu.com.cn/problem/P2731) 
 
-也称避桥法。
+???+note "题面"
+    给定一张有 500 个顶点的无向图,求这张图的一条欧拉路或欧拉回路。如果有多组解,输出最小的那一组。
 
-ç®\97æ³\95æµ\81ç¨\8b为æ¯\8f次é\80\89æ\8b©ä¸\8bä¸\80æ\9d¡è¾¹ç\9a\84æ\97¶å\80\99ä¼\98å\85\88é\80\89æ\8b©ä¸\8dæ\98¯æ¡¥ç\9a\84è¾¹ã\80\82
+    å\9c¨æ\9c¬é¢\98中ï¼\8c欧æ\8b\89è·¯æ\88\96欧æ\8b\89å\9b\9eè·¯ä¸\8dé\9c\80è¦\81ç»\8fè¿\87æ\89\80æ\9c\89顶ç\82¹ã\80\82
 
-### 逐步插入回路法
+    边的数量 m 满足 $1\leq m \leq 1024$ 。
 
-算法流程为从一条边开始,每次任取一条目前回路中某顶点关联的边,将其替换为一条简单回路。
+### Fleury 算法
+
+也称避桥法,一个偏暴力的算法。算法流程为每次选择下一条边的时候优先选择不是桥的边。
+
+一个广泛使用但是错误的实现方式是先 Tarjan 预处理桥边,然后再 DFS 避免走桥。但是由于走图过程中边会被删去,一些非桥边会变为桥边导致错误。最简单的实现方法是每次删除一条边之后暴力跑一遍 Tarjan 找桥,时间复杂度是 $\Theta(m(n+m))=\Theta(m^2)$ 。复杂的实现方法要用到动态图等,实用价值不高。
+
+在解决本题的时候只需要再贪心就好,不过由于复杂度不对,还是看更优的算法吧。
+
+### 逐步插入回路法(Hierholzer 算法)
+
+算法流程为从一条回路开始,每次任取一条目前回路中的点,将其替换为一条简单回路,以此寻找到一条欧拉回路。如果从路开始的话,就可以寻找到一条欧拉路。
+
+Hierholzer 算法的暴力实现如下:
+
+$$
+\begin{array}{ll}
+1 &  \textbf{Input. } \text{The edges of the graph } e , \text{ where each element in } e \text{ is } (u, v) \\
+2 &  \textbf{Output. } \text{The vertex of the Euler Road of the input graph}.\\
+3 &  \textbf{Method. } \\ 
+4 &  \textbf{Function } \text{Hierholzer } (v) \\
+5 &  \qquad circle \gets \text{Find a Circle in } e \text{ Begin with } v \\
+6 &  \qquad \textbf{if } circle=\varnothing \\
+7 &  \qquad\qquad \textbf{return } v \\
+8 &  \qquad e \gets e-circle \\
+9 &  \qquad \textbf{for} \text{ each } v \in circle \\
+10&  \qquad\qquad v \gets \text{Hierholzer}(v) \\
+11&  \qquad \textbf{return } circle \\
+12&  \textbf{Endfunction}\\
+13&  \textbf{return } \text{Hierholzer}(\text{any vertex})
+\end{array}
+$$
+
+这个算法的时间复杂度约为 $O(nm+m^2)$ 。实际上还有复杂度更低的实现方法,就是将找回路的 Dfs 和 Hierholzer 的递归合并,边找回路边 Hierholzer,保存答案可以使用 `stack<int>` ,因为如果找的不是回路的话必须将那一部分放在最后。
+
+如果需要输出字典序最小的欧拉路或欧拉回路的话,因为需要将边排序,时间复杂度是 $\Theta(n+m\log m)$ (计数排序或者基数排序可以优化至 $\Theta(n+m)$ )。如果不需要排序,时间复杂度是 $\Theta(n+m)$ 。
+
+对于这道例题的一个代码实现如下。注意,不能使用邻接矩阵存图,否则时间复杂度会退化为 $\Theta(nm)$ 。由于需要将边排序,建议使用前向星或者 vector 存图。示例代码使用 vector。
+
+???+note "代码实现"
+    ```cpp
+    #include <algorithm>
+    #include <cstdio>
+    #include <stack>
+    #include <vector>
+    using namespace std;
+    
+    struct edge {
+      int to;
+      bool exists;
+      int revref;
+    
+      bool operator<(const edge& b) const { return to < b.to; }
+    };
+    
+    vector<edge> beg[505];
+    int cnt[505];
+    
+    const int dn = 500;
+    stack<int> ans;
+    
+    void Hierholzer(int x)  // 关键函数
+    {
+      for (int& i = cnt[x]; i < (int)beg[x].size();) {
+        if (beg[x][i].exists) {
+          edge e = beg[x][i];
+          beg[x][i].exists = 0;
+          beg[e.to][e.revref].exists = 0;
+          ++i;
+          Hierholzer(e.to);
+        } else {
+          ++i;
+        }
+      }
+      ans.push(x);
+    }
+    
+    int deg[505];
+    int reftop[505];
+    
+    int main() {
+      for (int i = 1; i <= dn; ++i) {
+        beg[i].reserve(1050);  // vector 用 reserve 避免动态分配空间,加快速度
+      }
+    
+      int m;
+      scanf("%d", &m);
+      for (int i = 1; i <= m; ++i) {
+        int a, b;
+        scanf("%d%d", &a, &b);
+        beg[a].push_back((edge){b, 1, 0});
+        beg[b].push_back((edge){a, 1, 0});
+        ++deg[a];
+        ++deg[b];
+      }
+    
+      for (int i = 1; i <= dn; ++i) {
+        if (!beg[i].empty()) {
+          sort(beg[i].begin(), beg[i].end());  // 为了要按字典序贪心,必须排序
+        }
+      }
+    
+      for (int i = 1; i <= dn; ++i) {
+        for (int j = 0; j < (int)beg[i].size(); ++j) {
+          beg[i][j].revref = reftop[beg[i][j].to]++;
+        }
+      }
+    
+      int bv = 0;
+      for (int i = 1; i <= dn; ++i) {
+        if (!deg[bv] && deg[i]) {
+          bv = i;
+        } else if (!(deg[bv] & 1) && (deg[i] & 1)) {
+          bv = i;
+        }
+      }
+    
+      Hierholzer(bv);
+    
+      while (!ans.empty()) {
+        printf("%d\n", ans.top());
+        ans.pop();
+      }
+    }
+    ```
 
 ### 应用
 
 
 设有 $m$ 个字母,希望构造一个有 $m^n$ 个扇形的圆盘,每个圆盘上放一个字母,使得圆盘上每连续 $n$ 位对应长为 $n$ 的符号串。转动一周( $m^n$ 次)后得到由 $m$ 个字母产生的长度为 $n$ 的 $m^n$ 个各不相同的符号串。
 
-构造如下邮箱欧拉图:
+![](../images/euler1.png)
+
+构造如下有向欧拉图:
 
 设 $S = \{a_1, a_2, \cdots, a_m\}$ ,构造 $D=<V, E>$ ,如下:
 
 
 边 $a_{j_1}a_{j_2}\cdots a_{j_{n-1}}$ 引入顶点 $a_{j_2}a_{j_3}\cdots a_{j_{n}}$ 。
 
+![](../images/euler2.png)
+
 这样的 $D$ 是连通的,且每个顶点入度等于出度(均等于 $m$ ),所以 $D$ 是有向欧拉图。
 
 任求 $D$ 中一条欧拉回路 $C$ ,取 $C$ 中各边的最后一个字母,按各边在 $C$ 中的顺序排成圆形放在圆盘上即可。
 
 ## 练习题
 
- [「洛谷 1341」无序字母对](https://www.luogu.org/problemnew/show/P1341) 
+ [「洛谷 1341」无序字母对](https://www.luogu.org/problem/P1341) 
 
- [「洛谷 2731」骑马修栅栏](https://www.luogu.org/problemnew/show/P2731) 
+ [「洛谷 2731」骑马修栅栏](https://www.luogu.org/problem/P2731) 
index 3f36829..60041d1 100644 (file)
@@ -8,66 +8,66 @@
 
 ## 无源汇上下界可行流
 
-给定无源汇流量网络 G。询问是否存在一种标定每条边流量的方式,使得每条边流量满足上下界同时每一个点流量平衡。
+给定无源汇流量网络 $G$ 。询问是否存在一种标定每条边流量的方式,使得每条边流量满足上下界同时每一个点流量平衡。
 
-不妨假设每条边已经流了 $b(u,v)$ 的流量,设其为初始流。同时我们在新图中加入 u 连向 v 的流量为 $c(u,v) - b(u,v)$ 的边。考虑在新图上进行调整。
+不妨假设每条边已经流了 $b(u,v)$ 的流量,设其为初始流。同时我们在新图中加入 $u$ 连向 $v$ 的流量为 $c(u,v) - b(u,v)$ 的边。考虑在新图上进行调整。
 
-由于最大流需要满足初始流量平衡条件(最大流可以看成是下界为 0 的上下界最大流),但是构造出来的初始流很有可能不满足初始流量平衡。假设一个点初始流出流量 - 初始流入流量为 M
+由于最大流需要满足初始流量平衡条件(最大流可以看成是下界为 $0$ 的上下界最大流),但是构造出来的初始流很有可能不满足初始流量平衡。假设一个点初始流入流量减初始流出流量为 $M$ 
 
-若 M=0,此时流量平衡,不需要额外边。
+若 $M=0$ ,此时流量平衡,不需要附加边。
 
-若 M>0,此时出流量过大,需要新建附加源点 SS,SS 向其连流量为 M 的附加边。
+若 $M>0$ ,此时出流量过大,需要新建附加源点 $S'$ , $S'$ 向其连流量为 $M$ 的附加边。
 
-若 M&lt;0,此时入流量过大,需要新建附加汇点 TT,其向 TT 连流量为 -M 的附加边。
+若 $M<0$ ,此时入流量过大,需要新建附加汇点 $T'$ ,其向 $T'$ 连流量为 $-M$ 的附加边。
 
-如果附加边满流,说明这一个点的流量平衡条件可以满足,否则这个点的流量平衡条件不满足。(因为附加流满足流量平衡
+如果附加边满流,说明这一个点的流量平衡条件可以满足,否则这个点的流量平衡条件不满足。(因为原图加上附加流之后才会满足原图中的流量平衡。
 
-在建图完毕之后跑 S 到 T 的最大流,若 S 连出去的边全部满流,则存在可行流,否则不存在。
+在建图完毕之后跑 $S'$ 到 $T'$ 的最大流,若 $S'$ 连出去的边全部满流,则存在可行流,否则不存在。
 
 ## 有源汇上下界可行流
 
-给定有源汇流量网络 G。询问是否存在一种标定每条边流量的方式,使得每条边流量满足上下界同时除了源点和汇点每一个点流量平衡。
+给定有源汇流量网络 $G$ 。询问是否存在一种标定每条边流量的方式,使得每条边流量满足上下界同时除了源点和汇点每一个点流量平衡。
 
-假设源点为 S,汇点为 T
+假设源点为 $S$ ,汇点为 $T$ 
 
-则我们可以加入一条 T 到 S 的上界 $\inf$ 下界为 0 的边转化为无源汇上下界可行流问题。
+则我们可以加入一条 $T$ 到 $S$ 的上界为 $\infty$ ,下界为 $0$ 的边转化为无源汇上下界可行流问题。
 
-若有解,则 S 到 T 的可行流流量等于 T 到 S 的附加边的流量。
+若有解,则 $S$ 到 $T$ 的可行流流量等于 $T$ 到 $S$ 的附加边的流量。
 
 ## 有源汇上下界最大流
 
-给定有源汇流量网络 G。询问是否存在一种标定每条边流量的方式,使得每条边流量满足上下界同时除了源点和汇点每一个点流量平衡。如果存在,询问满足标定的最大流量。
+给定有源汇流量网络 $G$ 。询问是否存在一种标定每条边流量的方式,使得每条边流量满足上下界同时除了源点和汇点每一个点流量平衡。如果存在,询问满足标定的最大流量。
 
 我们找到网络上的任意一个可行流。如果找不到解就可以直接结束。
 
\90¦å\88\99æ\88\91们è\80\83è\99\91å\88 å\8e»æ\89\80æ\9c\89é¢\9då¤\96边之后的残量网络并且在网络上进行调整。
\90¦å\88\99æ\88\91们è\80\83è\99\91å\88 å\8e»æ\89\80æ\9c\89é\99\84å\8a 边之后的残量网络并且在网络上进行调整。
 
-我们在残量网络上再跑一次 S 到 T 的最大流,将可行流流量和最大流流量相加即为答案。
+我们在残量网络上再跑一次 $S$ 到 $T$ 的最大流,将可行流流量和最大流流量相加即为答案。
 
 !!! warning "一个非常易错的问题"
-    S 到 T 的最大流直接在跑完有源汇上下界可行的残量网络上跑。
+     $S$ 到 $T$ 的最大流直接在跑完有源汇上下界可行的残量网络上跑。
 
     千万不可以在原来的流量网络上跑。
 
 ## 有源汇上下界最小流
 
-给定有源汇流量网络 G。询问是否存在一种标定每条边流量的方式,使得每条边流量满足上下界同时除了源点和汇点每一个点流量平衡。如果存在,询问满足标定的最小流量。
+给定有源汇流量网络 $G$ 。询问是否存在一种标定每条边流量的方式,使得每条边流量满足上下界同时除了源点和汇点每一个点流量平衡。如果存在,询问满足标定的最小流量。
 
 类似的,我们考虑将残量网络中不需要的流退掉。
 
 我们找到网络上的任意一个可行流。如果找不到解就可以直接结束。
 
\90¦å\88\99æ\88\91们è\80\83è\99\91å\88 å\8e»æ\89\80æ\9c\89é¢\9då¤\96边之后的残量网络。
\90¦å\88\99æ\88\91们è\80\83è\99\91å\88 å\8e»æ\89\80æ\9c\89é\99\84å\8a 边之后的残量网络。
 
-我们在残量网络上再跑一次 T 到 S 的最大流,将可行流流量减去最大流流量即为答案。
+我们在残量网络上再跑一次 $T$ 到 $S$ 的最大流,将可行流流量减去最大流流量即为答案。
 
 ??? note "[AHOI 2014 支线剧情](https://loj.ac/problem/2226)"
 
-    对于每条 x 到 y 花费 v 的剧情边设上界为 $\inf$ , 下界为 1
+    对于每条 $x$ 到 $y$ 花费 $v$ 的剧情边设上界为 $\infty$ , 下界为 $1$
 
-    对于每个点,向 T 连边权 c, 上界 $\inf$ , 下界为 1 。
+    对于每个点,向 $T$ 连边权 $c$, 上界 $\infty$ , 下界为 $1$ 。
 
-    S 点为 1 号节点。
+    $S$ 点为 $1$ 号节点。
 
     跑一次 上下界带源汇最小费用可行流 即可。
 
index b334157..71aac00 100644 (file)
Binary files a/docs/graph/flow/images/flow1.png and b/docs/graph/flow/images/flow1.png differ
index 41fca30..aa7d1ca 100644 (file)
Binary files a/docs/graph/flow/images/flow2.png and b/docs/graph/flow/images/flow2.png differ
diff --git a/docs/graph/flow/images/flow3.png b/docs/graph/flow/images/flow3.png
deleted file mode 100644 (file)
index 286f150..0000000
Binary files a/docs/graph/flow/images/flow3.png and /dev/null differ
diff --git a/docs/graph/flow/images/flow4.png b/docs/graph/flow/images/flow4.png
deleted file mode 100644 (file)
index 4854f37..0000000
Binary files a/docs/graph/flow/images/flow4.png and /dev/null differ
diff --git a/docs/graph/flow/images/flow5.png b/docs/graph/flow/images/flow5.png
deleted file mode 100644 (file)
index 5eee366..0000000
Binary files a/docs/graph/flow/images/flow5.png and /dev/null differ
diff --git a/docs/graph/flow/images/flow6.png b/docs/graph/flow/images/flow6.png
deleted file mode 100644 (file)
index 002d3ff..0000000
Binary files a/docs/graph/flow/images/flow6.png and /dev/null differ
diff --git a/docs/graph/flow/images/flow7.png b/docs/graph/flow/images/flow7.png
deleted file mode 100644 (file)
index 4addb9e..0000000
Binary files a/docs/graph/flow/images/flow7.png and /dev/null differ
diff --git a/docs/graph/flow/images/flow8.png b/docs/graph/flow/images/flow8.png
deleted file mode 100644 (file)
index 6dfb49d..0000000
Binary files a/docs/graph/flow/images/flow8.png and /dev/null differ
index a25dfb0..8851199 100644 (file)
@@ -6,7 +6,7 @@ author: Ir1d, TrisolarisHD, ouuan, hsfzLZH1, Xeonacid, greyqz, Chrogeek, ftxj, s
 
 具体来说,将整棵树剖分为若干条链,使它组合成线性结构,然后用其他的数据结构维护信息。
 
- **树链剖分** (树剖/链剖)有多种形式,如 **重链剖分** , **长链剖分** 和用于 Link/cut Tree 的剖分(有时被称作“实链剖分”),大多数情况下(没有特别说明时),“树链剖分”都指“重链剖分”,本文所讲的也是“重链剖分”
+ **树链剖分** (树剖/链剖)有多种形式,如 **重链剖分** , **长链剖分** 和用于 Link/cut Tree 的剖分(有时被称作“实链剖分”),大多数情况下(没有特别说明时),“树链剖分”都指“重链剖分”。
 
 重链剖分可以将树上的任意一条路径划分成不超过 $O(\log n)$ 条连续的链,每条链上的点深度互不相同(即是自底向上的一条链,链上所有点的 LCA 为链的一个端点)。
 
@@ -23,19 +23,19 @@ author: Ir1d, TrisolarisHD, ouuan, hsfzLZH1, Xeonacid, greyqz, Chrogeek, ftxj, s
 
 我们给出一些定义:
 
-定义 **重子节点** 表示其子节点中子树最大的子结点。如果有相同的,任意取。如果没有子节点,就没有
+定义 **重子节点** 表示其子节点中子树最大的子结点。如果有多个子树最大的子结点,取其一。如果没有子节点,就无重子节点
 
-定义 **轻子节点** 表示剩余的子结点。
+定义 **轻子节点** 表示剩余的所有子结点。
 
-从这个结点到重子节点的边 **重边** 。
+从这个结点到重子节点的边 **重边** 。
 
-到其他轻子节点的边 **轻边** 。
+到其他轻子节点的边 **轻边** 。
 
 若干条首尾衔接的重边构成 **重链** 。
 
 把落单的结点也当作重链,那么整棵树就被剖分成若干条重链。
 
-看一张图就明白了
+如图:
 
 ![HLD](./images/hld.png)
 
@@ -82,7 +82,7 @@ $$
 \end{array}
 $$
 
-给一个具体的代码实现吧
+以下为代码实现
 
 我们先给出一些定义:
 
@@ -96,8 +96,6 @@ $$
 
 我们进行两遍 DFS 预处理出这些值,其中第一次 DFS 求出 $fa(x)$ , $dep(x)$ , $siz(x)$ , $son(x)$ ,第二次 DFS 求出 $top(x)$ , $dfn(x)$ , $rnk(x)$ 。
 
-给出一种代码实现:
-
 ```cpp
 void dfs1(int o) {
   son[o] = -1;
@@ -125,15 +123,21 @@ void dfs2(int o, int t) {
 
 ## 重链剖分的性质
 
-树上每个节点都属于且仅属于一条重链
+ **树上每个节点都属于且仅属于一条重链** 
 
-由于每个点最多有一个重儿子,重边一定会连成链状结构,而不会连成一棵树。
+重链开头的结点不一定是重子节点(因为重边是对于每一个结点都有定义的)。
+
+所有的重链将整棵树 **完全剖分** 。
 
 在剖分时 **优先遍历重儿子** ,最后重链的 DFS 序就会是连续的。
 
-可以发现,当我们向下经过一条 **轻边** 时,所在子树的大小至少会除以二。所以,从一个点出发向子树内走最多经过 $O(\log n)$ 条轻边,也就是最多经过 $O(\log n)$ 条重链。
+在剖分时 **重边优先遍历** ,最后树的 DFN 序上,重链内的 DFN 序是连续的。按 DFN 排序后的序列即为剖分后的链。
+
+一颗子树内的 DFN 序是连续的。
 
-对于树上的任意一条路径,把它拆分成从两个端点的 LCA 分别向两边往下走,分别最多经过 $O(\log n)$ 条重链,因此,树上的每条路径都可以被拆分成不超过 $O(\log n)$ 条重链。
+可以发现,当我们向下经过一条 **轻边** 时,所在子树的大小至少会除以二。
+
+因此,对于树上的任意一条路径,把它拆分成从 $lca$ 分别向两边往下走,分别最多走 $O(\log n)$ 次,因此,树上的每条路径都可以被拆分成不超过 $O(\log n)$ 条重链。
 
 ## 常见应用
 
@@ -165,7 +169,7 @@ $$
 
 ### 子树维护
 
-有时会要求维护子树上的信息,譬如将以 $x$ 为根的子树的所有结点的权值增加 $v$ 。
+有时会要求维护子树上的信息,譬如将以 $x$ 为根的子树的所有结点的权值增加 $v$ 。
 
 在 DFS 搜索的时候,子树中的结点的 DFS 序是连续的。
 
@@ -193,6 +197,18 @@ int lca(int u, int v) {
 }
 ```
 
+??? note "怎么有理有据地卡树剖"
+
+    一般情况下树剖的 $O(\log n)$ 常数不满很难卡,如果要卡只能建立二叉树深度低。
+
+    于是我们可以考虑折中方案。
+
+    我们建立一颗 $\sqrt{n}$ 个节点的二叉树。对于每个节点到其儿子的边,我们将其替换成一条长度为 $\sqrt{n}$ 的链。
+
+    这样子我们可以将随机询问轻重链切换次数卡到平均 $\frac{\log n}{2}$ 次,同时有 $O(\sqrt{n} \log n)$ 的深度。
+
+    加上若干随机叶子看上去可以卡树剖。但是树剖常数小有可能卡不掉。
+
 ## 例题
 
 ###  [「ZJOI2008」树的统计](https://loj.ac/problem/10138) 
@@ -241,13 +257,10 @@ int querymax(int x, int y) {
     fx = top[x];
     fy = top[y];
   }
-  if (x != y) {
-    if (dfn[x] < dfn[y])
-      ret = max(ret, st.query1(1, 1, n, dfn[x], dfn[y]));
-    else
-      ret = max(ret, st.query1(1, 1, n, dfn[y], dfn[x]));
-  } else
+  if (dfn[x] < dfn[y])
     ret = max(ret, st.query1(1, 1, n, dfn[x], dfn[y]));
+  else
+    ret = max(ret, st.query1(1, 1, n, dfn[y], dfn[x]));
   return ret;
 }
 ```
@@ -345,13 +358,10 @@ int querymax(int x, int y) {
         fx = top[x];
         fy = top[y];
       }
-      if (x != y) {
-        if (dfn[x] < dfn[y])
-          ret = std::max(ret, st.query1(1, 1, n, dfn[x], dfn[y]));
-        else
-          ret = std::max(ret, st.query1(1, 1, n, dfn[y], dfn[x]));
-      } else
+      if (dfn[x] < dfn[y])
         ret = std::max(ret, st.query1(1, 1, n, dfn[x], dfn[y]));
+      else
+        ret = std::max(ret, st.query1(1, 1, n, dfn[y], dfn[x]));
       return ret;
     }
     int querysum(int x, int y) {
@@ -364,13 +374,10 @@ int querymax(int x, int y) {
         fx = top[x];
         fy = top[y];
       }
-      if (x != y) {
-        if (dfn[x] < dfn[y])
-          ret += st.query2(1, 1, n, dfn[x], dfn[y]);
-        else
-          ret += st.query2(1, 1, n, dfn[y], dfn[x]);
-      } else
+      if (dfn[x] < dfn[y])
         ret += st.query2(1, 1, n, dfn[x], dfn[y]);
+      else
+        ret += st.query2(1, 1, n, dfn[y], dfn[x]);
       return ret;
     }
     int main() {
@@ -519,6 +526,161 @@ $$
     }
     ```
 
+## 长链剖分
+
+长链剖分本质上就是另外一种链剖分方式。
+
+定义 **重子节点** 表示其子节点中子树深度最大的子结点。如果有多个子树最大的子结点,取其一。如果没有子节点,就无重子节点。
+
+定义 **轻子节点** 表示剩余的子结点。
+
+从这个结点到重子节点的边为 **重边** 。
+
+到其他轻子节点的边为 **轻边** 。
+
+若干条首尾衔接的重边构成 **重链** 。
+
+把落单的结点也当作重链,那么整棵树就被剖分成若干条重链。
+
+如图(这种剖分方式既可以看成重链剖分也可以看成长链剖分):
+
+![HLD](./images/hld.png)
+
+长链剖分实现方式和重链剖分类似,这里就不再展开。
+
+### 常见应用
+
+首先,我们发现长链剖分从一个节点到根的路径的轻边切换条数是 $\sqrt{n}$ 级别的。
+
+??? note "如何构造数据将轻重边切换次数卡满"
+    我们可以构造这么一颗二叉树 T:
+
+    假设构造的二叉树参数为 $D$ 。
+
+    若 $D \neq 0$, 则在左儿子构造一颗参数为 $D-1$ 的二叉树,在右儿子构造一个长度为 $2D-1$ 的链。
+
+    若 $D = 0$,则我们可以直接构造一个单独叶节点,并且结束调用。
+
+    这样子构造一定可以将单独叶节点到根的路径全部为轻边且需要 $D^2$ 级别的节点数。
+
+    取 $D=\sqrt{n}$ 即可。
+
+### 长链剖分优化 DP
+
+一般情况下可以使用长链剖分来优化的 DP 会有一维状态为深度维。
+
+我们可以考虑使用长链剖分优化树上 DP。
+
+具体的,我们每个节点的状态直接继承其重儿子的节点状态,同时将轻儿子的 DP 状态暴力合并。
+
+!!! note "[CF 1009F](http://codeforces.com/contest/1009/problem/F)"
+    我们设 $f_{i,j}$ 表示在子树 i 内,和 i 距离为 j 的点数。
+
+    直接暴力转移时间复杂度为 $O(n^2)$
+
+    我们考虑每次转移我们直接继承重儿子的 DP 数组和答案,并且考虑在此基础上进行更新。
+
+    首先我们需要将重儿子的 DP 数组前面插入一个元素 1,这代表着当前节点。
+
+    然后我们将所有轻儿子的 DP 数组暴力和当前节点的 DP 数组合并。
+
+    注意到因为轻儿子的 DP 数组长度为轻儿子所在重链长度,而所有重链长度和为 $n$。
+
+    也就是说,我们直接暴力合并轻儿子的总时间复杂度为 $O(n)$ 。
+
+注意,一般情况下 DP 数组的内存分配为一条重链整体分配内存,链上不同的节点有不同的首位置指针。
+
+DP 数组的长度我们可以根据子树最深节点算出。
+
+例题参考代码:
+
+```cpp
+#include <bits/stdc++.h>
+using namespace std;
+const int N = 1000005;
+struct edge {
+  int to, next;
+} e[N * 2];
+int head[N], tot, n;
+int d[N], fa[N], mx[N];
+int *f[N], g[N], mxp[N];
+int dfn[N];
+void add(int x, int y) {
+  e[++tot] = (edge){y, head[x]};
+  head[x] = tot;
+}
+void dfs1(int x) {
+  d[x] = 1;
+  for (int i = head[x]; i; i = e[i].next)
+    if (e[i].to != fa[x]) {
+      fa[e[i].to] = x;
+      dfs1(e[i].to);
+      d[x] = max(d[x], d[e[i].to] + 1);
+      if (d[e[i].to] > d[mx[x]]) mx[x] = e[i].to;
+    }
+}
+void dfs2(int x) {
+  dfn[x] = ++*dfn;
+  f[x] = g + dfn[x];
+  if (mx[x]) dfs2(mx[x]);
+  for (int i = head[x]; i; i = e[i].next)
+    if (e[i].to != fa[x] && e[i].to != mx[x]) dfs2(e[i].to);
+}
+void getans(int x) {
+  if (mx[x]) {
+    getans(mx[x]);
+    mxp[x] = mxp[mx[x]] + 1;
+  }
+  f[x][0] = 1;
+  if (f[x][mxp[x]] <= 1) mxp[x] = 0;
+  for (int i = head[x]; i; i = e[i].next)
+    if (e[i].to != fa[x] && e[i].to != mx[x]) {
+      getans(e[i].to);
+      int len = d[e[i].to];
+      For(j, 0, len - 1) {
+        f[x][j + 1] += f[e[i].to][j];
+        if (f[x][j + 1] > f[x][mxp[x]]) mxp[x] = j + 1;
+        if (f[x][j + 1] == f[x][mxp[x]] && j + 1 < mxp[x]) mxp[x] = j + 1;
+      }
+    }
+}
+int main() {
+  scanf("%d", &n);
+  for (int i = 1; i < n; i++) {
+    int x, y;
+    scanf("%d%d", &x, &y);
+    add(x, y);
+    add(y, x);
+  }
+  dfs1(1);
+  dfs2(1);
+  getans(1);
+  for (int i = 1; i <= n; i++) printf("%d\n", mxp[i]);
+}
+```
+
+当然长链剖分优化 DP 技巧非常多,包括但是不仅限于打标记等等。这里不再展开。
+
+参考 [租酥雨的博客](https://www.cnblogs.com/zhoushuyu/p/9468669.html) 。
+
+### 长链剖分求 k 级祖先
+
+即询问一个点向父亲跳 $k$ 次跳到的节点。
+
+首先我们假设我们已经预处理了每一个节点的 $2^i$ 级祖先。
+
+现在我们假设我们找到了询问节点的 $2^i$ 级祖先满足 $2^i < k < 2^{i+1}$ 。
+
+我们考虑求出其所在重链的节点并且按照深度列入表格。假设重链长度为 $d$ 。
+
+同时我们在预处理的时候找到每条重链的根节点的 $1$ 到 $d$ 级祖先,同样放入表格。
+
+根据长链剖分的性质, $k-2^i < 2^i < d$ , 也就是说,我们可以 $O(1)$ 在这条长链的表格上求出的这个节点的 $k$ 级祖先。
+
+预处理需要倍增出 $2^i$ 次级祖先,同时需要预处理每条重链对应的表格。
+
+预处理复杂度 $O(n\log n)$ , 询问复杂度 $O(1)$ 。
+
 ## 练习
 
  [「luogu P3379」【模板】最近公共祖先(LCA)](https://www.luogu.org/problemnew/show/P3379) (树剖求 LCA 无需数据结构,可以用作练习)
@@ -533,4 +695,8 @@ $$
 
  [「SDOI2011」染色](https://www.luogu.org/problem/P2486) 
 
- [「SDOI2014」旅行](https://loj.ac/problem/2195) 
+ [「SDOI2014」旅行](https://www.lydsy.com/JudgeOnline/problem.php?id=3531) 
+
+ [「POI2014」Hotel 加强版](https://www.lydsy.com/JudgeOnline/problem.php?id=4543) (长链剖分优化 DP)
+
+ [攻略](https://www.lydsy.com/JudgeOnline/problem.php?id=3252) (长链剖分优化贪心)
diff --git a/docs/graph/images/bi-graph-1.png b/docs/graph/images/bi-graph-1.png
new file mode 100644 (file)
index 0000000..b6ca166
Binary files /dev/null and b/docs/graph/images/bi-graph-1.png differ
diff --git a/docs/graph/images/bi-graph-2.png b/docs/graph/images/bi-graph-2.png
new file mode 100644 (file)
index 0000000..0a1ba3f
Binary files /dev/null and b/docs/graph/images/bi-graph-2.png differ
diff --git a/docs/graph/images/bi-graph-3.png b/docs/graph/images/bi-graph-3.png
new file mode 100644 (file)
index 0000000..4062b94
Binary files /dev/null and b/docs/graph/images/bi-graph-3.png differ
diff --git a/docs/graph/images/bi-graph-4.png b/docs/graph/images/bi-graph-4.png
new file mode 100644 (file)
index 0000000..4520397
Binary files /dev/null and b/docs/graph/images/bi-graph-4.png differ
diff --git a/docs/graph/images/bridge4.png b/docs/graph/images/bridge4.png
new file mode 100644 (file)
index 0000000..bb76574
Binary files /dev/null and b/docs/graph/images/bridge4.png differ
diff --git a/docs/graph/images/flow1.png b/docs/graph/images/flow1.png
deleted file mode 100644 (file)
index 25af900..0000000
Binary files a/docs/graph/images/flow1.png and /dev/null differ
diff --git a/docs/graph/images/flow2.png b/docs/graph/images/flow2.png
deleted file mode 100644 (file)
index 86b8f69..0000000
Binary files a/docs/graph/images/flow2.png and /dev/null differ
index 123fba2..cd2ddad 100644 (file)
@@ -1,99 +1,5 @@
- **图论(graph theory)** 是数学的一个分支,它以 **图** 为研究的对象。
-
-图论本身是应用数学的一部分,历史上图论曾经被很多数学家各自独立建立过。关于图论的最早文字记载最早出现在欧拉 1736 年的论著中,也就是著名的柯尼斯堡(Konigsberg)问题(七桥问题)。
-
-## 图的定义
-
-一个图 $G$ 是一个二元组,即序偶 $\langle V,E\rangle$ ,或记作 $G= \langle V,E\rangle$ ,其中 $V$ 是有限非空集合,称为 $G$ 的顶点集, $V$ 中的元素称为顶点或结点; $E$ 称为 $G$ 的边的集合, $\forall e_i \in E$ ,都有 $V$ 中的结点与之对应,称 $e_i$ 为 $G$ 的边。
-
-简单来说,就是图 $G$ 就是一个结点的集合 $V$ 和边的集合 $E$ ,其中任意一条边都可以表示为两个结点之间的关系。若 $e_i\in E$ 表示为 $\langle u,v\rangle$ ,则有 $u\in V , v\in V$ 。
-
-## 有向边和无向边
-
-以上定义的结点对 **可以是有序的,也可以是无序的** 。如果边 $e_i$ 和结点无序对 $(u,v)$ 相对应,则称 $e_i$ 为无向边,记作 $e_i=(u,v)$ ,称 $u,v$ 为边 $e_i$ 的两个端点。
-
-如果边 $e_i$ 和结点有序对 $\langle u,v\rangle$ 相对应,则称 $e_i$ 为有向边,记为 $e_i= \langle u,v\rangle$ ,称 $u$ 为边 $e_i$ 的 **始点** , $v$ 为该边的终点。
-
-简单来说,如果边对结点的关系是双向的,那么这条边是无向边;如果是单向的,那么这条边是有向边。
-
-## 图的基本概念
-
-无向图:每条边都是无向边的图。
-
-有向图:每条边都是有向边的图。
-
-混合图:在一个图中,有些边是有向边,另一些边是无向边,则该图为混合图。
-
-有限图:一个图的点集和边集都是有穷集的图。
-
-零图:边集为空集的图。
-
-平凡图:仅有一个结点而没有边构成的图。
-
-关联:若有 $e_i=(u,v)$ 且 $e_i\in E$ ,则称 $u$ 是和 $v$ 相关联的。
-
-孤立点:无边关联的点。
-
-自环:若一条边所关联的两个结点重合,则称此边为自环。
-
-邻接:关联于同一条边的两个点 $u$ 和 $v$ 称为邻接的;关联于同一个点的两条边 $e_1$ 和 $e_2$ 是邻接的(或相邻的)。
-
-## 结点的度数
-
-设图 $G= \langle V,E\rangle$ 为一个有向图, $v\in V$ ,关联于结点 $v$ 的 **边** 的条数,称为点 $v$ 的度数,记作 $\deg(v)$ 。
-
-注意:一个自环为它的端点增加 2 度。
-
-当图 $G= \langle V,E\rangle$ 为一个有向图, $v\in V$ ,称以 $v$ 作为始点的边数之和称为结点 $v$ 的出度,记为 $\deg^{+} (v)$ 。将以 $v$ 作为终点的边数之和称为结点 $v$ 的入度,记为 $\deg^{-} (v)$ 。称以 $v$ 作为端点的边数之和为结点 $v$ 的度数或度,记为 $\deg(v)$ 。
-
-显然, $\forall v\in V,\deg(v)=deg^{+} (v)+\deg^{-} (v)$ 。
-
-### 定理 1
-
- $\sum_{v\in V} \deg(v)=2\times |E|$ 
-
-推论:在任意图中,度数为奇数的点必然有偶数个。
-
-### 定理 2
-
- $\sum_{v\in V} \deg^{+} (v)=\sum_{v\in V} \deg^{-} (v)=|E|$ 
-
-即所有点入度之和等于出度之和。
-
-## 子图的概念
-
-设有图 $G= \langle V,E\rangle$ 和图 $G'= \langle V',E'\rangle$ 。
-
-如果 $V'\subseteq V,E'\subseteq E$ ,则称 $G'$ 是 $G$ 的子图,记作 $G'\subseteq G$ 。
-
-如果 $G'\subsetneqq G$ ,即 $V'\subset V$ 或 $E'\subset E$ ,则称 $G'$ 是 $G$ 的真子图,记作 $G'\subset G$ 。
-
-如果 $V'=V,E'\subseteq E$ ,则称 $G'$ 是 $G$ 的生成子图。
-
-如果 $V''\subseteq V$ 且 $V'' \neq \varnothing$ ,以 $V''$ 为结点集,以两端点均在 $V''$ 中的边为边集的 $G$ 的子图,称为 $V''$ 导出的 $G$ 的子图,简称为 $V''$ 的导出子图。
-
-如果 $G''= \langle V'',E''\rangle$ 使得 $E''=E-E'$ ,且 $V''$ 中仅包含 $E''$ 中的边所关联的结点,则称 $G''$ 是子图 $G'$ 相对于原图 $G$ 的补图。
-
-## 特殊的图
-
-树:边数比结点数少一的连通图。更多内容,详见 [树相关基础](./tree-basic.md) 。
-
-森林:由 $m$ 棵( $m\ge 0$ )互不相交的树组成的图。
-
-基环树:边数和点数相等的连通图。
-
-仙人掌:每条边至多属于一个简单环的无向连通图。
-
-在无向图中,关联一对顶点的边多于 $1$ 条,则称这些边为重边(平行边),重边的条数称为重数。
-
-简单图:不含重边和自环的图。
-
-多重图:含重边的图。
-
-完全图:每对不同的顶点之间都恰连有一条边相连的简单无向图。容易证明, $n$ 个顶点的完全图有 $\dfrac{n(n-1)}{2}$ 条边。
-
-竞赛图:通过在完全图中为每条边分配方向而获得的有向图。
+ **图论 (Graph theory)** 是数学的一个分支,图是图论的主要研究对象。 **图 (Graph)** 是由若干给定的顶点及连接两顶点的边所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系。顶点用于代表事物,连接两顶点的边则用于表示两个事物间具有这种关系。
 
 ## 参考资料
 
-离散数学(修订版),田文成 周禄新 编著,天津文学出版社,P184-187
+ <https://zh.wikipedia.org/wiki/图论> 
index 57c2714..d22ab49 100644 (file)
@@ -2,7 +2,7 @@
 
 Lindström–Gessel–Viennot lemma,即 LGV 引理,可以用来处理有向无环图上不相交路径计数等问题。
 
\89\8dç½®ç\9f¥è¯\86ï¼\9a [å\9b¾è®ºç®\80ä»\8b](./index.md) ã\80\81 [å\9b¾è®ºå\9fºç¡\80](./basic.md) 、 [矩阵](../math/matrix.md) 、 [高斯消元求行列式](../math/gauss.md) 。
\89\8dç½®ç\9f¥è¯\86ï¼\9a [å\9b¾è®ºç\9b¸å\85³æ¦\82念](./concept.md) ä¸­ç\9a\84å\9fºç¡\80é\83¨å\88\86、 [矩阵](../math/matrix.md) 、 [高斯消元求行列式](../math/gauss.md) 。
 
 LGV 引理仅适用于 **有向无环图** 。
 
diff --git a/docs/graph/misc.md b/docs/graph/misc.md
deleted file mode 100644 (file)
index 32288ae..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-## 支配集
-
-设无向图 $G=<V,E>, V^*\subset V$ ,若对任意的 $v_i \in V-V^*$ ,都存在 $v_j \in V^*$ ,使得 $(v_i, v_j) \in E$ ,则称 $v_j$ 支配 $v_i$ ,并称 $V^*$ 为 $G$ 的一个支配集。最小支配集的顶点个数记为 $\gamma_0$ 
-
-## 独立集
-
-### 点独立集
-
-设无向图 $G=<V,E>, V^*\subset V$ ,若 $V^*$ 中任意两个顶点均不相邻,则称 $V^*$ 为 $G$ 的点独立集,或称独立集。最大点独立集的顶点个数记做 $\beta_0$ 
-
-若 $G$ 中无孤立点, $V^*$ 为 $G$ 中极大独立集,则 $V^*$ 为极小独立集。
-
-### 匹配
-
-设无向图 $G=<V,E>, E^*\subset E$ ,若 $E^*$ 中任意两个边均不相邻,则称 $E^*$ 为 $G$ 的边独立集,或称匹配。最大匹配的边数记做 $\beta_1$ 
-
-设 $M_1, M_2$ 为两个不同的匹配,则 $G[M_1 \oplus M_2]$ 的每个连通分支为 $M_1, M_2$ 中的边组成的交错圈或交错路径。
-
-#### 相关定义
-
-设 $M$ 为图 $G$ 的匹配:
-
- $M$ 饱和点:匹配 $M$ 中边关联的点
-
-完美匹配:每个顶点都是 $M$ 饱和点
-
-增广路:在 $M$ 和 $E(G)-M$ 中交替取边的交错路径,且起点和终点都是 $M$ 非饱和点
-
-#### 托特定理
-
- $n$ 阶无向图 $G$ 有完美匹配当且仅当对于任意的 $V' \subset V(G)$ , $p_{奇}(G-V')\leq |V'|$ ,其中 $p_{奇}$ 表示奇数阶连通分支数。
-
-推论:任何无桥 3 - 正则图都有完美匹配。
-
-## 覆盖集
-
-### 点覆盖
-
-设无向图 $G=<V,E>, V^*\subset V$ ,若对于任意的 $e \in E$ ,都存在 $v \in V^*$ ,使得 $v$ 与 $e$ 相关联,则称 $v$ 覆盖 $e$ ,称 $V^*$ 为 $G$ 中点覆盖集。最小点覆盖集的元素个数记为 $\alpha_0$ 
-
-点覆盖集必为支配集,但极小点覆盖集不一定是极小支配集。
-
-若 $V^*$ 为点覆盖集,则 $V-V^*$ 为点独立集。
-
-### 边覆盖
-
-设无向图 $G=<V,E>, E^*\subset E$ ,若对于任意的 $v \in V$ ,都存在 $e \in E^*$ ,使得 $v$ 与 $e$ 相关联,则称 $e$ 覆盖 $v$ ,称 $E^*$ 为 $G$ 中边覆盖集。最小边覆盖集的元素个数记为 $\alpha_1$ 
-
-边覆盖与匹配的关系:
-
-1.  对于一个最大匹配 $M$ ,对其每个非饱和点取一条关联的边组成的边集 $N$ ,则 $W=M \cup N$ 为一个最小边覆盖集。( $\beta_1 \leq \alpha_1$ )
-2.  对于一个最小边覆盖集 $W_1$ ,若 $W_1$ 中存在相邻的边就移去其中的一条边,继续这一过程,直到无相邻边,设移去的边集合为 $N_1$ ,则 $M_1=W_1-N_1$ 为一个最大匹配。
-3.   $\alpha_1 + \beta_1 = n$ 
-4.  对图 $G$ , $M$ 为一个匹配, $W$ 为一个边覆盖,则 $|M| \leq |W|$ 。等号成立时分别为完美匹配和最小边覆盖。
-
-对图 $G$ , $M$ 为一个匹配, $W$ 为一个边覆盖, $N$ 为一个点覆盖, $Y$ 为一个点独立集,则:
-
-1.   $|M| \leq |N|$ 
-2.   $|Y| \leq |W|$ 
-
-推论: $\beta_1 \leq \alpha_0, \beta_0 \leq \alpha_1$ 
-
-对于完全二部图 $K_{r,s}$ ,有: $\alpha_0=\min\{r,s\}=\beta_1, \beta_0=\max\{r,s\}=\alpha_1$ 
-
-## 团
-
-设无向图 $G=<V,E>, V^*\subset V$ ,若导出子图 $G[V^*]$ 是完全图,则称 $V^*$ 为团。最大团的顶点个数称为团数,记做 $\nu_0$ 
-
- $V^*$ 为 $G$ 的团当且仅当 $V^*$ 为 $\bar{G}$ 的独立集。
-
-推论: $\nu_0(G) = \beta_0(\bar{G})$ 
-
-??? note
-    到目前为止,求图中的极小(最小)支配集、极小(最小)点覆盖、极大(最大)独立集和极大(最大)团还没有找到有效的多项式时间算法。
index 0591f41..5659f65 100644 (file)
@@ -1,6 +1,6 @@
 ## 定义
 
-在阅读下列内容之前,请务必阅读 [图论基础](/graph/basic) 与 [树基础](/graph/tree-basic) 部分,并了解以下定义:
+在阅读下列内容之前,请务必阅读 [图论相关概念](./concept.md) 与 [树基础](./tree-basic.md) 部分,并了解以下定义:
 
 1.  生成子图
 2.  生成树
@@ -15,7 +15,7 @@ Kruskal 算法是一种常见并且好写的最小生成树算法,由 Kruskal
 
 ### 前置知识
 
- [并查集](../ds/dsu.md) 、 [贪心](../basic/greedy.md) 、 [图的存储](./basic.md) 。
+ [并查集](../ds/dsu.md) 、 [贪心](../basic/greedy.md) 、 [图的存储](./save.md) 。
 
 ### 证明
 
diff --git a/docs/graph/save.md b/docs/graph/save.md
new file mode 100644 (file)
index 0000000..b64d0ae
--- /dev/null
@@ -0,0 +1,289 @@
+author: Ir1d, sshwy, Xeonacid, partychicken, Anguei, HeRaNO
+在 OI 中,想要对图进行操作,就需要先学习图的存储方式。
+
+## 约定
+
+本文默认读者已阅读并了解了 [图论相关概念](./concept.md) 中的基础内容,如果在阅读中遇到困难,也可以在 [图论相关概念](./concept.md) 中进行查阅。
+
+在本文中,用 $n$ 代指图的点数,用 $m$ 代指图的边数,用 $d^+(u)$ 代指点 $u$ 的出度,即以 $u$ 为出发点的边数。
+
+## 直接存边
+
+### 方法
+
+使用一个数组来存边,数组中的每个元素都包含一条边的起点与终点(带边权的图还包含边权)。(或者使用多个数组分别存起点,终点和边权。)
+
+??? note "参考代码"
+    ```cpp
+    #include <iostream>
+    #include <vector>
+    
+    using namespace std;
+    
+    struct Edge {
+      int u, v;
+    };
+    
+    int n, m;
+    vector<Edge> e;
+    vector<bool> vis;
+    
+    bool find_edge(int u, int v) {
+      for (int i = 1; i <= m; ++i) {
+        if (e[i].u == u && e[i].v == v) {
+          return true;
+        }
+      }
+      return false;
+    }
+    
+    void dfs(int u) {
+      if (vis[u]) return;
+      vis[u] = true;
+      for (int i = 1; i <= m; ++i) {
+        if (e[i].u == u) {
+          dfs(e[i].v);
+        }
+      }
+    }
+    
+    int main() {
+      cin >> n >> m;
+    
+      vis.resize(n + 1, false);
+      e.resize(m + 1);
+    
+      for (int i = 1; i <= m; ++i) cin >> e[i].u >> e[i].v;
+    
+      return 0;
+    }
+    ```
+
+### 复杂度
+
+查询是否存在某条边: $O(m)$ 。
+
+遍历一个点的所有出边: $O(m)$ 。
+
+遍历整张图: $O(nm)$ 。
+
+空间复杂度: $O(m)$ 。
+
+### 应用
+
+由于直接存边的遍历效率低下,一般不用于遍历图。
+
+在 [Kruskal 算法](./mst.md#kruskal) 中,由于需要将边按边权排序,需要直接存边。
+
+在有的题目中,需要多次建图(如建一遍原图,建一遍反图),此时既可以使用多个其它数据结构来同时存储多张图,也可以将边直接存下来,需要重新建图时利用直接存下的边来建图。
+
+## 邻接矩阵
+
+### 方法
+
+使用一个二维数组 `adj` 来存边,其中 `adj[u][v]` 为 1 表示存在 $u$ 到 $v$ 的边,为 0 表示不存在。如果是带边权的图,可以在 `adj[u][v]` 中存储 $u$ 到 $v$ 的边的边权。
+
+??? note "参考代码"
+    ```cpp
+    #include <iostream>
+    #include <vector>
+    
+    using namespace std;
+    
+    int n, m;
+    vector<bool> vis;
+    vector<vector<bool> > adj;
+    
+    bool find_edge(int u, int v) { return adj[u][v]; }
+    
+    void dfs(int u) {
+      if (vis[u]) return;
+      vis[u] = true;
+      for (int v = 1; v <= n; ++v) {
+        if (adj[u][v]) {
+          dfs(v);
+        }
+      }
+    }
+    
+    int main() {
+      cin >> n >> m;
+    
+      vis.resize(n + 1, false);
+      adj.resize(n + 1, vector<bool>(n + 1, false));
+    
+      for (int i = 1; i <= m; ++i) {
+        int u, v;
+        cin >> u >> v;
+        adj[u][v] = true;
+      }
+    
+      return 0;
+    }
+    ```
+
+### 复杂度
+
+查询是否存在某条边: $O(1)$ 。
+
+遍历一个点的所有出边: $O(n)$ 。
+
+遍历整张图: $O(n^2)$ 。
+
+空间复杂度: $O(n^2)$ 。
+
+### 应用
+
+邻接矩阵只适用于没有重边(或重边可以忽略)的情况。
+
+其最显著的优点是可以 $O(1)$ 查询一条边是否存在。
+
+由于邻接矩阵在稀疏图上效率很低(尤其是在点数较多的图上,空间无法承受),所以一般只会在稠密图上使用邻接矩阵。
+
+## 邻接表
+
+### 方法
+
+使用一个支持动态增加元素的数据结构构成的数组,如 `vector<int> adj[n + 1]` 来存边,其中 `adj[u]` 存储的是点 $u$ 的所有出边的相关信息(终点、边权等)。
+
+??? note "参考代码"
+    ```cpp
+    #include <iostream>
+    #include <vector>
+    
+    using namespace std;
+    
+    int n, m;
+    vector<bool> vis;
+    vector<vector<int> > adj;
+    
+    bool find_edge(int u, int v) {
+      for (int i = 0; i < adj[u].size(); ++i) {
+        if (adj[u][i] == v) {
+          return true;
+        }
+      }
+      return false;
+    }
+    
+    void dfs(int u) {
+      if (vis[u]) return;
+      vis[u] = true;
+      for (int i = 0; i < adj[u].size(); ++i) dfs(adj[u][i]);
+    }
+    
+    int main() {
+      cin >> n >> m;
+    
+      vis.resize(n + 1, false);
+      adj.resize(n + 1);
+    
+      for (int i = 1; i <= m; ++i) {
+        int u, v;
+        cin >> u >> v;
+        adj[u].push_back(v);
+      }
+    
+      return 0;
+    }
+    ```
+
+### 复杂度
+
+查询是否存在 $u$ 到 $v$ 的边: $O(d^+(u))$ (如果事先进行了排序就可以使用 [二分查找](../basic/binary.md) 做到 $O(\log(d^+(u)))$ )。
+
+遍历点 $u$ 的所有出边: $O(d^+(u))$ 。
+
+遍历整张图: $O(n+m)$ 。
+
+空间复杂度: $O(m)$ 。
+
+### 应用
+
+存各种图都很适合,除非有特殊需求(如需要快速查询一条边是否存在,且点数较少,可以使用邻接矩阵)。
+
+尤其适用于需要对一个点的所有出边进行排序的场合。
+
+## 链式前向星
+
+### 方法
+
+本质上是用链表实现的邻接表,核心代码如下:
+
+```cpp
+// head[u] 和 cnt 的初始值都为 -1
+void add(int u, int v) {
+  nxt[++cnt] = head[u];  // 当前边的后继
+  head[u] = cnt;         // 起点 u 的第一条边
+  to[cnt] = v;           // 当前边的终点
+}
+
+// 遍历 u 的出边
+for (int i = head[u]; ~i; i = nxt[i]) {  // ~i 表示 i != -1
+  int v = to[i];
+}
+```
+
+??? note "参考代码"
+    ```cpp
+    #include <iostream>
+    #include <vector>
+    
+    using namespace std;
+    
+    int n, m;
+    vector<bool> vis;
+    vector<int> head, nxt, to;
+    
+    void add(int u, int v) {
+      nxt.push_back(head[u]);
+      head[u] = to.size();
+      to.push_back(v);
+    }
+    
+    bool find_edge(int u, int v) {
+      for (int i = head[u]; ~i; i = nxt[i]) {  // ~i 表示 i != -1
+        if (to[i] == v) {
+          return true;
+        }
+      }
+      return false;
+    }
+    
+    void dfs(int u) {
+      if (vis[u]) return;
+      vis[u] = true;
+      for (int i = head[u]; ~i; i = nxt[i]) dfs(to[i]);
+    }
+    
+    int main() {
+      cin >> n >> m;
+    
+      vis.resize(n + 1, false);
+      head.resize(n + 1, -1);
+    
+      for (int i = 1; i <= m; ++i) {
+        int u, v;
+        cin >> u >> v;
+        add(u, v);
+      }
+    
+      return 0;
+    }
+    ```
+
+### 复杂度
+
+查询是否存在 $u$ 到 $v$ 的边: $O(d^+(u))$ 。
+
+遍历点 $u$ 的所有出边: $O(d^+(u))$ 。
+
+遍历整张图: $O(n+m)$ 。
+
+空间复杂度: $O(m)$ 。
+
+### 应用
+
+存各种图都很适合,但不能快速查询一条边是否存在,也不能方便地对一个点的出边进行排序。
+
+优点是边是带编号的,有时会非常有用,而且如果 `cnt` 的初始值为奇数,存双向边时 `i ^ 1` 即是 `i` 的反边(常用于 [网络流](./flow.md) )。
index 0429754..22a0f2f 100644 (file)
@@ -1,6 +1,6 @@
 ## 简介
 
-在阅读下列内容之前,请务必了解 [图论基础](/graph/basic) 部分。
+在阅读下列内容之前,请务必了解 [图论相关概念](./concept.md) 中的基础部分。
 
 强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通。
 
index 82b570a..94f73b5 100644 (file)
@@ -1,6 +1,6 @@
 ## 定义
 
-(还记得这些定义吗?在阅读下列内容之前,请务必了解 [图论基础](/graph/basic) 部分。)
+(还记得这些定义吗?在阅读下列内容之前,请务必了解 [图论相关概念](./concept.md) 中的基础部分。)
 
 -   路径
 -   最短路
diff --git a/docs/images/OI_wiki_new_year_ver.png b/docs/images/OI_wiki_new_year_ver.png
new file mode 100644 (file)
index 0000000..780f1f8
Binary files /dev/null and b/docs/images/OI_wiki_new_year_ver.png differ
diff --git a/docs/images/euler1.png b/docs/images/euler1.png
new file mode 100644 (file)
index 0000000..51d7b9a
Binary files /dev/null and b/docs/images/euler1.png differ
diff --git a/docs/images/euler2.png b/docs/images/euler2.png
new file mode 100644 (file)
index 0000000..10b428c
Binary files /dev/null and b/docs/images/euler2.png differ
diff --git a/docs/images/wordArt.png b/docs/images/wordArt.png
deleted file mode 100644 (file)
index ecbba36..0000000
Binary files a/docs/images/wordArt.png and /dev/null differ
diff --git a/docs/images/wordArt.webp b/docs/images/wordArt.webp
new file mode 100644 (file)
index 0000000..65585a0
Binary files /dev/null and b/docs/images/wordArt.webp differ
index ec9f4cf..3bacf8e 100644 (file)
@@ -4,7 +4,7 @@ title: OI Wiki
 
 # 欢迎来到 **OI Wiki** ! [![GitHub watchers](https://img.shields.io/github/watchers/OI-wiki/OI-wiki.svg?style=social&label=Watch)](https://github.com/OI-wiki/OI-wiki)  [![GitHub stars](https://img.shields.io/github/stars/OI-wiki/OI-wiki.svg?style=social&label=Stars)](https://github.com/OI-wiki/OI-wiki) 
 
- [![Word Art](./images/wordArt.png)](https://github.com/OI-wiki/OI-wiki) 
+ [![Word Art](./images/wordArt.webp)](https://github.com/OI-wiki/OI-wiki) 
 
  **OI** (Olympiad in Informatics,信息学奥林匹克竞赛)在中国起源于 1984 年,是五大高中学科竞赛之一。自 1989 年起,每年还会选拔出国家集训队选手准备 IOI (International Olympiad in Informatics,国际信息学奥林匹克竞赛)。
 
@@ -96,3 +96,8 @@ Telegram 群组链接为 [@OIwiki](https://t.me/OIwiki) ,QQ 群号码为 [ `58
   // #758
   document.getElementsByClassName('md-nav__title')[1].click()
 </script>
+
+<div align="center">
+<a href="https://www.hulu.com/" target="_blank"><img height="40px" src="https://i.loli.net/2020/01/24/mtfvuxEFiO8dY1Z.png" ></a>
+<a href="https://www.netlify.com/" target="_blank" style="margin-left: 60px;"><img height="40px" src="https://cn-south-17-rsshub-16857749.oss.dogecdn.com/netlify.png"></a>
+</div>
index 57f1f91..24e1381 100644 (file)
@@ -8,12 +8,24 @@
 
 -   写完 `struct` 或 `class` 忘记写分号。
 
+-   数组开太大,(在 OJ 上)使用了不合法的函数(例如多线程),或者函数声明但未定义,会引起链接错误。
+
+-   使用 `algorithm` 中的 `max` 函数时,一个参数类型为 `int` 而另一个参数类型为 `long long` 
+    -   示例:
+        ```cpp
+        printf("%lld\n", max(0, query(1, 1, n, l, r)); // query 返回 long long 类型
+        ```
+
+-    `goto` 的时候,跳过了一些局部变量的初始化。
+
+    -    `switch-case` 的时候,跳过了一些局部变量的初始化。
+
 ## 不会引起 Compile Error 但会引发 Warning 的错误
 
 这类错误较难发现,但会在使用 `-W{warningtype}` 参数编译时被编译器指出,所以要多学会使用 `-W{warningtype}` 参数,常见的有 `-Wall` , `-Wextra` , `-Wshadow` 等。
 
 -   由于运算符优先级产生的错误。
-    -    `1 << 1 + 1` : 1 左移了 2,即该表达式返回的值是 `4` 
+    -    `1 << 1 + 1` : 1 左移了 2,即该表达式返回的值是 4
 
 -   不正确地使用 `static` 修饰符。
 
         ```
         无论 $n$ 的值之前为多少,输出肯定是 `Yes` 。
 
--   使用 `scanf` 读入的时候没加取地址符 `&` 。
+-   使用 `scanf` 读入的时候没加取地址符 `&` 。更一般地,使用 `scanf` 或 `printf` 的时候参数类型与格式指定符不符。
 
 -   没有考虑数组下标出现负数的情况。
 
+-   同时使用位运算和逻辑运算符( `==` )并且未加括号(例如 `(x>>j)&3==2` )。
+
+-    `int` 字面量溢出,例如: `long long x = 0x7f7f7f7f7f7f7f7f` , `1<<62` 。
+
+-   未初始化局部变量,导致局部变量被赋予垃圾初值。
+
+-   局部变量与全局变量重名,导致全局变量被意外覆盖。(开 `-Wshadow` 就可检查此类错误。)
+
 ## 既不会引起 Compile Error 也不会引发 Warning 的错误
 
 这类错误无法被编译器发现,所以在调试时只能依靠你自己。
 
--   无向图边表未开 2 倍。
-
--   线段树未开 4 倍空间。
+### 会导致 WA
 
 -   多组数据未清空数组。
 
--   分治未判边界导致死递归。
-
 -   读入优化未判断负数。
 
--   所用数据类型不够大导致溢出,即常见的不开 `long long` 见祖宗
+-   所用数据类型不够大导致溢出,即常见的“三年 OI 一场空,不开 `long long` 见祖宗”,意思是因为没有使用 `long long` (开 `long long` )导致大量丢分从而赛季作废。
 
--   存图下标从 0 开始输入节点未 -1。
-
--   BFS 时不标记某个状态是否已访问过。
+-   存图时,节点编号 0 开始,而题目给的边中两个端点的编号从 1 开始,读入的时候忘记 -1。
 
 -   大/小于号打错或打反。
 
 -   在执行 `ios::sync_with_stdio(false);` 后混用两种 IO,导致输入/输出错乱。
     -   可以参考这个例子。
         ```cpp
-        //这个例子将说明,关闭与 stdio 的同步后,混用两种 IO 的后果
-        //建议单步运行来观察效果
+        // 这个例子将说明,关闭与 stdio 的同步后,混用两种 IO 的后果
+        // 建议单步运行来观察效果
         #include <cstdio>
         #include <iostream>
         int main() {
           std::ios::sync_with_stdio(false);
-          //关闭同步后,cin/cout 将使用独立缓冲区,而不是将输出同步至 scanf/printf
-          //的缓冲区,从而减少 IO 耗时
+          // 关闭同步后,cin/cout 将使用独立缓冲区,而不是将输出同步至 scanf/printf
+          // 的缓冲区,从而减少 IO 耗时
           std::cout << "a\n";
           // cout 下,使用'\n'换行时,内容会被缓冲而不会被立刻输出,应该使用 endl
           // 来换行并立刻刷新缓冲区
@@ -75,6 +89,7 @@
           return 0;  //程序结束时,cout 的缓冲区才会被输出
         }
         ```
+    -   特别的,也不能在执行 `ios::sync_with_stdio(false);` 后使用 `freopen` 。
 
 -   由于宏的展开,且未加括号导致的错误:
     ```cpp
     ```
     该宏返回的值并非 $4^2 = 16$ 而是 $2+2\times 2+2 = 8$ 。
 
--   使用宏展开编写 min/max
-     这种做法虽然算不上是「错误」,但是这里还是要拎出来说一下。
-               常见的写法是这样的:
-               ```cpp
-               #define Min(x, y) (x < y ? x : y)
-               #define Max(x, y) (x > y ? x : y)
-               ```
-               这样写虽然在正确性上没有问题,但是如果你直接对函数的返回值取 max,如 `a = Max(func1(), func2())`,而这个函数的运行时间较长,则会大大影响程序的性能,因为宏展开后是 `a = func1() > func2() ? func1() : func2()` 的形式,调用了三次函数,比正常的 max 函数多调用了一次。
-               这种错误在初学者写线段树时尤为多见。
+-   哈希的时候没有使用 `unsigned` ,因为对负数的右移运算会在最高位补 1,详见 [位运算](../math/bit.md) 
 
--   æ\96\87件æ\93\8dä½\9cæ\9c\89å\8f¯è\83½ä¼\9aå\8f\91ç\94\9fç\9a\84é\94\99误ã\80\82
+-   æ²¡æ\9c\89å\88 é\99¤è°\83è¯\95ä¿¡æ\81¯ã\80\82
 
-    -   对拍时未清除文件指针即 `fclose(fp)` 就又令 `fp = fopen()` , 这会使得进程出现大量的文件野指针。
-    -    `freopen()` 中的文件名未加 `.in` / `.out` 。
+-   误加了 `;` 。
+    -   可以参考这个例子:
+        ```cpp
+        /* clang-format off */
+        while (1);
+            printf("OI Wiki!\n");
+        ```
+
+-   没有正确设置哨兵值。例如,平衡树的 `0` 节点。
+
+-   在类或结构体的构造函数中,使用 : 初始化变量,且变量声明顺序不符合初始化时候的依赖关系。因为成员变量的初始化顺序只与它们在类中声明的顺序有关,而与在初始化列表中的顺序无关。
+
+-   并查集合并集合时没有把两个元素的祖先合并:
+
+```cpp
+f[a] = b;              //错误
+f[find(a)] = find(b);  // 正确
+```
+
+### 会导致 RE
+
+-   对整数除以 $0$ 。
+    -   对 $0$ 求逆元。
+
+-   没删文件操作(某些 OJ)。
 
 -   排序时比较函数的错误 `std::sort` 要求比较函数是严格弱序: `a<a` 为 `false` ;若 `a<b` 为 `true` ,则 `b<a` 为 `false` ;若 `a<b` 为 `true` 且 `b<c` 为 `true` ,则 `a<c` 为 `true` 。其中要特别注意第二点。
     如果不满足上述要求,排序时很可能会 RE。
       else
         return block[a.l] < block[b.l];
     ```
+
+-   解引用空指针。
+
+### 会导致 TLE
+
+-   分治未判边界导致死递归。
+
+-   死循环。
+
+    -   循环变量重名。
+
+    -   循环方向反了。
+
+-   BFS 时不标记某个状态是否已访问过。
+
+-   使用宏展开编写 min/max
+
+    这种做法虽然算不上是「错误」,但是这里还是要拎出来说一下。
+
+    常见的写法是这样的:
+
+    ```cpp
+    #define Min(x, y) ((x) < (y) ? (x) : (y))
+    #define Max(x, y) ((x) > (y) ? (x) : (y))
+    ```
+
+    这样写虽然在正确性上没有问题,但是如果你直接对函数的返回值取 max,如 `a = Max(func1(), func2())` ,而这个函数的运行时间较长,则会大大影响程序的性能,因为宏展开后是 `a = func1() > func2() ? func1() : func2()` 的形式,调用了三次函数,比正常的 max 函数多调用了一次。
+
+    这种错误在初学者写线段树时尤为多见,会大大增加程序的运行时间,甚至直接影响代码的时间复杂度。例如这份错误代码:
+
+    ```cpp
+    #define max(x, y) ((x) > (y) ? (x) : (y))
+
+    int query(int t, int l, int r, int ql, int qr) {
+      if (ql <= l && qr >= r) {
+        ++ti[t];  // 记录结点访问次数方便测试
+        return vi[t];
+      }
+
+      int mid = (l + r) >> 1;
+      if (mid >= qr) {
+        return query(lt(t), l, mid, ql, qr);
+      }
+      if (mid < ql) {
+        return query(rt(t), mid + 1, r, ql, qr);
+      }
+      return max(query(lt(t), l, mid, ql, qr), query(rt(t), mid + 1, r, ql, qr));
+    }
+    ```
+
+    会被卡到单次查询 $\Theta(n)$ 导致 TLE。
+
+-   没删文件操作(另一些 OJ)。
+
+-    `for (int i = 0; i < strlen(s); ++i)` :在循环中重复执行复杂度非 $O(1)$ 的函数。(严格来说,这可能会引起时间复杂度的改变。)
+
+### 会导致 MLE
+
+-   数组过大。
+
+-   STL 容器中插入了过多的元素。
+
+    -   经常是在一个会向 STL 插入元素的循环中死循环了。
+
+    -   也有可能被卡了。
+
+### 错误类型不定
+
+-   数组越界。上下都算。(多数是 RE。)
+
+    -   未正确设置循环的初值导致访问了下标为 -1 的值。
+
+    -   无向图边表未开 2 倍。
+
+    -   线段树未开 4 倍空间。
+
+    -   看错数据范围,少打一个零。
+
+    -   错误预估了算法的空间复杂度。
+
+    -   写线段树的时候, `pushup` 或 `pushdown` 叶节点。
+
+-   解引用野指针。
+
+    -   未初始化就解引用指针。
+
+    -   指针指向的区域已经 `free` 或 `delete` 。
+
+### 会导致常数过大
+
+-   定义模数的时候,使用了全局变量(如 `int mod = 998244353` ,正确做法是 `const int mod = 998244353` )。
+
+-   使用了不必要的递归(需要注意的是,尾递归不在此列)。
+
+-   将递归转化成迭代的时候,引入了大量额外运算。
+
+### 只在程序在本地运行的时候造成影响的错误
+
+-   文件操作有可能会发生的错误。
+
+    -   对拍时未清除文件指针即 `fclose(fp)` 就又令 `fp = fopen()` , 这会使得进程出现大量的文件野指针。
+
+    -    `freopen()` 中的文件名未加 `.in` / `.out` 。
+
+-   使用堆空间忘记 `delete` 或 `free` 。
index a030143..1860e86 100644 (file)
@@ -1,7 +1,26 @@
 disqus:
 
-Hulu 是美国领先的互联网专业视频服务平台,成立于 2006 年,目前由迪士尼控股,在美国拥有超过 2900 万付费用户。通过 Hulu,用户可以在电脑、可联网电视机、手机、平板电脑等多种设备上观看长视频和电视直播。2017 年,Hulu 自制剧《使女的故事》成为艾美奖和金球奖双料最大赢家,斩获十余奖项;2019 年,Hulu 自制纪录片《滑板少年》获奥斯卡最佳纪录片提名。
+Hulu 是美国领先的互联网专业视频服务平台,成立于 2006 年,目前由迪士尼控股,在美国拥有超过 2900 万付费用户。通过 Hulu,用户可以在电脑、可联网电视机、手机、平板电脑等多种设备上观看长视频和电视直播。
 
-Hulu 总部位于美国洛杉矶,北京办公室是仅次于总部的第二大研发中心,也是从 Hulu 成立伊始就具有重要战略地位的研发中心,独立负责播放器开发、搜索和推荐、广告精准投放、大规模用户数据处理、视频内容分析、视频编解码等核心项目,在人工智能,机器学习,计算机视觉和视频理解方面有专门的研究部门,拥有数十项相关专利。十多年来,Hulu 北京的团队规模已经从不到 10 人发展到如今拥有约两百名顶尖的技术人才,博士和硕士比例超过百分之八十。
+<div style="text-align:center;font-weight:bold;margin-top: 35px;font-size: 25pt;"> Hulu 是全美领先的流媒体平台 </div>
+<img style="display: block;margin: 0 auto;" src="https://i.loli.net/2020/02/03/6oCP7XOKj9AvzMR.png" />
 
-正如 Hulu 的产品是技术与娱乐的最佳结合,在 Hulu 工作,既能与一群志同道合的技术达人合作学习,又能享受充满乐趣的工作环境。2018 年,Hulu 北京荣膺“大中华区最佳职场 ®”榜单第一名。
+2017 年,Hulu 自制剧《使女的故事》成为艾美奖和金球奖双料最大赢家,斩获十余奖项;2019 年,Hulu 自制纪录片《滑板少年》获奥斯卡最佳纪录片提名。
+
+<div style="text-align:center;font-weight:bold;margin-top: 35px;font-size: 25pt;"> Hulu 办公室分布 </div>
+<img style="display: block;margin: 0 auto;" src="https://i.loli.net/2020/02/03/Z87FfMHA6kxqclt.png" />
+
+Hulu 总部位于美国洛杉矶,在全球一共拥有 8 个办公室。北京办公室是仅次于总部的第二大研发中心,也是从 Hulu 成立伊始就具有重要战略地位的研发中心。
+
+<div style="text-align:center;font-weight:bold;margin-top: 35px;font-size: 25pt;"> Hulu 北京办公室 </div>
+<img style="display: block;margin: 0 auto;" src="https://i.loli.net/2020/02/03/M9dIrShWJDNoGia.png" />
+
+Hulu 北京办公室成立于 2007 年,目前规模为 200 人,其中博士和硕士比例超过百分之八十。Hulu 北京于 2018 和 2019 连续两年当选“大中华区最佳职场 ®”。
+
+<div style="text-align:center;font-weight:bold;margin-top: 35px;font-size: 25pt;"> Hulu 校园机会 </div>
+
+<div style="text-align:center;font-weight:small">
+<a href="https://sm.ms/image/Ls1cPJAB36gUztN" target="_blank"><img src="https://i.loli.net/2020/02/03/iSGMqmy8fTDJ5bz.png" ></a>
+</div>
+
+正如 Hulu 的产品是技术与娱乐的最佳结合,在 Hulu 工作,既能与一群志同道合的技术达人合作学习,又能享受充满乐趣的工作环境。Hulu 北京面向校园群体开放全年实习生招聘项目。欢迎关注 **Hulu 微信公众号** 了解更多关于 Hulu 的信息!
diff --git a/docs/intro/images/cf-tool3.gif b/docs/intro/images/cf-tool3.gif
new file mode 100644 (file)
index 0000000..15790ef
Binary files /dev/null and b/docs/intro/images/cf-tool3.gif differ
index b50c7b0..b90f01c 100644 (file)
@@ -32,7 +32,7 @@ LaTeX 基于 TeX(Donald Knuth 在 1978 年为数字化排版设计的排版系
 
 一个新的文档会被自动打开。
 
- $\rightarrow$ 进入 **Fomart** 菜单,选择 **Line Numbers** 。
+ $\rightarrow$ 进入 **Format** 菜单,选择 **Line Numbers** 。
 
 行号并不是要素,但它可以帮助你比较代码与屏幕信息,找到错误。
 
@@ -107,7 +107,7 @@ A sentence of text.
 要点笔记:
 
 -    `\today` 是插入当前时间的命令。你也可以输入一个不同的时间,比如 `\data{November 2013}` 。
--    **Article** 文档的正文会紧跟着标题之后在同一页上排版。 **Reports** 会将标题置为单独的一页。
+-    **article** 文档的正文会紧跟着标题之后在同一页上排版。 **report** 会将标题置为单独的一页。
 
 ### 章节
 
@@ -187,7 +187,7 @@ Here are my results.
 
 \title{My First Document}
 \author{My Name}
-\date{\rightarrowday}
+\date{\today}
 \maketitle
 
 \section{Introduction}
@@ -236,7 +236,7 @@ Here are my results. Referring to section \ref{sec1} on page \pageref{sec1}
 
 \title{My First Document}
 \author{My Name}
-\date{\rightarrowday}
+\date{\today}
 \maketitle
 
 \pagenumbering{roman}
index 6b441f8..f4756ac 100644 (file)
@@ -8,27 +8,31 @@ OI 竞赛中允许使用的语言包括 Pascal(NOI 将于 2020 年停止使用
 
 ### NOIP
 
-NOIP(National Olympiad in Informatics in Provinces)是全国青少年信息学奥林匹克联赛,顾名思义,是以省为单位排名评奖,对于大部分高校来说,获得提高组省一等奖可以用于获得自主招生资格。
+NOIP(National Olympiad in Informatics in Provinces)是全国青少年信息学奥林匹克联赛,顾名思义,是以省为单位排名评奖,截至 2019 年,对于大部分高校来说,获得提高组省一等奖可以用于获得自主招生资格。
 
-NOIP 分为初赛和复赛两个阶段。初赛会考察一些计算机基础知识和算法基础,复赛是上机考试,也分提高组和普及组(2018 年于上海试点入门组),时间上一般是 11 月的第二个周末,周六上午提高组 1 试 8:30-12:00(3.5h,共 3 题),下午 14:30-18:00 普及组(3.5h,共 4 题),周日上午提高组 2 试 8:30-12:00(3.5h,共 3 题)。全国使用同一套试卷,但是评奖规则是按照省内情况由 CCF(中国计算机学会)统一指定,并于赛后在 [NOI 官方网站](http://www.noi.cn) 上公布。各省的一等奖分数线略有不同。
+NOIP 分为初赛和复赛两个阶段。初赛会考察一些计算机基础知识和算法基础,复赛是上机考试,也分提高组和普及组(2018 年于上海试点入门组),时间上一般是 11 月的第二个周末,周六上午提高组一试 8:30-12:00(3.5 小时,共 3 题),下午 14:30-18:00 普及组(3.5 小时,共 4 题),周日上午提高组二试 8:30-12:00(3.5 小时,共 3 题)。全国使用同一套试卷,但是评奖规则是按照省内情况由 CCF(中国计算机学会)统一指定,并于赛后在 [NOI 官方网站](http://www.noi.cn) 上公布。各省的一等奖分数线略有不同。
 
-目前 NOIP 已经于 2019 被 CCF 取消
+NOIP 于 2019 年 8 月 16 日 [被 CCF 暂停](http://www.noi.cn/newsview.html?id=932&hash=72F731&type=1) ,于 2020 年 1 月 21 日 [被宣布恢复](http://www.noi.cn/newsview.html?id=1172&hash=AC7D99&type=1) 
 
 ### CSP J/S
 
 CSP (Certified Software Professional Junior/Senior) 是继 NOIP 在 2019 年被取消之后 CCF 开设的非专业级软件能力认证,面向全年龄段。
 具体赛制、时间基本同 NOIP 一致。在部分地区,CSP 2019 设有小学组。
 
-目前暂不清楚获得 CSP 认证对自主招生资格的获取是否有帮助。
+目前暂不清楚获得 CSP J/S 认证对自主招生资格的获取是否有帮助。
 
 ### 省选
 
 省队选拔赛是用于选拔各省参加全国赛的代表队,各个省队的名额有复杂的计算公式,一般和之前的成绩和参赛人数有关。省选由各个省自行决定,目前的趋势是很多省份选择联合命题。通常来讲,NOIP 分数需要在省选中占一定比例。根据规则,初中选手只能选拔成为 E 类选手,不参加 A、B 类选拔。A 类选手 5 人(4 男一女),其他选手根据给定名额和所得分数依次进入 B 队。一个学校参加 NOI 的名额不超过本省 A、B 名额总数的三分之一(四舍五入),得分最高且入选 A 队的女选手不占该比例。(简称 1/3 限制或 1/3 淘汰)
 
+自 2020 年起,NOI 省队选拔由 CCF 统一命题和评测,有能力命题的省可自行命题,但选拔方式需得到 CCF 的批准。
+
 ### NOI
 
 NOI(National Olympiad in Informatics)是全国信息学奥林匹克竞赛,一般在七月份举行,有现场赛和网络赛。现场赛选手分为五类,其中 A、B、C 类为正式选手,D、E 类选手为邀请赛选手。A、B 类对应省队的 A、B 类选手(其中 A 类在计算成绩时会有 5 分加分),C 类名义上是学校对 CCF 做出突出贡献后的奖励名额,D 类名义上是个人对 CCF 做出突出贡献后的奖励名额(基本为大额捐款),E 类选手为初中组选手,如果成绩超过分数线的话,只有成绩证明而没有奖牌(同等分数含金量要低一些)。正式选手前 50 名组成国家集训队,获得保送资格。网络赛报名形式上没有门槛。
 
+在国际平台上,为了与其他同样称作 NOI 的比赛区分,有时会被称作 CNOI。
+
 ### WC
 
 WC(Winter Camp)是全国青少年信息学奥林匹克竞赛冬令营,是每年冬天在当年 NOI 举办地进行的一项活动,内容包括若干天的培训和一天的考试。这项考试主要用于从国家集训队(50 人)选拔国家候选队(15 人),但是前一年 NOIP 取得较好成绩的选手也可以参加(不参与选拔)。
@@ -67,15 +71,17 @@ NOIP、NOI、省选都是 OI 赛制。
 目前国内比赛也在逐渐向 IOI 赛制靠拢。
 IOI 赛制可以赛时任意提交,可以即时查看评测结果,APIO、IOI 都是 IOI 赛制。
 
-### ACM/ICPC 赛制
+### ICPC 赛制
 
-在 ACM/ICPC 比赛中一般是三个人使用一台机器,每个题目只有在所有数据点全部正确后才能得到分数。比赛过程中可以有多次提交机会,实时评测并返回结果。比赛排名根据做题数和罚时来评判,罚时是通过题目的用时之和加上错误提交次数乘以一个系数。在 ACM 相关赛事中,选手允许带纸质资料。
+在 ICPC 比赛中一般是三个人使用一台机器,每个题目只有在所有数据点全部正确后才能得到分数。比赛过程中可以有多次提交机会,实时评测并返回结果。比赛排名根据做题数和罚时来评判,罚时是通过题目的用时之和加上错误提交次数乘以一个系数。在 ICPC 相关赛事中,选手允许带一定量的纸质资料。
 
 参见 [ICPC/CCPC 赛事与赛制](./icpc.md) 。
 
 ### Codeforces (CF) 赛制
 
- [Codeforces](https://codeforces.com) 是一个在线评测系统,定期会举办比赛。它的比赛特点是在比赛过程中只测试一部分数据(pretests),而在比赛结束后返回完整的所有测试点的测试结果(system tests)。比赛时可以多次提交,允许 hack 别人的代码(此处 hack 的意思是提交一个测试数据,使得别人的代码无法给出正确答案)。当然,如果想要 hack,必须要锁定自己的代码(换言之,比赛时无法重新提交该题)。
+ [Codeforces](https://codeforces.com) 是一个在线评测系统,定期会举办比赛。它的比赛特点是在比赛过程中只测试一部分数据(pretests),而在比赛结束后返回完整的所有测试点的测试结果(system tests)。比赛时可以多次提交,允许 hack 别人的代码(此处 hack 的意思是提交一个测试数据,使得别人的代码无法给出正确答案)。当然,如果想要 hack,必须要锁定自己的代码(换言之,比赛时无法重新提交该题)。Hack 时不允许将选手程序拷贝到本地进行测试(你看到的会是代码转换成图片的版本)。
+
+Codeforces 同时提供另外一种赛制,称作扩展 ICPC(extended ICPC)。在这一赛制中,在比赛过程中会测试全部数据,但比赛结束以后会有 12 小时的全网 Hack 时间。Hack 时允许将选手程序拷贝到本地进行测试。
 
 ## 其他国家和地区的 OI 竞赛
 
index d471a67..733154c 100644 (file)
@@ -105,3 +105,23 @@ cf-tool 是 Codeforces 的命令行界面的跨平台(支持 Windows、Linux
 -   计算一场比赛的 Rating 预测。
 
 大家可以自行尝试一下。
+
+## Competitive companion
+
+网站: <https://github.com/jmerle/competitive-companion> 
+
+功能介绍:
+
+-   这个工具是一个浏览器插件 用来解析网页里面的测例数据
+-   支持解析几乎所有的主流 oj 平台(比如 codeforces atcoder)
+
+推荐理由:使用这个插件后 再也不用手动复制任何的测例数据
+
+使用方法:
+
+1.  在谷歌或者火狐浏览器上安装插件 该工具会将解析到的测例数据以 JSON 格式的形式发到指定的端口
+2.  在本地安装任何可以从端口监听读取数据的工具即可 可参考 <https://github.com/jmerle/competitive-companion-example> 
+
+图片演示:
+
+![演示](images/cf-tool3.gif)
index ccc28e9..732ea1c 100644 (file)
@@ -10,13 +10,13 @@ author: Konano, Enter-tainer, JulieSigtuna, GldHkkowo
 -    [BZOJ](https://www.lydsy.com/JudgeOnline/) 因原属衡阳八中而得简称,汇聚多种习题和真题,题目质量相对较高,但可能需要联系邮箱。  
     BZOJ 上有大量题目只有付费用户才能提交。2018 年 BZOJ 测试数据泄露,催生了 DarkBZOJ。
 -    [Comet OJ](https://www.cometoj.com) 始于 2018 年,旨在为广大算法爱好者提供一个竞技、练习、交流的平台,经常举办原创性的高质量比赛,有丰富的题库。
--    [CodeVS](http://www.codevs.cn/) 面向 OI 选手的过气 OJ。
+    <!-- - [CodeVS](http://www.codevs.cn/) 面向 OI 选手的过气 OJ。 -->
 -    [FZUOJ](http://acm.fzu.edu.cn/) 始于 2008 年,福州大学在线评测系统。
 -    [HDU Online Judge](http://acm.hdu.edu.cn/) 始于 2005 年,杭州电子科技大学在线评测系统,有多校训练的题目。
 -    [hihoCoder](https://hihocoder.com/) 始于 2012 年,面向企业招聘,有些题目来自于每周一题,涉及知识点的学习。(登录后方可查看题面)
 -    [计蒜客](https://www.jisuanke.com/) 北京矩道优达网络科技有限公司旗下的核心产品,提供按知识点和难度筛选的信息学题库和 ICPC 题库。
 -    [Judge Duck Online](https://duck.ac/) 基于 [松松松](https://github.com/wangyisong1996) 开发的开源项目 [JudgeDuck](https://github.com/JudgeDuck) ,可以将评测程序的运行时间精确到 $\mu s$ 。(题目较少)
--    [JoyOI](http://www.joyoi.cn/) 原 Tyvj, [项目开源](https://github.com/joyoi) 。
+    <!--  - [JoyOI](http://www.joyoi.cn/) 原 Tyvj, [项目开源](https://github.com/joyoi) 。-->
 -    [LibreOJ](https://loj.ac/) 始于 2017 年。
     目前由 [Menci](https://github.com/Menci) 维护。
     Libre 取自由之意,基于开源项目 [SYZOJ](https://github.com/syzoj/syzoj) 。
@@ -53,9 +53,9 @@ author: Konano, Enter-tainer, JulieSigtuna, GldHkkowo
 -    [TopCoder](https://www.topcoder.com/) 始于 2001 年,其 [竞技编程社区](https://www.topcoder.com/community/competitive-programming/) 有很多比赛;目前主营业务是技术众包。
 -    [TimusOJ](http://acm.timus.ru/) 始于 2000 年,由 Ural Federal University 开发,拥有俄罗斯最大的在线评测题库,题目主要来自乌拉尔联邦大学校赛、乌拉尔锦标赛、ICPC 乌拉尔区域赛、以及 Petrozavodsk 训练营。
 -   Online Judge(前 [UVaOJ](https://uva.onlinejudge.org/) )始于 1995 年,国际成名最早的 OJ,创始人是西班牙 University of Valladolid (UVa) 的 Miguel Ángel Revilla 教授;由于 [Revilla 教授于 2018 年不幸离世](https://www.elnortedecastilla.es/valladolid/muere-profesor-miguel-20180402225739-nt.html) ,且 Valladolid 大学终止维护,UVaOJ 自 2019 年 7 月起更名为 Online Judge; [刘汝佳强烈安利](http://product.dangdang.com/20637355.html) 。
--    [Yandex](https://contest.yandex.ru/) 存档了近几年的全俄罗斯信息学奥赛
+-    [Yandex](https://contest.yandex.ru/) 存档了近几年的全俄罗斯信息学奥赛
 
-## 教程
+## 教程资料
 
 -    [OI Wiki](https://oi-wiki.org) 
 -    [Codeforces 上网友整理的一份教程合集](http://codeforces.com/blog/entry/57282) 
@@ -66,6 +66,9 @@ author: Konano, Enter-tainer, JulieSigtuna, GldHkkowo
 -    [如何为 ACM-ICPC 做准备?- geeksforgeeks](https://www.geeksforgeeks.org/how-to-prepare-for-acm-icpc/) 
 -    [Topcoder 整理的教程](https://www.topcoder.com/community/competitive-programming/tutorials/) 
 -    [校招面试指南](https://github.com/jwasham/coding-interview-university) 
+-    [由 hzwer 收集整理自互联网的课件](https://github.com/hzwer/sharePPT) 
+-    [Trinkle23897 的课件](https://github.com/Trinkle23897/oi_slides) 
+-    [huzecong 的课件](https://github.com/huzecong/oi-slides) 
 
 ## 书籍
 
index 8e510df..0d5a81b 100644 (file)
@@ -12,13 +12,27 @@ disqus:
 
 * * *
 
-|       id      | amount |    date   |
-| :-----------: | :----: | :-------: |
-|     匿名捐赠者     |  30 元  |  2019.8.8 |
-| Billchenchina |  100 元 |  2019.8.7 |
-|     sshwy     |  50 元  |  2019.8.4 |
-|     匿名捐赠者     |  10 元  |  2018.9.9 |
-|     匿名捐赠者     |  20 元  | 2018.8.31 |
-|    Xeonacid   |  30 元  | 2018.8.30 |
-|     匿名捐赠者     |  240 元 | 2018.8.29 |
-|     Anguei    |   5 元  | 2018.8.29 |
+|       id      |  amount |    date    |
+| :-----------: | :-----: | :--------: |
+|       陌陌      |   10 元  |  2020.2.6  |
+|     匿名捐赠者     |   10 元  |  2020.2.5  |
+|     Yisin     |   10 元  |  2020.2.4  |
+|    GinRyan    |   50 元  | 2019.11.30 |
+|    JuicyMio   |   10 元  | 2019.11.30 |
+|     匿名捐赠者     |   10 元  | 2019.11.14 |
+|    QQ 联系 12   |   5 元   | 2019.10.28 |
+|     匿名捐赠者     |   5 元   | 2019.10.27 |
+|     增肥中的小肥    |   50 元  | 2019.10.24 |
+|    ianahao    |   10 元  | 2019.10.12 |
+|     Sundy     |   10 元  | 2019.10.11 |
+|     三鸽最可爱     | 23.33 元 |  2019.8.17 |
+|     Fburan    | 10.24 元 |  2019.8.17 |
+|     匿名捐赠者     |   30 元  |  2019.8.8  |
+| Billchenchina |  100 元  |  2019.8.7  |
+|   贷款捐头的匿名入土   |   30 元  |  2019.8.4  |
+|     sshwy     |   50 元  |  2019.8.4  |
+|     匿名捐赠者     |   10 元  |  2018.9.9  |
+|     匿名捐赠者     |   20 元  |  2018.8.31 |
+|    Xeonacid   |   30 元  |  2018.8.30 |
+|     匿名捐赠者     |  240 元  |  2018.8.29 |
+|     Anguei    |   5 元   |  2018.8.29 |
index ee4eaa7..5f9f236 100644 (file)
@@ -2,7 +2,7 @@
 
 ## 定义数组
 
-数组的声明形如 `a[d]` ,其中, `a` 是数组的名字, `d` 是数组中元素的个数。在编译时, `d` 应该是已知的,也就是说, `d` 应该是一个常量表达式。
+数组的声明形如 `a[d]` ,其中, `a` 是数组的名字, `d` 是数组中元素的个数。在编译时, `d` 应该是已知的,也就是说, `d` 应该是一个整型的常量表达式。
 
 ```cpp
 unsigned int d1 = 42;
@@ -11,8 +11,6 @@ int arr1[d1];  // 错误:d1 不是常量表达式
 int arr2[d2];  // 正确:arr2 是一个长度为 42 的数组
 ```
 
-### 不允许赋值
-
 不能将一个数组直接赋值给另一个数组:
 
 ```cpp
@@ -21,30 +19,57 @@ int arr2 = arr1;  // 错误
 arr2 = arr1;      // 错误
 ```
 
+应该尽量将较大的数组定义为全局变量。因为局部变量会被创建在栈区中,过大(大于栈的大小)的数组会爆栈,进而导致 RE。如果将数组声明在全局作用域中,就会在静态区中创建数组。
+
 ## 访问数组元素
 
-可以通过下标运算符来访问数组内元素的值,数组的索引从 0 开始。以一个包含 10 个元素的数组为例,它的索引为 0 到 9,而非 1 到 10。但在 OI 中,为了使用方便,我们通常会将数组开大一点,不使用数组的首元素,从下标 1 开始访问数组元素。
+可以通过下标运算符 `[]` 来访问数组内元素,数组的索引(即方括号中的值)从 0 开始。以一个包含 10 个元素的数组为例,它的索引为 0 到 9,而非 1 到 10。但在 OI 中,为了使用方便,我们通常会将数组开大一点,不使用数组的第一个元素,从下标 1 开始访问数组元素。
 
 例 1:从标准输入中读取一个整数 $n$ ,再读取 $n$ 个数,存入数组中。其中, $n\leq 1000$ 。
 
 ```cpp
-int n;
-int arr[1001];  // 数组 arr 的下标范围是 [0, 1000]
-cin >> n;
-for (int i = 1; i <= n; ++i) cin >> arr[i];
+#include <iostream>
+using namespace std;
+
+int arr[1001];  // 数组 arr 的下标范围是 [0, 1001)
+
+int main() {
+  int n;
+  cin >> n;
+  for (int i = 1; i <= n; ++i) {
+    cin >> arr[i];
+  }
+}
 ```
 
 例 2:(接例 1)求和数组 `arr` 中的元素,并输出和。满足数组中所有元素的和小于等于 $2^{31} - 1$ 
 
 ```cpp
-int sum = 0;
-for (int i = 1; i <= n; ++i) sum += arr[i];
-cout << sum << endl;
+#include <iostream>
+using namespace std;
+
+int arr[1001];
+
+int main() {
+  int n;
+  cin >> n;
+  for (int i = 1; i <= n; ++i) {
+    cin >> arr[i];
+  }
+
+  int sum = 0;
+  for (int i = 1; i <= n; ++i) {
+    sum += i;
+  }
+
+  printf("%d\n", sum);
+  return 0;
+}
 ```
 
 ### 越界访问下标
 
-数组的下标 $\mathit{idx}$ 应当满足 $0\leq \mathit{idx}< \mathit{size}$ ,如果下标越界,则会产生不可预料的后果,如段错误(Segmentation Fault)。
+数组的下标 $\mathit{idx}$ 应当满足 $0\leq \mathit{idx}< \mathit{size}$ ,如果下标越界,则会产生不可预料的后果,如段错误(Segmentation Fault),或者修改预期以外的变量
 
 ## 多维数组
 
@@ -56,7 +81,7 @@ int arr[3][4];  // 一个长度为 3 的数组,它的元素是「元素为 int
 arr[2][1] = 1;  // 访问二维数组
 ```
 
-我们经常使用嵌套的 `for` 循环来处理二维数组。
+我们经常使用嵌套的 for 循环来处理二维数组。
 
 例:从标准输入中读取两个数 $n$ 和 $m$ ,分别表示黑白图片的高与宽,满足 $n,m\leq 1000$ 。对于接下来的 $n$ 行数据,每行有用空格分隔开的 $m$ 个数,代表这一位置的亮度值。现在我们读取这张图片,并将其存入二维数组中。
 
index 51e4da0..87925ce 100644 (file)
@@ -13,24 +13,24 @@ int main() {
 ```
 
 ??? note "什么是 include?"
-     `#include` 其实是一个预处理命令,意思为将一个文件“放”在这条语句处。也就是说,在编译时,编译器会“复制” `iostream` 头文件中的内容,“粘贴”到 `#include <iostream>` 这条语句处。这样,你就可以使用 `iostream` 中提供的 `std::cin` 、 `std::cout` 、 `std::endl` 等对象了。
+     `#include` 其实是一个预处理命令,意思为将一个文件“放”在这条语句处,被“放”的文件被称为头文件。也就是说,在编译时,编译器会“复制”头文件 `iostream` 中的内容,“粘贴”到 `#include <iostream>` 这条语句处。这样,你就可以使用 `iostream` 中提供的 `std::cin` 、 `std::cout` 、 `std::endl` 等对象了。
 
-    如果你学过 C 语言,你会发现 C++ 中的头文件一般都不带 `.h` 后缀,而那些 C 语言中的头文件 `xx.h` 都变成了 `cxx` ,如 `stdio.h` 变成了 `cstdio` 
-
-    一般来说,应当根据你需要使用的 C++ 内置的函数、对象来确定你要 `#include` 哪些头文件。但如果你 `#include` 了多余的头文件,也几乎不会造成什么影响
+    如果你学过 C 语言,你会发现目前我们接触的 C++ 中的头文件一般都不带 `.h` 后缀,而那些 C 语言中的头文件 `xx.h` 都变成了 `cxx` ,如 `stdio.h` 变成了 `cstdio` 。因为 C++ 为了和 C 保持兼容,都直接使用了 C 语言中的头文件,为了区分 C++ 的头文件和 C 的头文件,使用了 `c` 前缀
+      
+    一般来说,应当根据你需要编写的 C++ 程序的需要来确定你要 `#include` 哪些头文件。但如果你 `#include` 了多余的头文件,只会增加编译时间,几乎不会对运行时间造成影响。目前我们只接触到了 `iostream` 和 `cstdio` 两个头文件,如果你只需要 `scanf` 和 `printf`,就可以不用 `#include <iostream>` 
 
     可以 `#include` 自己写的头文件吗?答案是,可以。
 
     你可以自己写一个头文件,如: `myheader.h` 。然后,将其放到和你的代码相同的目录里,再 `#include "myheader.h"` 即可。需要注意的是,自定义的头文件需要使用引号而非尖括号。当然,你也可以使用编译命令 `-I <header_file_path>` 来告诉编译器在哪找头文件,就不需要将头文件放到和代码相同的目录里了。
 
-??? note "什么是 main 函数?"
-    可以理解为程序运行时就会执行 `main` 函数中的代码。
+??? note "什么是 `main()` ?"
+    可以理解为程序运行时就会执行 `main()` 中的代码。
 
-    实际上, `main` 函数是由系统或外部程序调用的。如,你在 cmd 中调用了你的程序,也就是调用了你程序中的 `main` 函数(在此之前先完成了全局变量的构造)。
+    实际上, `main` 函数是由系统或外部程序调用的。如,你在命令行中调用了你的程序,也就是调用了你程序中的 `main` 函数(在此之前先完成了全局 [变量](./var.md) 的构造)。
 
-    æ\9c\80å\90\8eç\9a\84 `return 0;` è¡¨ç¤ºç¨\8båº\8fè¿\90è¡\8cæ\88\90å\8a\9fã\80\82é»\98认æ\83\85å\86µä¸\8bï¼\8cç¨\8båº\8fç»\93æ\9d\9fæ\97¶è¿\94å\9b\9e 0 è¡¨ç¤ºä¸\80å\88\87正常ï¼\8cå\90¦å\88\99表示é\94\99误代ç \81ã\80\82è¿\99个å\80¼è¿\94å\9b\9eç»\99è°\81å\91¢ï¼\9få\85¶å®\9eå°±æ\98¯è°\83ç\94¨ä½ å\86\99ç\9a\84ç¨\8båº\8fç\9a\84ç³»ç»\9fæ\88\96å¤\96é\83¨ç¨\8båº\8fï¼\8cå®\83ä¼\9aå\9c¨ä½ ç\9a\84ç¨\8båº\8fç»\93æ\9d\9fæ\97¶æ\8e¥æ\94¶å\88°è¿\99个è¿\94å\9b\9eå\80¼
+    æ\9c\80å\90\8eç\9a\84 `return 0;` è¡¨ç¤ºç¨\8båº\8fè¿\90è¡\8cæ\88\90å\8a\9fã\80\82é»\98认æ\83\85å\86µä¸\8bï¼\8cç¨\8båº\8fç»\93æ\9d\9fæ\97¶è¿\94å\9b\9e 0 è¡¨ç¤ºä¸\80å\88\87正常ï¼\8cå\90¦å\88\99è¿\94å\9b\9eå\80¼è¡¨ç¤ºé\94\99误代ç \81ã\80\82è¿\99个å\80¼è¿\94å\9b\9eç»\99è°\81å\91¢ï¼\9få\85¶å®\9eå°±æ\98¯è°\83ç\94¨ä½ å\86\99ç\9a\84ç¨\8båº\8fç\9a\84ç³»ç»\9fæ\88\96å¤\96é\83¨ç¨\8båº\8fï¼\8cå®\83ä¼\9aå\9c¨ä½ ç\9a\84ç¨\8båº\8fç»\93æ\9d\9fæ\97¶æ\8e¥æ\94¶å\88°è¿\99个è¿\94å\9b\9eå\80¼ã\80\82å¦\82æ\9e\9cä¸\8då\86\99 `return` è¯­å\8f¥ç\9a\84è¯\9dï¼\8cç¨\8båº\8f正常ç»\93æ\9d\9fé»\98认è¿\94å\9b\9eå\80¼ä¹\9fæ\98¯ 0
 
-    在 OI 中,程序的返回值不为 0 会导致运行时错误(RE)。
+    在 C 或 C++ 中,程序的返回值不为 0 会导致运行时错误(RE)。
 
 ## 注释
 
@@ -48,11 +48,11 @@ int main() {
 
 在工程开发中,注释可以便于日后维护、他人阅读。
 
\9c¨ OI ä¸­ï¼\8cå¾\88å¤\9a人é\83½å¾\88å°\91å\86\99注é\87\8aï¼\8cä½\86注é\87\8aå\8f¯ä»¥ä¾¿äº\8eæ\97¥å\90\8eå¤\8dä¹ ï¼\8cè\80\8cä¸\94ï¼\8cå¦\82æ\9e\9cè¦\81å\86\99é¢\98解ã\80\81æ\95\99ç¨\8bç\9a\84è¯\9dï¼\8cé\80\82é\87\8fç\9a\84注é\87\8aå\8f¯ä»¥ä¾¿äº\8e读è\80\85é\98\85读
\9c¨ OI ä¸­ï¼\8cå¾\88å°\91æ\9c\89人å\86\99许å¤\9a注é\87\8aï¼\8cä½\86注é\87\8aå\8f¯ä»¥ä¾¿äº\8eå\9c¨å\86\99代ç \81ç\9a\84æ\97¶å\80\99ç\90\86æ¸\85æ\80\9dè·¯ï¼\8cæ\88\96è\80\85便äº\8eæ\97¥å\90\8eå¤\8dä¹ ã\80\82è\80\8cä¸\94ï¼\8cå¦\82æ\9e\9cè¦\81å\86\99é¢\98解ã\80\81æ\95\99ç¨\8bç\9a\84è¯\9dï¼\8cé\80\82é\87\8fç\9a\84注é\87\8aå\8f¯ä»¥ä¾¿äº\8e读è\80\85é\98\85读ï¼\8cç\90\86解代ç \81ç\9a\84æ\84\8få\9b¾
 
 ## 输入与输出
 
-### cin 与 cout
+###  `cin` 与 `cout` 
 
 ```cpp
 #include <iostream>
@@ -65,14 +65,17 @@ int main() {
 }
 ```
 
-??? note "什么是 std?"
-     `std` 是 C++ 标准库所使用的 **命名空间** 。使用命名空间是为了避免重名。
+???+note "什么是变量?"
+    可以参考 [变量](./var.md) 页面。
+
+???+note " 什么是 `std` ?" 
+    std 是 C++ 标准库所使用的 **命名空间** 。使用命名空间是为了避免重名。
 
     关于命名空间的详细知识,可以参考 [命名空间](./namespace.md) 页面。
 
-### scanf 与 printf
+###  `scanf` 与 `printf` 
 
- `scanf` 与 `printf` 其实是 C 语言中的函数。大多数情况下,它们的速度比 `cin` 和 `cout` 更快,并且能够方便地支持格式控制
+ `scanf` 与 `printf` 其实是 C 语言提供的函数。大多数情况下,它们的速度比 `cin` 和 `cout` 更快,并且能够方便地控制输入输出格式
 
 ```cpp
 #include <cstdio>
@@ -96,20 +99,25 @@ int main() {
 5.   `%u` 表示无符号整型  ( `unsigned int` )。
 6.   `%llu` 表示无符号长整型 ( `unsigned long long` ),也可能是 `%I64u` 。
 
-特殊地,还有一些控制格式的方式
+除了类型标识符以外,还有一些控制格式的方式。许多都不常用,选取两个常用的列举如下
 
-1.   `%1d` 表示长度为 1 的整型。在读入时,即使没有空格也可以逐位读入数字。在输出时,若指定的长度大于数字的位数,就会在数字前用空格填充。
+1.   `%1d` 表示长度为 1 的整型。在读入时,即使没有空格也可以逐位读入数字。在输出时,若指定的长度大于数字的位数,就会在数字前用空格填充。若指定的长度小于数字的位数,就没有效果。
 2.   `%.6lf` ,用于输出,保留六位小数。
 
-??? note "为什么 scanf 中有 & 运算符?"
-    在这里, `&` 实际上是取址运算符,返回的是变量在内存中的地址。而 scanf 接收的参数就是变量的地址。
+这两种运算符的相应地方都可以填入其他数字,例如 `%.3lf` 表示保留三位小数。
+
+??? note "“双精度浮点数”,“长整型”是什么"
+    这些表示变量的类型。和上面一样,会留到 [变量](./var.md) 中统一讲解。
 
-??? note "什么是 \n?"
+??? note "为什么 `scanf` 中有 `&` 运算符?"
+    在这里, `&` 实际上是取址运算符,返回的是变量在内存中的地址。而 scanf 接收的参数就是变量的地址。具体可能要在 [指针](./pointer.md) 才能完全清楚地说明,现在只需要记下来就好了。
+
+??? note " 什么是 `\n` ?" 
      `\n` 是一种 **转义字符** ,表示换行。
 
-    转义字符用来表示一些无法轻易输入的字符,如由于字符串字面值无法换行而无法输入的换行符,由于表示字符串字面值的开头结尾而无法输入的引号,由于表示转义字符而无法输入的反斜杠。
+    转义字符用来表示一些无法直接输入的字符,如由于字符串字面量中无法换行而无法直接输入的换行符,由于有特殊含义而无法输入的引号,由于表示转义字符而无法输入的反斜杠。
 
-    常用的转义字符有:
+    常用的转义字符有:
 
     1. `\t` 表示制表符。
 
@@ -119,7 +127,14 @@ int main() {
 
     4. `\0` 表示空字符,用来表示 C 风格字符串的结尾。
 
-    5. `\r` 表示回车。Linux 中换行符为 `\n` ,Windows 中换行符为 `\r\n` 。在 OI 中,如果输出需要换行,使用 `\n` 即可。但读入时,如果需要读入换行符,使用逐字符读入可能造成一些问题,需要注意。
+    5. `\r` 表示回车。Linux 中换行符为 `\n` ,Windows 中换行符为 `\r\n` 。在 OI 中,如果输出需要换行,使用 `\n` 即可。但读入时,如果使用逐字符读入,可能会由于换行符造成一些问题,需要注意。例如,`gets` 将 `\n` 作为字符串结尾,这时候如果换行符是 `\r\n`,`\r` 就会留在字符串结尾。
+
+    6. 特殊地, `%%` 表示 `%` ,只能用在 `printf` 或 `scanf` 中,在其他字符串字面量中只需要简单使用 `%` 就好了。
+
+    ??? note "什么是字面量?"
+        “字面量”是在代码里直接作为一个值的程序段,例如 `3` 就是一个 `int` 字面量,`'c'` 就是一个 char 字面量。我们上面写的程序中的 `"hello world"` 也是一个字符串字面量。
+
+        不加解释、毫无来由的字面量又被称为“魔术数”(magic number),如果代码需要被人阅读的话,这是一种十分不被推荐的行为。
 
 ## 一些扩展内容
 
@@ -127,7 +142,7 @@ int main() {
 
 在 C++ 中,所有空白字符(空格、制表符、换行),多个或是单个,都被视作是一样的。(当然,引号中视作字符串的一部分的不算。)
 
-因此,你可以自由地使用任何代码风格(除了行内注释、字符串字面与预处理命令必须在单行内),例如:
+因此,你可以自由地使用任何代码风格(除了行内注释、字符串字面与预处理命令必须在单行内),例如:
 
 ```cpp
 /* clang-format off */
@@ -150,34 +165,33 @@ int/**/x, y;  std::cin
 
 当然,这么做是不被推荐的。
 
-ä¸\80ç§\8dä¸\8dé\82£ä¹\88ä¸\91é\99\8bè\80\8c与 **OI Wiki** 要求的码风不同的代码风格:
+ä¸\80ç§\8dä¹\9f被广æ³\9b使ç\94¨ä½\86与 **OI Wiki** 要求的码风不同的代码风格:
 
 ```cpp
 /* clang-format off */
 
 #include <iostream>
 
-using namespace std; // 其实这么做是不被推荐的
-
 int main()
 {
     int x, y;
 
-    cin >> x >> y;
-    cout << y << endl << x;
+    std::cin >> x >> y;
+    std::cout << y << std::endl << x;
 
     return 0;
 }
 ```
 
-### define 命令
+###  `#define` 命令
 
  `#define` 是一种预处理命令,用于定义宏,本质上是文本替换。例如:
 
 ```cpp
 #include <iostream>
 #define n 233
-// n 不是变量,而是编译器会将代码中所有 "n" 文本替换为 "233"
+// n 不是变量,而是编译器会将代码中所有 n 文本替换为 233,但是作为标识符一部分的
+// n 的就不会被替换,如 fn 不会被替换成 f233,同样,字符串内的也不会被替换
 
 int main() {
   std::cout << n;  // 输出 233
@@ -185,12 +199,32 @@ int main() {
 }
 ```
 
+??? note "什么是标识符?"
+    标识符就是可以用作变量名的一组字符。例如, `abcd` 和 `abc1` 都是合法的标识符,而 `1a` 和 `c+b` 都不是合法的标识符。
+
+    标识符由英文字母、下划线开头,中间只允许出现英文字母、下划线和数字。值得注意的是,关键字(如 `int`, `for`, `if`)不能用作标识符。
+
+??? note "什么是预处理命令?"
+    预处理命令就是预处理器所接受的命令,用于对代码进行初步的变换,包含 `#include` 和 `#define` 等。
+
 宏可以带参数,带参数的宏可以像函数一样使用:
 
 ```cpp
 #include <iostream>
+#define sum(x, y) ((x) + (y))
+#define square(x) ((x) * (x))
+
+int main() {
+  std::cout << sum(1, 2) << ' ' << 2 * sum(3, 5) << std::endl;  // 输出 3 16
+}
+```
+
+但是带参数的宏和函数有区别。因为宏是文本替换,所以会引发许多问题。如:
+
+```cpp
+#include <iostream>
 #define sum(x, y) x + y
-// 这里应当为 #define sum(x, y) (x + y)
+// 这里应当为 #define sum(x, y) ((x) + (y))
 #define square(x) ((x) * (x))
 
 int main() {
@@ -198,8 +232,8 @@ int main() {
   // 输出为 3 11,因为 #define 是文本替换,后面的语句被替换为了 2 * 3 + 5
   int i = 1;
   std::cout << square(++i) << ' ' << i;
-  // 输出为 9 3 或 6 3,因为 ++i 被执行了两遍
-  // è\80\8cå\90\8cä¸\80个语å\8f¥ä¸­å\87ºç\8e°å¤\9a个 ++ æ\98¯æ\9cªå®\9aä¹\89è¡\8c为
+  // 输出未定义,因为 ++i 被执行了两遍
+  // è\80\8cå\90\8cä¸\80个语å\8f¥ä¸­å¤\9a次修æ\94¹å\90\8cä¸\80个å\8f\98é\87\8fæ\98¯æ\9cªå®\9aä¹\89è¡\8c为ï¼\88æ\9c\89ä¾\8bå¤\96ï¼\89
 }
 ```
 
@@ -207,5 +241,5 @@ int main() {
 
 但是,在 OI 中, `#define` 依然有用武之处(依然是不被推荐的,会降低代码的规范性):
 
-1.   `#define int long long` + `signed main()` 。通常用于避免忘记开 long long 导致的错误,或是调试时排除忘开 long long 导致错误的可能性。(也可能导致增大常数甚至 MLE。
-2.   `#define For(i, l, r) for (int i = l; i <= r; ++i)` 、 `#define push_back pb` 、 `#define mid ((l + r) / 2)` ,用于减短代码长度。
+1.   `#define int long long` + `signed main()` 。通常用于避免忘记开 long long 导致的错误,或是调试时排除忘开 long long 导致错误的可能性。(也可能导致增大常数甚至 TLE,或者因为爆空间而 MLE
+2.   `#define For(i, l, r) for (int i = (l); i <= (r); ++i)` 、 `#define pb push_back` 、 `#define mid ((l + r) / 2)` ,用于减短代码长度。
index 3d9e75c..582501f 100644 (file)
@@ -1,4 +1,4 @@
-一个程序默认是按照代码的顺序执行下来的,有时我们需要选择性的执行某些语句,这时候就需要分支的功能来实现。对于分支的选择应该使用恰当的语句,这样可以提升程序效率。
+一个程序默认是按照代码的顺序执行下来的,有时我们需要选择性的执行某些语句,这时候就需要分支的功能来实现。选择合适的分支语句可以提高程序的效率。
 
 ## if 语句
 
@@ -7,63 +7,76 @@
 以下是基本 if 语句的结构。
 
 ```cpp
-if (表达式) {
-  语句;
+if (条件) {
+  主体;
 }
 ```
 
-if 语句通过对表达式进行判断,若表达式为真(非 0)则执行语句,否则不执行。
+if 语句通过对条件进行求值,若结果为真(非 0),执行语句,否则不执行。
+
+如果主体中只有单个语句的话,花括号可以省略。
 
 ### if...else 语句
 
 ```cpp
-if (表达式) {
-  语句;
+if (条件) {
+  主体1;
 } else {
-  语句;
+  主体2;
 }
 ```
 
-if...else 语句和 if 语句类似,else 不需要再写判断表达式。两者区别在于当 if 语句的判断表达式为假时,直接执行 else 里的语句
+if...else 语句和 if 语句类似,else 不需要再写条件。当 if 语句的条件满足时会执行 if 里的语句,if 语句的条件不满足时会执行 else 里的语句。同样,当主体只有一条语句时,可以省略花括号
 
 ### else if 语句
 
 ```cpp
-if (表达式1) {
-  语句1;
-} else if (表达式2) {
-  语句2;
-} else if (表达式3) {
-  语句3;
+if (条件1) {
+  主体1;
+} else if (条件2) {
+  主体2;
+} else if (条件3) {
+  主体3;
 } else {
-  语句4;
+  主体4;
 }
 ```
 
-else if 语句是 if 和 else 的组合,对多个条件进行判断并选择不同的语句分支。在最后一条的 else 语句则不需要再写判断表达式。
+else if 语句是 if 和 else 的组合,对多个条件进行判断并选择不同的语句分支。在最后一条的 else 语句不需要再写条件。例如,若条件 1 为真,执行主体 1,条件 3 为真而条件 1 和条件 2 都为假,执行主体 3,所有的条件都为假才执行主体 4。
+
+实际上,这一个语句相当于第一个 if 的 else 分句只有一个 if 语句,就将花括号省略之后放在一起了。如果条件相互之间是并列关系,这样写可以让代码的逻辑更清晰。
+
+在逻辑上,大约相当于这一段话:
+
+> 解一元二次方程的时候,方程的根与判别式的关系:
+>
+> -   如果 ( $\Delta<0$ )
+>     方程无解;
+> -   否则,如果 ( $\Delta=0$ )
+>     方程有两个相同的实数解;
+> -   否则
+>     方程有两个不相同的实数解;
 
 ## switch 语句
 
 ```cpp
-switch (整数类型的表达式) {
-  case 常量表达式1: {
-    语句1;
-  }
-  case 常量表达式2: {
-    语句2;
-  }
-  default: { 语句3; }
+switch (选择句) {
+  case 标签1:
+    主体1;
+  case 标签2:
+    主体2;
+  default:
+    主体3;
 }
 ```
 
-switch 语句的括号中的表达式就是要判断的条件必须是整数类型的表达式(如 int/char/bool 以及它们的修饰类型),case 检验条件是否等于该表达式,若等于则执行其后的语句直到 switch 块末尾;若不等于所有 case 的表达式则执行 default 之后的语句。如果不需要默认执行的操作,那么 switch 中也可以没有 default 语句。
+switch 语句执行时,先求出选择句的值,然后根据选择句的值选择相应的标签,从标签处开始执行。其中,选择句必须是一个整数类型表达式,而标签都必须是整数类型的常量。例如:
 
 ```cpp
 int i = 1;  //这里的 i 的数据类型是整型 ,满足整数类型的表达式的要求
 switch (i) {
-  case 1: {
+  case 1:
     cout << "OI WIKI" << endl;
-  }
 }
 ```
 
@@ -72,43 +85,72 @@ char i = 'A';
 // 这里的 i 的数据类型是字符型 ,但 char
 // 也是属于整数的类型,满足整数类型的表达式的要求
 switch (i) {
-  case 'A': {
+  case 'A':
     cout << "OI WIKI" << endl;
-  }
 }
 ```
 
-switch 语句中还要根据需求加入 break 语句进行中断,否则检验条件满足后接下来的所有 case 里的语句和 default 里的语句都会被运行。具体例子可看下面的示例。
+switch 语句中还要根据需求加入 break 语句进行中断,否则在对应的 case 被选择之后接下来的所有 case 里的语句和 default 里的语句都会被运行。具体例子可看下面的示例。
 
 ```cpp
 char i = 'B';
 switch (i) {
-  case 'A': {
+  case 'A':
     cout << "OI" << endl;
     break;
-  }
-  case 'B': {
+
+  case 'B':
     cout << "WIKI" << endl;
-  }
-  default: { cout << "Hello World" << endl; }
+
+  default:
+    cout << "Hello World" << endl;
 }
 ```
 
-以上代码运行后输出的结果为 WIKI 和 Hello World,如果不想让 default 分支的内容被输出就需要 break 了,具体例子可看下面的示例。
+以上代码运行后输出的结果为 `WIKI` 和 `Hello World` ,如果不想让下面分支的语句被运行就需要 break 了,具体例子可看下面的示例。
+
+```cpp
+char i = 'B';
+switch (i) {
+  case 'A':
+    cout << "OI" << endl;
+    break;
+
+  case 'B':
+    cout << "WIKI" << endl;
+    break;
+
+  default:
+    cout << "Hello World" << endl;
+}
+```
+
+以上代码运行后输出的结果为 WIKI,因为 break 的存在,接下来的语句就不会继续被执行了。default 语句不需要 break,因为下面没有语句了。
+
+switch 的 case 分句中也可以选择性的加花括号。不过要注意的是,如果需要在 switch 语句中定义变量,花括号是必须要加的。例如:
 
 ```cpp
 char i = 'B';
 switch (i) {
   case 'A': {
+    int i = 1, j = 2;
     cout << "OI" << endl;
+    ans = i + j;
     break;
   }
+
   case 'B': {
+    int qwq = 3;
     cout << "WIKI" << endl;
+    ans = qwq * qwq;
     break;
   }
+
   default: { cout << "Hello World" << endl; }
 }
 ```
 
-以上代码运行后输出的结果为 WIKI,因为 break 的存在接下来的语句就不会继续被执行了。
+??? note "如何理解 switch"
+    在上文中,用了大量“case 分句”,“case 子句”等用语,实际上,在底层实现中,switch 相当于一组跳转语句。也因此,有 Duff's Device 这种奇技淫巧,希望了解的人可以自行学习。
+
+    另外还有一种理解 switch 的方式,就是从其逻辑意义去理解。在这种理解里,case 代表的就是一组子句,而 switch 根据选择句的值选择某个 case 分句进行执行。在这种理解中,除了极少数例外,case 是必须要加 break 和花括号的。
index 8b13789..8a1774b 100644 (file)
@@ -1 +1,331 @@
+author: Ir1d, cjsoft, Lans1ot
+类(class)是结构体的拓展,不仅能够拥有成员元素,还拥有成员函数。
 
+在面向对象编程(OOP)中,对象就是类的实例,也就是变量。
+
+C++ 中 `struct` 关键字定义的也是类,上文中的 **结构体** 的定义来自 C。因为某些历史原因,C++ 保留并拓展了 `struct` 。
+
+## 定义类
+
+类使用关键字 `class` 或者 `struct` 定义,下文以 `class` 举例。
+
+```cpp
+class ClassName {
+  ...
+};
+
+// Example:
+class Object {
+ public:
+  int weight;
+  int value;
+} e[array_length];
+
+const Object a;
+Object b, B[array_length];
+Object *c;
+```
+
+与使用 `struct` 大同小异。该例定义了一个名为 `Object` 的类。该类拥有四个成员元素,分别为 `weight,value` ;并在 `}` 后定义了一个数组 `B` 。
+
+定义类的指针形同 [ `struct` ](./struct.md) 。
+
+### 访问说明符
+
+不同于 [ `struct` ](./struct.md) 中的举例,本例中出现了 `public` ,这属于访问说明符。
+
+-    `public` :该访问说明符之后的各个成员都可以被公开访问,简单来说就是无论 **类内** 还是 **类外** 都可以访问。
+-    `protected` :该访问说明符之后的各个成员可以被 **类内** 、派生类或者友元的成员访问,但类外 **不能访问** 。
+-    `private` :该访问说明符之后的各个成员 **只能** 被 **类内** 成员或者友元的成员访问, **不能** 被从类外或者派生类中访问。
+
+对于 `struct` ,它的所有成员都是默认 `public` 。对于 `class` ,它的所有成员都是默认 `private` 。
+
+_关于 "友元" 和 "派生类",可以参考下方折叠框,或者查询网络资料进行详细了解。_
+
+_对于算法竞赛来说,友元和派生类并不是必须要掌握的知识点。_
+
+??? note "关于友元以及派生类的基本概念"
+
+    友元(`friend`): 使用`friend`关键字修饰某个函数或者类。可以使得在**被修饰者**在不成为成员函数或者成员类的情况下,访问该类的私有(`private`)或者受保护(`protected`)成员。简单来说就是只要带有这个类的`friend`标记,就可以访问私有或受保护的成员元素。
+
+    派生类(`derived class`): C++允许使用一个类作为**基类**,并通过基类**派生**出**派生类**。其中派生类(根据特定规则)继承基类中的成员变量和成员函数。可以提高代码的复用率。
+
+    派生类似" is "的关系。如猫(派生类)" is " 哺乳动物(基类)。
+
+     对于上面`private`和`protected`的区别,可以看做派生类可以访问基类的`protected`的元素(`public`同),但不能访问`private`元素。
+
+## 访问与修改成员元素的值
+
+方法形同 [ `struct` ](./struct.md) 
+
+-   对于变量,使用 `.` 符号。
+-   对于指针,使用 `->` 符号。
+
+## 成员函数
+
+成员函数,顾名思义。就是类中所包含的函数。
+
+??? note "常见成员函数举例"
+    ```cpp
+    vector.push_back();
+    set.insert();
+    queue.empty();
+    ```
+
+```cpp
+class Class_Name {
+  ... type Funciton_Name(...) { ... }
+};
+
+// Example:
+class Object {
+ public:
+  int weight;
+  int value;
+  void print() {
+    cout << weight << endl;
+    return;
+  }
+  void change_w(int);
+};
+
+void Object::change_w(int _weight) { weight = _weight; }
+```
+
+该类有一个打印 `Object` 成员元素的函数,以及更改成员元素 `weight` 的函数。
+
+和函数类似,对于成员函数,也可以先声明,在定义,如第十四行(声明处)以及十七行后(定义处)。
+
+如果想要调用 `var` 的 `print` 成员函数,可以使用 `var.print()` 进行调用。
+
+### 重载运算符
+
+??? note "何为重载"
+    C++ 允许编写者为名称相同的函数或者运算符指定不同的定义。这称为 **重载** (overload)。
+
+    如果同名函数的参数种类、数量、返回类型不相同其中一者或多者两两不相同,则这些同名函数被看做是不同的。
+
+    如果在调用时不会出现混淆(指调用某些同名函数时,无法根据所填参数种类和数量唯一地判断出被调用函数。常发生在具有默认参数的函数中),则编译器会根据调用时所填参数判断应调用函数。
+
+    而上述过程被称作重载解析。
+
+重载运算符,可以部分程度上代替函数,简化代码。
+
+下面给出重载运算符的例子。
+
+```cpp
+class Vector {
+ public:
+  int x, y;
+  Vector() : x(0), y(0) {}
+  Vector(int _x, int _y) : x(_x), y(_y) {}
+  int operator*(const Vector& other) { return x * other.y + y * other.x; }
+  Vector operator+(const Vector&);
+  Vector operator-(const Vector&);
+};
+
+Vector Vector::operator+(const Vector& other) {
+  return Vector(x + other.x, y + other.y);
+}
+
+Vector Vector::operator-(const Vector& other) {
+  return Vector(x - other.x, y - other.y);
+}
+//关于4,5行表示为x,y赋值,具体实现参见后文。
+```
+
+该例定义了一个向量类,并重载了 `* + -` 运算符,并分别代表向量内积,向量加,向量减。
+
+重载运算符的模板大致可分为下面几部分。
+
+```text
+/*类定义内重载*/ 返回类型 operator符号(参数){...}
+
+/*类定义内声明,在外部定义*/ 返回类型 类名称::operator符号(参数){...}
+```
+
+对于自定义的类,如果重载了某些运算符(一般来说只需要重载 `<` 这个比较运算符),便可以使用相应的 STL 容器或算法,如 [ `sort` ](../basic/stl-sort.md) 。
+
+_如要了解更多,参见“参考资料”第四条。_
+
+??? note " 可以被重载的运算符"
+
+      ```cpp
+         =
+         +  -  *  /  =  %
+         +=  -=  *=  /=  %=
+         <  >  ==  !=  <=  >=
+         &  |  !  ^  ~
+         &=  |=  ^=
+         //----------
+         <<  <<=  >>  >>=
+         ++  --
+         &&  ||
+         []  ()  ,
+         ->*  ->  new  delete  new[]  delete[]
+      ```
+
+### 在实例化变量时设定初始值
+
+为完成这种操作,需要定义 **默认构造函数** (Default constructor)。
+
+```cpp
+class ClassName {
+  ... ClassName(...)... { ... }
+};
+
+// Example:
+class Object {
+ public:
+  int weight;
+  int value;
+  Object() {
+    weight = 0;
+    value = 0;
+  }
+};
+```
+
+该例定义了 `Object` 的默认构造函数,该函数能够在我们实例化 `Object` 类型变量时,将所有的成员元素初始化为 `0` 。
+
+若无显式的构造函数,则编译器认为该类有隐式的默认构造函数。换言之,若无定义任何构造函数,则编译器会自动生成一个默认构造函数,并会根据成员元素的类型进行初始化(与定义 内置类型 变量相同)。
+
+在这种情况下,成员元素都是未初始化的,访问未初始化的变量的结果是未定义的(也就是说并不知道会返回和值)。
+
+如果需要自定义初始化的值,可以再定义(或重载)构造函数。
+
+??? note "关于定义(或重载)构造函数"
+    一般来说,默认构造函数是不带参数的,这区别于构造函数。构造函数和默认构造函数的定义大同小异,只是参数数量上的不同。
+
+    构造函数可以被重载(当然首次被叫做定义)。需要注意的是,如果已经定义了构造函数,且构造函数的参数列表不为空,那么编译器便不会再生成无参数的默认构造函数。这会可能会使试图以默认方法构造变量的行为编译失败(指不填入初始化参数)。
+
+使用 C++11 或以上时,可以使用 `{}` 进行变量的初始化。
+
+??? note "关于`{}`"
+    使用 `{}` 进行初始化,会用到 std::initializer_list 这一个轻量代理对象进行初始化。
+
+    初始化步骤大概如下
+
+    1. 尝试寻找参数中有`std::initializer_list`的默认构造函数,如果有则调用(调用完后不再进行下面的查找,下同)。
+
+    2. 尝试将`{}`中的元素填入其他构造参数,如果能将参数按照顺序填满(默认参数也算在内),则调用该默认构造函数。
+
+    3. 若无`private`成员元素,则尝试在**类外**按照元素定义顺序或者下标顺序依次赋值。
+
+    _上述过程只是完整过程的简化版本,详细内容参见"参考资料九"_
+
+```cpp
+class Object {
+ public:
+  int weight;
+  int value;
+  Object() {
+    weight = 0;
+    value = 0;
+  }
+  Object(int _weight = 0, int _value = 0) {
+    weight = _weight;
+    value = _value;
+  }
+  // the same as
+  // Object(int _weight,int _value):weight(_weight),value(_value) {}
+};
+
+// the same as
+// Object::Object(int _weight,int _value){
+//   weight = _weight;
+//   value = _value;
+// }
+//}
+
+Object A;        // ok
+Object B(1, 2);  // ok
+Object C{1, 2};  // ok,(C++11)
+```
+
+??? note "关于隐式类型转换"
+    有时候会写出如下的代码
+
+    ```cpp
+    class Node {
+     public:
+      int var;
+      Node(int _var) : var(_var) {}
+    };
+    Node a = 1;
+    ```
+
+    看上去十分不符合逻辑,一个 `int` 类型不可能转化为 `node` 类型。但是编译器不会进行 `error` 提示。
+
+    原因是在进行赋值时,首先会将 `1` 作为参数调用 `node::node(int)` ,然后调用默认的复制函数进行赋值。
+
+    但大多数情况下,编写者会希望编译器进行报错。这时便可以在构造函数前追加 `explicit` 关键字。这会告诉编译器必须显式进行调用。
+
+    ```cpp
+    class Node {
+     public:
+      int var;
+      explicit Node(int _var) : var(_var) {}
+    };
+    ```
+
+    也就是说 `node a=1` 将会报错,但 `node a=node(1)` 不会。因为后者显式调用了构造函数。当然大多数人不会写出后者的代码,但此例足以说明 explicit 的作用。
+
+    _不过在算法竞赛中,为了避免此类情况常用的是"加强对代码的规范程度",从源头上避免_
+
+### 销毁
+
+这是不可避免的问题。每一个变量都将在作用范围结束走向销毁。
+
+但对于已经指向了动态申请的内存的指针来说,该指针在销毁时不会自动释放所指向的内存,需要手动释放动态内存。
+
+如果结构体的成员元素包含指针,同样会遇到这种问题。需要用到析构函数来手动释放动态内存。
+
+ **析构** 函数(Destructor)将会在该变量被销毁时被调用。重载的方法形同构造函数,但需要在前加 `~` 
+
+_默认定义的析构函数通常对于算法竞赛已经足够使用,通常我们只有在成员元素包含指针时才会重载析构函数。_
+
+```cpp
+class Object {
+ public:
+  int weight;
+  int value;
+  int* ned;
+  Object() {
+    weight = 0;
+    value = 0;
+  }
+  ~Object() { delete ned; }
+};
+```
+
+### 为类变量赋值
+
+默认情况下,赋值时会按照对应成员元素赋值的规则进行。也可以使用 `类名称()` 或 `类名称{}` 作为临时变量来进行赋值。
+
+前者只是调用了复制构造函数(copy constructor),而后者在调用复制构造函数前会调用默认构造函数。
+
+另外默认情况下,进行的赋值都是对应元素间进行 **浅拷贝** ,如果成员元素中有指针,则在赋值完成后,两个变量的成员指针具有相同的地址。
+
+```cpp
+// A,tmp1,tmp2,tmp3类型为Object
+tmp1 = A;
+tmp2 = Object(...);
+tmp3 = {...};
+```
+
+如需解决指针问题或更多操作,需要重载相应的构造函数。
+
+_更多 构造函数(constructor)内容,参见“参考资料”第六条。_
+
+## 参考资料
+
+1.   [cppreference class](https://zh.cppreference.com/w/cpp/language/class) 
+2.   [cppreference access](https://zh.cppreference.com/w/cpp/language/access) 
+3.   [cppreference default_constructor](https://zh.cppreference.com/w/cpp/language/default_constructor) 
+4.   [cppreference operator](https://zh.cppreference.com/w/cpp/language/operators) 
+5.   [cplusplus Data structures](http://www.cplusplus.com/doc/tutorial/structures/) 
+6.   [cplusplus Special members](http://www.cplusplus.com/doc/tutorial/classes2/) 
+7.   [C++11 FAQ](http://www.stroustrup.com/C++11FAQ.html) 
+8.   [cppreference Friendship and inheritance](http://www.cplusplus.com/doc/tutorial/inheritance/) 
+9.   [cppreference value initialization](https://zh.cppreference.com/w/cpp/language/value_initialization) 
index 9f2eb5e..fc96321 100644 (file)
@@ -4,7 +4,7 @@
 
 每一个版本的 C++ 标准不仅规定了 C++ 的语法、语言特性,还规定了一套 C++ 内置库的实现规范,这个库便是 C++ 标准库。C++ 标准库中包含大量常用代码的实现,如输入输出、基本数据结构、内存管理、多线程支持等。掌握 C++ 标准库是编写更现代的 C++ 代码必要的一步。C++ 标准库的详细文档在 [cppreference](https://zh.cppreference.com/) 网站上,文档对标准库中的类型函数的用法、效率、注意事项等都有介绍,请善用。
 
-需要指出的是,不同的 OJ 平台对 C++ 版本均不相同,例如 [最新的 ICPC 比赛规则](https://icpc.baylor.edu/worldfinals/programming-environment) 支持 C++14 标准,而 [NOI 现行规则](http://www.noi.cn/newsview.html?id=559&hash=E4E249) 中指定的 g++ 4.8 [默认支持标准](https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/Standards.html#Standards) 是 C++98。因此在学习 C++ 时要注意比赛支持的标准,避免在赛场上时编译报错。
+需要指出的是,不同的 OJ 平台对 C++ 版本均不相同,例如 [最新的 ICPC 比赛规则](https://icpc.baylor.edu/worldfinals/programming-environment) 支持 C++17 标准,而 [NOI 现行规则](http://www.noi.cn/newsview.html?id=559&hash=E4E249) 中指定的 g++ 4.8 [默认支持标准](https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/Standards.html#Standards) 是 C++98。因此在学习 C++ 时要注意比赛支持的标准,避免在赛场上时编译报错。
 
 ## 标准模板库(STL)
 
diff --git a/docs/lang/editor/geany.md b/docs/lang/editor/geany.md
new file mode 100644 (file)
index 0000000..4240576
--- /dev/null
@@ -0,0 +1,64 @@
+# Geany
+
+Geany 是一个轻量、便捷的编辑器,对于 Linux 环境下的初学者较为友好。
+
+与 Dev-C++ 一样,它可以编译运行单个文件。
+
+不过,它可以在 Linux/Windows/macOS 下运行。
+
+其官网为: <https://geany.org/> 
+
+## 优缺点
+
+### 优点
+
+1.  轻量;
+2.  可以编译运行单个文件;
+3.  不需要太多配置;
+4.  跨平台。
+
+### 缺点
+
+1.  没有太多人使用;
+2.  在 macOS Catalina 下有一些权限问题;
+3.  新建文件时,默认不会有语法高亮,需要保存为 C++ 文件后才会有;
+4.  如果从模板新建 C++ 文件,后缀名为\*.cxx,而不是我们所熟悉的\*.cpp。
+
+## 安装
+
+### Windows/macOS
+
+在官网上下载安装包安装
+
+### Linux
+
+#### 方法一
+
+使用 `apt` 等包管理器进行安装
+
+#### 方法二
+
+1.  从官网下载源码
+2.  终端下运行:
+
+```bash
+    ./configure
+    make
+    sudo make install
+```
+
+如遇到 `No package 'gtk+-2.0' found` 可能需要安装 `libgtk2.0-dev` (使用 `apt` 等包管理器 即可)
+
+## 常见问题
+
+兼容深度终端:
+
+在首选项→工具→虚拟终端,修改终端的命令为:
+
+```bash
+deepin-terminal -x "/bin/sh" %c
+```
+
+点击“应用”按钮后即可。
+
+(来源:Deepin Wiki <https://wiki.deepin.org/> )
index 0f24981..d0e3d8e 100644 (file)
@@ -244,11 +244,12 @@ xmodmap -e 'clear Lock' -e 'keycode x042=Escape'
 
 Vim 的宗旨是效率至上唯快不破,那么一切都以 `快` 来思考才是正途。那么如何使用这个自行车才是最快的呢?当然是沿着起点和终点之间的那条直线骑。同样的,<kbd>.</kbd>命令只有用到关键处才是最快的。如何使用它呢?我们来看几个例子。
 
-```cpp
-int a, b cin >> a >> b cout << a + b return 0
-```
+    int a, b
+    cin >> a >> b
+    cout << a + b
+    return 0
 
-可以看见每一行都少了空格。那么如何使用<kbd>.</kbd>命令来优雅地修改呢?为了省去 Vim 的缺点,我们显然可以先将光标移到第一行行尾,然后输入 `a;<Esc>` ,然后接着向下移动到每一行行尾的时候,直接使用<kbd>.</kbd>命令即可。但是这还是没有变快。那么怎么办呢?你会想起 Vim 还有个进入插入模式的命令:A。即移动到行尾插入。那么一切都鲜明起来了,命令如下即可: `A;<Esc>` ,然后你只需要不停地 `j.` 就行了,还是挺~~爽~~方便的。
+可以看见每一行末尾都少了分号。那么如何使用<kbd>.</kbd>命令来优雅地修改呢?为了省去 Vim 的缺点,我们显然可以先将光标移到第一行行尾,然后输入 `a;<Esc>` ,然后接着向下移动到每一行行尾的时候,直接使用<kbd>.</kbd>命令即可。但是这还是没有变快。那么怎么办呢?你会想起 Vim 还有个进入插入模式的命令:A。即移动到行尾插入。那么一切都鲜明起来了,命令如下即可: `A;<Esc>` ,然后你只需要不停地 `j.` 就行了,还是挺~~爽~~方便的。
 
 那么它的用处止步于此了吗?显然远远没有。再来看如下一行代码:
 
index fd8ba45..92f63a5 100644 (file)
@@ -32,9 +32,17 @@ xcode-select --install
 sudo apt update && sudo apt install g++
 ```
 
+#### 在命令行中编译代码
+
 熟练之后也有玩家会使用更灵活的命令行来编译代码,这样就不依赖 IDE 了,而是使用自己熟悉的文本编辑器编写代码。
 
-g++ 是 C++ 语言的编译器,C 语言的编译器为 gcc。
+```bash
+g++ test.cpp -o test -lm
+```
+
+ `g++` 是 C++ 语言的编译器(C 语言的编译器为 `gcc` ), `-o` 用于指定可执行文件的文件名,编译选项 `-lm` 用于链接数学库 `libm` ,从而使得使用 `math.h` 的代码可以正常编译运行。
+
+注:C++ 程序不需要 `-lm` 即可正常编译运行。历年 NOI/NOIP 试题的 C++ 编译选项中都带着 `-lm` ,故这里也一并加上。
 
 ## 第一行代码
 
@@ -43,18 +51,10 @@ g++ 是 C++ 语言的编译器,C 语言的编译器为 gcc。
 C++ 语言
 
 ```c++
-#include <cstdio>  // 引用头文件
-
-int main() {                // 定义 main 函数
-  printf("Hello, world!");  // 输出 Hello, world!
-  return 0;                 // 返回 0,结束 main 函数
-}
-```
-
-```c++
 #include <iostream>  // 引用头文件
 
 using namespace std;
+// 引入命名空间(相关阅读 https://oi-wiki.org/lang/namespace/#using )
 
 int main() {                // 定义 main 函数
   cout << "Hello, world!";  // 输出 Hello, world!
@@ -65,10 +65,12 @@ int main() {                // 定义 main 函数
 C 语言
 
 ```c
-#include <stdio.h>  // 引用头文件
+#include <stdio.h>          // 引用头文件
 
 int main() {                // 定义 main 函数
   printf("Hello, world!");  // 输出 Hello, world!
   return 0;                 // 返回 0,结束 main 函数
 }
 ```
+
+注意:C 语言在这里仅做参考(它基本上已经过时),C++ 完全兼容 C 语言,并且拥有许多新的功能,可以让选手在赛场上事半功倍。具体请见 [C 与 C++ 区别](/lang/c-cpp/) 
diff --git a/docs/lang/images/java1.png b/docs/lang/images/java1.png
new file mode 100644 (file)
index 0000000..4d3e793
Binary files /dev/null and b/docs/lang/images/java1.png differ
diff --git a/docs/lang/images/java2.png b/docs/lang/images/java2.png
new file mode 100644 (file)
index 0000000..7d18b0d
Binary files /dev/null and b/docs/lang/images/java2.png differ
diff --git a/docs/lang/images/java3.png b/docs/lang/images/java3.png
new file mode 100644 (file)
index 0000000..7e252b7
Binary files /dev/null and b/docs/lang/images/java3.png differ
diff --git a/docs/lang/images/java4.png b/docs/lang/images/java4.png
new file mode 100644 (file)
index 0000000..6fa6bf8
Binary files /dev/null and b/docs/lang/images/java4.png differ
diff --git a/docs/lang/images/java5.png b/docs/lang/images/java5.png
new file mode 100644 (file)
index 0000000..f2494d6
Binary files /dev/null and b/docs/lang/images/java5.png differ
diff --git a/docs/lang/images/java6.png b/docs/lang/images/java6.png
new file mode 100644 (file)
index 0000000..28390f9
Binary files /dev/null and b/docs/lang/images/java6.png differ
index 8b13789..5727345 100644 (file)
@@ -1 +1,286 @@
+## 关于 Java
 
+Java 是一种广泛使用的计算机编程语言,拥有 **跨平台** 、 **面向对象** 、 **泛型编程** 的特性,广泛应用于企业级 Web 应用开发和移动应用开发。
+
+## 环境安装
+
+使用 [OpenJDK](https://jdk.java.net/) 作为实例,下载下来的都是压缩包,解压缩此处略过
+
+### Windows
+
+将解压缩后的文件夹放到你想放的位置,假设你解压后放到了 `C:\Program Files\Java\jdk-14` ,
+
+![第一步](images/java1.png)
+
+![第二步](images/java2.png)
+
+![第三步](images/java3.png)
+
+![第四步](images/java4.png)
+
+![第五步](images/java5.png)
+
+![第六步](images/java6.png)
+
+### Linux
+
+#### 使用包管理器安装
+
+可以使用包管理器提供的 JDK。具体指令如下
+
+```bash
+sudo apt install default-jre
+sudo apt install default-jdk
+```
+
+如果 `CentOS` 则使用的是 `yum` 安装,命令如下:
+
+```bash
+sudo yum install java-1.8.0-openjdk
+```
+
+在稍后询问是否安装时按下 `y` 继续安装
+或是你已经下好了 `rpm` 文件,可以使用以下命令安装
+
+```bash
+sudo yum localinstall jre-9.0.4_linux_x64_bin.rpm #安装jre-9.0
+sudo yum localinstall jdk-9.0.4_linux-x64_bin.rpm #安装jdk-9.0
+```
+
+#### 手动安装
+
+```bash
+sudo mv jdk-14 /opt
+```
+
+并在 `.bashrc` 文件末尾添加
+
+```bash
+export JAVA_HOME="/opt/jdk-14/bin"
+export PATH=${JAVA_HOME}:$PATH
+```
+
+在控制台中输入命令 `source ~/.bashrc` 即可重载。如果是使用的 zsh 或其他命令行,在 `~/.zshrc` 或对应的文件中添加上面的内容
+
+### MacOS
+
+如果是 MacOS,你可以使用以下命令安装包
+
+```bash
+cd ~/Downloads
+curl -v -j -k -L -H "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u121-b13/e9e7ea248e2c4826b92b3f075a80e441/jdk-8u121-macosx-x64.dmg > jdk-8u121-macosx-x64.dmg
+hdiutil attach jdk-8u121-macosx-x64.dmg
+sudo installer -pkg /Volumes/JDK\ 8\ Update\ 121/JDK\ 8\ Update\ 121.pkg -target /
+diskutil umount /Volumes/JDK\ 8\ Update\ 121
+rm jdk-8u121-macosx-x64.dmg
+```
+
+或者直接在官方网站下载 `pkg` 包或 `dmg` 包安装
+
+## 基本语法
+
+ **_注意_**  `Java` 类似 `C/C++` 语言,有一个函数作为程序执行的起始点,所有的程序只有一个主函数,每次执行的时候都会从主类开始,主函数是整个程序的入口,一切从此处开始。
+
+### 注释
+
+和 `C/C++` 一样, `Java` 使用 `//` 和 `/* */` 分别注释单行和多行
+
+### 基本数据类型
+
+|   类型名   |   意义  |
+| :-----: | :---: |
+| boolean |  布尔类型 |
+|   byte  |  字节类型 |
+|   char  |  字符型  |
+|  double | 双精度浮点 |
+|  float  | 单精度浮点 |
+|   int   |   整型  |
+|   long  |  长整型  |
+|  short  |  短整型  |
+|   null  |   空   |
+
+### 申明变量
+
+```java
+int a = 12;//设置a为整数类型,并给a赋值12
+String str = "Hello, OI-wiki"; //申明字符串变量str
+char ch = "W";
+double PI = 3.1415926;
+```
+
+### final 关键字
+
+ `final` 含义是这是最终的、不可更改的结果,被 final 修饰的变量只能被赋值一次,赋值后不再改变。
+
+```java
+final double PI = 3.1415926;
+```
+
+### 数组
+
+```java
+int[] ary = new int[10];
+//有十个元素的整数类型数组
+//其语法格式为 数据类型[] 变量名 = new 数据类型[数组大小]
+```
+
+### 字符串
+
+-   字符串是 `Java` 一个内置的类。
+
+```java
+//最为简单的构造一个字符串变量的方法如下
+String a = "Hello";
+//还可以使用字符数组构造一个字符串变量
+char[] stringArray = {'H','e','l','l','o'};
+String s = new String(stringArray);
+```
+
+### 输出
+
+可以对变量进行格式化输出
+
+|   符号   |   意义  |
+| :----: | :---: |
+|  `%f`  |  浮点类型 |
+|  `%s`  | 字符串类型 |
+|  `%d`  |  整数类型 |
+|  `%c`  |  字符类型 |
+
+```java
+class test{
+    public static void main(String[] args) {
+        int a = 12;
+        char b = 'A';
+        double s = 3.14;
+        String str = "Hello world";
+        System.out.println("%f",s);
+        System.out.println("%d",a);
+        system.out.println("%c",b);
+        system.out.println("%s",str);
+    }
+}
+```
+
+### 控制语句
+
+#### 选择
+
+-   if
+
+```java
+class test{
+    public static void main(String[] args) {
+        if(/*判断条件*/){
+              //条件成立时执行这里面的代码
+          }
+      }
+}
+```
+
+-   if...else
+
+```java
+class test{
+    public static void main(String[] args) {
+        if(/*判断条件*/){
+            //条件成立时执行这里面的代码
+        }else{
+            //条件不成立时执行这里面的代码
+        }
+    }
+}
+```
+
+-   if...else if...else
+
+```java
+class test{
+    public static void main(String[] args) {
+        if(/*判断条件*/){
+            //判断条件成立执行这里面的代码
+        }else if(/*判断条件2*/){
+            //判断条件2成立执行这里面的代码
+        }else{
+          //上述条件都不成立执行这里面的代码
+        }
+    }
+}
+```
+
+#### 循环
+
+-   for
+
+```java
+class test{
+    public static void main(String[] args) {
+            for(/*初始化*/;/*循环的判断条件*/;/*每次循环后执行的步骤*/){
+                //当循环的条件成立执行循环体内代码
+            }
+    }
+}
+```
+
+-   while
+
+```java
+class test{
+    public static void main(String[] args) {
+        while(/*判定条件*/){
+            //条件成立时执行循环体内代码
+        }
+    }
+}
+```
+
+-   do...while
+
+```java
+class test{
+    public static void main(String[] args) {
+        do{
+          //需要执行的代码
+        }while(/*循环判断条件*/);
+    }
+}
+```
+
+-   switch...case
+
+```java
+class test{
+      public static void main(String[] args) {
+        switch(/*表达式*/){
+          case /*值-1*/:
+              //当表达式取得的值符合值-1执行此段代码
+          break; //如果不加上break语句,会让程序按顺序往下执行,执行所有的case语句
+          case /*值-2*/:
+              //当表达式取得的值符合值-2执行此段代码
+          break;
+          default:
+              //当表达式不符合上面列举的值的时候执行这里面的代码
+        }
+      }
+}
+```
+
+## 注意事项
+
+### 类名与文件名一致
+
+创建 Java 源程序需要类名和文件名一致才能编译通过,否则编译器会提示找不到 `类` 。通常该文件名会在具体 OJ 中指定。
+
+例:
+
+Add.java
+
+```java
+class Add{
+    public static void main(String[] args) {
+        // ...
+    }
+}
+```
+
+在该文件中需使用 Add 为类名方可编译通过。
index 4656c40..6572c5b 100644 (file)
@@ -94,7 +94,7 @@ while (statement2) {
 }
 ```
 
-这两种方式是等价的
+在 statement4 中没有 `continue` 语句(见下文)的时候是等价的,但是下面一种方法很少用到
 
 ```cpp
 // while 语句
@@ -111,7 +111,7 @@ do {
 } while (statement2);
 ```
 
-这两种方式也是等价的。
+在 statement1 中没有 `continue` 语句的时候这两种方式也也是等价的。
 
 ```cpp
 while (1) {
@@ -123,13 +123,13 @@ for (;;) {
 }
 ```
 
-这两种方式都是永远循环下去。
+这两种方式都是永远循环下去。(可以使用 `break` (见下文)退出。)
 
 可以看出,三种语句可以彼此代替,但一般来说,语句的选用遵守以下原则:
 
-1.  枚举一个变量时,使用 for 语句;
-2.  “到何时为止”时,使用 while 语句;
-3.  使用 while 语句时,若要先执行循环体再进行判断,使用 do...while 语句。
+1.  循环过程中有个固定的增加步骤(最常见的是枚举)时,使用 for 语句;
+2.  只确定循环的终止条件时,使用 while 语句;
+3.  使用 while 语句时,若要先执行循环体再进行判断,使用 do...while 语句。一般很少用到,常用场景是用户输入。
 
 ## break 与 continue 语句
 
index 8b13789..0a97563 100644 (file)
@@ -1 +1,71 @@
+author: Ir1d, cjsoft, Lans1ot
+结构体(struct),可以看做是一系列称为成员元素的组合体。
 
+可以看做是自定义的数据类型。
+
+_本页描述的 `struct` 不同于 C 中 `struct` ,在 C++ 中 `struct` 被扩展为类似 [ `class` ](./class.md) 的类说明符_。
+
+## 定义结构体
+
+```cpp
+struct Object {
+  int weight;
+  int value;
+} e[array_length];
+
+const Object a;
+Object b, B[array_length], tmp;
+Object *c;
+```
+
+上例中定义了一个名为 `Object` 的结构体,两个成员元素 `value,weight` ,类型都为 `int` 。
+
+在 `}` 后,定义了数据类型为 `Object` 的常量 `a` ,变量 `b` ,变量 `tmp` ,数组 `B` ,指针 `c` 。对于某种已经存在的类型,都可以使用这里的方法进行定义常量、变量、指针、数组等。
+
+_关于指针:不必强求掌握。_
+
+### 定义指针
+
+如果是定义内置类型的指针,则与平常定义指针一样。
+
+如果是定义结构体指针,在定义中使用 `StructName*` 进行定义。
+
+```cpp
+struct Edge {
+  /*
+  ...
+  */
+  Edge* nxt;
+};
+```
+
+上例仅作举例,不必纠结实际意义。
+
+## 访问/修改成员元素
+
+可以使用 `变量名.成员元素名` 进行访问(其中双引号不写入程序,下同)。
+
+如 : 输出 `var` 的 `v` 成员: `cout << var.v` 。
+
+也可以使用 `指针名->成员元素名` 或者 使用 `(*指针名).成员元素名` 进行访问。
+
+如 : 将结构体指针 `ptr` 指向的结构体的成员元素 `v` 赋值为 `tmp` : `(*ptr).v = tmp` 或者 `ptr->v = tmp` 。
+
+## 为什么需要结构体?
+
+首先,条条大路通罗马,可以不使用结构体达到相同的效果。但是结构体能够显式地将成员元素(在算法竞赛中通常是变量)捆绑在一起,如本例中的 `Object` 结构体,便将 `value,weight` 放在了一起(定义这个结构体的实际意义是表示一件物品的重量与价值)。这样的好处边是限制了成员元素的使用。  
+想象一下,如果不使用结构体而且有两个数组 `value[],Value[]` ,很容易写混淆。但如果使用结构体,能够减轻出现使用变量错误的几率。
+
+并且不同的结构体(结构体类型,如 `Object` 这个结构体)或者不同的结构体变量(结构体的实例,如上方的 `e` 数组)可以拥有相同名字的成员元素(如 `tmp.value,b.value` ),同名的成员元素相互独立(拥有独自的内存,比如说修改 `tmp.value` 不会影响 `b.value` 的值)。  
+这样的好处是可以使用尽可能相同或者相近的变量去描述一个物品。比如说 `Object` 里有 `value` 这个成员变量;我们还可以定义一个 `Car` 结构体,同时也拥有 `value` 这个成员;如果不使用结构体,或许我们就需要定义 `valueOfObject[],valueOfCar[]` 等不同名称的数组来区分。
+
+_如果想要更详细的描述一种事物,还可以定义成员函数。请参考 [类](./class.md) 获取详细内容。_
+
+## 更多的操作?
+
+详见 [类](./class.md) 
+
+## 参考资料
+
+1.   [cppreference class](https://zh.cppreference.com/w/cpp/language/class) 
+2.   [cplusplus Data structures](http://www.cplusplus.com/doc/tutorial/structures/) 
index 5297a92..5700f7f 100644 (file)
@@ -11,8 +11,6 @@ C++ 内置了六种基本数据类型:
 | 双浮点型 | double |
 | 无类型  | void   |
 
-一些基本类型可以使用一个或多个类型修饰符进行修饰: `signed` , `unsigned` , `short` , `long` 
-
 | 类型     | 字节数   | 范围                                              |
 | ------ | ----- | ----------------------------------------------- |
 | char   | 1 个字节 | -128 到 127 或者 0 到 255                           |
@@ -20,6 +18,8 @@ C++ 内置了六种基本数据类型:
 | float  | 4 个字节 |  $-3.4\times 10^{38}$ 到 $3.4\times 10^{38}$     |
 | double | 8 个字节 |  $-1.7\times 10^{-308}$ 到 $1.7\times 10^{308}$  |
 
+一些基本类型可以使用一个或多个类型修饰符进行修饰,例如 `signed` , `unsigned` 修饰类型表示所修饰的数有没有符号, `short` , `long` 表示类型的长短,即类型所能表示的范围。另外还有一些其他的修饰符例如 `const` ,可以用来描述一些更加复杂的东西,将会在下面讲解。
+
 ## 声明变量
 
 使用关键词加上变量名即可声明。
@@ -30,15 +30,15 @@ double wiki;
 char org = 'c';
 ```
 
-声明时没有初始化值的全局变量会被初始化为 0。而局部变量没有这种特性,需要手动赋初始值。
+在目前我们所接触到的程序段中,声明在花括号包裹的地方的变量是局部变量,而声明在没有花括号包裹的地方的变量是全局变量。实际有例外,但是现在不必了解。
+
+声明时没有初始化值的全局变量会被初始化为 0。而局部变量没有这种特性,需要手动赋初始值,否则可能引起难以发现的 bug。
 
 ## 变量作用域
 
 作用域是变量可以发挥作用的代码块。
 
-变量分为全局变量和局部变量。
-在所有函数外部声明的变量,称为全局变量。
-在函数或一个代码块内部声明的变量,称为局部变量。
+变量分为全局变量和局部变量,意义已经在上面讲解。
 
 全局变量的作用域是整个文件,全局变量一旦声明,在整个程序中都是可用的。
 
@@ -59,7 +59,7 @@ int main() {
 
 ## 常量
 
-常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。
+常量是固定值,在程序执行期间不会改变。
 
 常量的值在定义后不能被修改。声明时加一个 `const` 关键字即可。
 
index ca432df..e6dac1b 100644 (file)
@@ -1,16 +1,16 @@
 ## 基础篇
 
-BSGSï¼\88baby-step gaint-stepï¼\89ï¼\8cå\8d³å¤§æ­¥å°\8fæ­¥ç®\97æ³\95ã\80\82常ç\94¨äº\8eæ±\82解离æ\95£å¯¹æ\95°é\97®é¢\98ã\80\82å½¢å¼\8få\8c\96å\9c°è¯´ï¼\8c该ç®\97æ³\95å\8f¯ä»¥å\9c¨ $O(\sqrt{p})$ ç\94¨äº\8eæ±\82解ã\80\82
+BSGSï¼\88baby-step gaint-stepï¼\89ï¼\8cå\8d³å¤§æ­¥å°\8fæ­¥ç®\97æ³\95ã\80\82常ç\94¨äº\8eæ±\82解离æ\95£å¯¹æ\95°é\97®é¢\98ã\80\82å½¢å¼\8få\8c\96å\9c°è¯´ï¼\8c该ç®\97æ³\95å\8f¯ä»¥å\9c¨ $O(\sqrt{p})$ ç\9a\84æ\97¶é\97´å\86\85æ±\82解
 
 $$
-a^x \equiv b \bmod p
+a^x \equiv b \pmod p
 $$
 
 其中 $a\perp p$ 。方程的解 $x$ 满足 $0 \le x < p$ 。(在这里需要注意,只要 $a\perp p$ 就行了,不要求 $p$ 是素数)
 
 ### 算法描述
 
-令 $x = A \left \lceil \sqrt p \right \rceil - B$ ,其中 $0\le A,B \le \left \lceil \sqrt p \right \rceil$ ,则有 $a^{A\left \lceil \sqrt p \right \rceil -B} \equiv b$ ,稍加变换,则有 $a^{A\left \lceil \sqrt p \right \rceil} \equiv ba^B$ 。
+令 $x = A \left \lceil \sqrt p \right \rceil - B$ ,其中 $0\le A,B \le \left \lceil \sqrt p \right \rceil$ ,则有 $a^{A\left \lceil \sqrt p \right \rceil -B} \equiv b \pmod p$ ,稍加变换,则有 $a^{A\left \lceil \sqrt p \right \rceil} \equiv ba^B \pmod p$ 。
 
 我们已知的是 $a,b$ ,所以我们可以先算出等式右边的 $ba^B$ 的所有取值,枚举 $B$ ,用 `hash` / `map` 存下来,然后逐一计算 $a^{A\left \lceil \sqrt p \right \rceil}$ ,枚举 $A$ ,寻找是否有与之相等的 $ba^B$ ,从而我们可以得到所有的 $x$ , $x=A \left \lceil \sqrt p \right \rceil - B$ 。
 
@@ -21,7 +21,7 @@ $$
 求解
 
 $$
-x^a \equiv b \bmod p
+x^a \equiv b \pmod p
 $$
 
 其中 $p$ 是个质数。
@@ -32,48 +32,48 @@ $$
 
 ### 方法一
 
-我们令 $x=g^c$ , $g$ 是 $p$ 的原根(我们一定可以找到这个 $g$ 和 $c$ ),问题转化为求解 $(g^c)^a \equiv b \bmod p$ 。稍加变换,得到
+我们令 $x=g^c$ , $g$ 是 $p$ 的原根(我们一定可以找到这个 $g$ 和 $c$ ),问题转化为求解 $(g^c)^a \equiv b \pmod p$ 。稍加变换,得到
 
 $$
-(g^a)^c \equiv b \mod p
+(g^a)^c \equiv b \pmod p
 $$
 
-于是就转换成了我们熟知的 **BSGS** 的基本模型了,可以在 $O(\sqrt p)$ 解出 $c$ ,这样可以得到原方程的一个特解 $x_0\equiv g^c\bmod p$ 。
+于是就转换成了我们熟知的 **BSGS** 的基本模型了,可以在 $O(\sqrt p)$ 解出 $c$ ,这样可以得到原方程的一个特解 $x_0\equiv g^c\pmod p$ 。
 
 ### 方法二
 
 我们仍令 $x=g^c$ ,并且设 $b=g^t$ ,于是我们得到
 
 $$
-g^{ac}\equiv g^t\mod p
+g^{ac}\equiv g^t\pmod p
 $$
 
 方程两边同时取离散对数得到
 
 $$
-ac\equiv t\mod \varphi(p)
+ac\equiv t\pmod{\varphi(p)}
 $$
 
-我们可以通过 BSGS 求解 $g^t\equiv b\bmod p$ 得到 $t$ ,于是这就转化成了一个线性同余方程的问题。这样也可以解出 $c$ ,求出 $x$ 的一个特解 $x_0\equiv g^c\bmod p$ 。
+我们可以通过 BSGS 求解 $g^t\equiv b\pmod p$ 得到 $t$ ,于是这就转化成了一个线性同余方程的问题。这样也可以解出 $c$ ,求出 $x$ 的一个特解 $x_0\equiv g^c\pmod p$ 。
 
 ### 找到所有解
 
 在知道 $x_0\equiv g^{c}\pmod n$ 的情况下,我们想得到原问题的所有解。首先我们知道 $g^{\varphi(n)}\equiv 1\pmod n$ ,于是可以得到
 
 $$
-\forall\ t \in \mathbb{Z},\ x^k \equiv g^{ c \cdot k + t\cdot\varphi(n)}\equiv a \mod p
+\forall\ t \in \mathbb{Z},\ x^k \equiv g^{ c \cdot k + t\cdot\varphi(n)}\equiv a \pmod p
 $$
 
 于是得到所有解为
 
 $$
-\forall\ t\in \mathbb{Z},k\mid t\cdot\varphi(n),\ x\equiv g^{c+\frac{t\cdot\varphi(n)}{k}}\mod p
+\forall\ t\in \mathbb{Z},k\mid t\cdot\varphi(n),\ x\equiv g^{c+\frac{t\cdot\varphi(n)}{k}}\pmod p
 $$
 
 对于上面这个式子,显然有 $\frac{k}{\gcd(k,\varphi(n))}  \mid t$ 。因此我们设 $t=\frac{k}{\gcd(k,\varphi(n))}\cdot i$ ,得到
 
 $$
-\forall \ i\in \mathbb{Z},x\equiv g^{c+\frac{\varphi(n)}{\gcd(k,\varphi(n))}\cdot i}\mod p
+\forall \ i\in \mathbb{Z},x\equiv g^{c+\frac{\varphi(n)}{\gcd(k,\varphi(n))}\cdot i}\pmod p
 $$
 
 这就是原问题的所有解。
@@ -82,78 +82,79 @@ $$
 
 下面的代码实现的找原根、离散对数解和原问题所有解的过程。
 
-```cpp
-int gcd(int a, int b) { return a ? gcd(b % a, a) : b; }
-int powmod(int a, int b, int p) {
-  int res = 1;
-  while (b > 0) {
-    if (b & 1) res = res * a % p;
-    a = a * a % p, b >>= 1;
-  }
-  return res;
-}
-// Finds the primitive root modulo p
-int generator(int p) {
-  vector<int> fact;
-  int phi = p - 1, n = phi;
-  for (int i = 2; i * i <= n; ++i) {
-    if (n % i == 0) {
-      fact.push_back(i);
-      while (n % i == 0) n /= i;
+??? "参考代码"
+    ```cpp
+    int gcd(int a, int b) { return a ? gcd(b % a, a) : b; }
+    int powmod(int a, int b, int p) {
+      int res = 1;
+      while (b > 0) {
+        if (b & 1) res = res * a % p;
+        a = a * a % p, b >>= 1;
+      }
+      return res;
     }
-  }
-  if (n > 1) fact.push_back(n);
-  for (int res = 2; res <= p; ++res) {
-    bool ok = true;
-    for (int factor : fact) {
-      if (powmod(res, phi / factor, p) == 1) {
-        ok = false;
-        break;
+    // Finds the primitive root modulo p
+    int generator(int p) {
+      vector<int> fact;
+      int phi = p - 1, n = phi;
+      for (int i = 2; i * i <= n; ++i) {
+        if (n % i == 0) {
+          fact.push_back(i);
+          while (n % i == 0) n /= i;
+        }
+      }
+      if (n > 1) fact.push_back(n);
+      for (int res = 2; res <= p; ++res) {
+        bool ok = true;
+        for (int factor : fact) {
+          if (powmod(res, phi / factor, p) == 1) {
+            ok = false;
+            break;
+          }
+        }
+        if (ok) return res;
       }
+      return -1;
     }
-    if (ok) return res;
-  }
-  return -1;
-}
-// This program finds all numbers x such that x^k=a (mod n)
-int main() {
-  int n, k, a;
-  scanf("%d %d %d", &n, &k, &a);
-  if (a == 0) return puts("1\n0"), 0;
-  int g = generator(n);
-  // Baby-step giant-step discrete logarithm algorithm
-  int sq = (int)sqrt(n + .0) + 1;
-  vector<pair<int, int>> dec(sq);
-  for (int i = 1; i <= sq; ++i)
-    dec[i - 1] = {powmod(g, i * sq * k % (n - 1), n), i};
-  sort(dec.begin(), dec.end());
-  int any_ans = -1;
-  for (int i = 0; i < sq; ++i) {
-    int my = powmod(g, i * k % (n - 1), n) * a % n;
-    auto it = lower_bound(dec.begin(), dec.end(), make_pair(my, 0));
-    if (it != dec.end() && it->first == my) {
-      any_ans = it->second * sq - i;
-      break;
+    // This program finds all numbers x such that x^k=a (mod n)
+    int main() {
+      int n, k, a;
+      scanf("%d %d %d", &n, &k, &a);
+      if (a == 0) return puts("1\n0"), 0;
+      int g = generator(n);
+      // Baby-step giant-step discrete logarithm algorithm
+      int sq = (int)sqrt(n + .0) + 1;
+      vector<pair<int, int>> dec(sq);
+      for (int i = 1; i <= sq; ++i)
+        dec[i - 1] = {powmod(g, i * sq * k % (n - 1), n), i};
+      sort(dec.begin(), dec.end());
+      int any_ans = -1;
+      for (int i = 0; i < sq; ++i) {
+        int my = powmod(g, i * k % (n - 1), n) * a % n;
+        auto it = lower_bound(dec.begin(), dec.end(), make_pair(my, 0));
+        if (it != dec.end() && it->first == my) {
+          any_ans = it->second * sq - i;
+          break;
+        }
+      }
+      if (any_ans == -1) return puts("0"), 0;
+      // Print all possible answers
+      int delta = (n - 1) / gcd(k, n - 1);
+      vector<int> ans;
+      for (int cur = any_ans % delta; cur < n - 1; cur += delta)
+        ans.push_back(powmod(g, cur, n));
+      sort(ans.begin(), ans.end());
+      printf("%d\n", ans.size());
+      for (int answer : ans) printf("%d ", answer);
     }
-  }
-  if (any_ans == -1) return puts("0"), 0;
-  // Print all possible answers
-  int delta = (n - 1) / gcd(k, n - 1);
-  vector<int> ans;
-  for (int cur = any_ans % delta; cur < n - 1; cur += delta)
-    ans.push_back(powmod(g, cur, n));
-  sort(ans.begin(), ans.end());
-  printf("%d\n", ans.size());
-  for (int answer : ans) printf("%d ", answer);
-}
-```
+    ```
 
 ## 扩展篇
 
 接下来我们求解
 
 $$
-a^x\equiv b\mod p
+a^x\equiv b\pmod p
 $$
 
 其中 $a,p$ 不一定互质。
@@ -163,13 +164,13 @@ $$
 具体地,设 $d_1=\gcd(a,p)$ 。如果 $d_1\nmid b$ ,则原方程无解。否则我们把方程同时除以 $d_1$ ,得到
 
 $$
-\frac{a}{d_1}\cdot a^{x-1}\equiv \frac{b}{d_1}\mod \frac{p}{d_1}
+\frac{a}{d_1}\cdot a^{x-1}\equiv \frac{b}{d_1}\pmod{\frac{p}{d_1}}
 $$
 
 如果 $a$ 和 $\frac{p}{d_1}$ 仍不互质就再除,设 $d_2=\gcd\left(a,\frac{p}{d_1}\right)$ 。如果 $d_2\nmid \frac{b}{d_1}$ ,则方程无解;否则同时除以 $d_2$ 得到
 
 $$
-\frac{a^2}{d_1d_2}\cdot a^{x-2}≡\frac{b}{d_1d_2} \mod \frac{p}{d_1d_2}
+\frac{a^2}{d_1d_2}\cdot a^{x-2}≡\frac{b}{d_1d_2} \pmod{\frac{p}{d_1d_2}}
 $$
 
 同理,这样不停的判断下去。直到 $a\perp \frac{p}{d_1d_2\cdots d_k}$ 。
@@ -177,12 +178,12 @@ $$
 记 $D=\prod_{i=1}^kd_i$ ,于是方程就变成了这样:
 
 $$
-\frac{a^k}{D}\cdot a^{x-k}\equiv\frac{b}{D} \mod \frac{p}{D}
+\frac{a^k}{D}\cdot a^{x-k}\equiv\frac{b}{D} \pmod{\frac{p}{D}}
 $$
 
 由于 $a\perp\frac{p}{D}$ ,于是推出 $\frac{a^k}{D}\perp \frac{p}{D}$ 。这样 $\frac{a^k}{D}$ 就有逆元了,于是把它丢到方程右边,这就是一个普通的 BSGS 问题了,于是求解 $x-k$ 后再加上 $k$ 就是原方程的解啦。
 
-注意,不排除解小于等于 $k$ 的情况,所以在消因子之前做一下 $\Theta(k)$ 枚举,直接验证 $a^i\equiv b \mod p$ ,这样就能避免这种情况。
+注意,不排除解小于等于 $k$ 的情况,所以在消因子之前做一下 $\Theta(k)$ 枚举,直接验证 $a^i\equiv b \pmod p$ ,这样就能避免这种情况。
 
 ## 习题
 
index 7774238..700c474 100644 (file)
@@ -278,19 +278,13 @@ $$
 通过定义可以证明。
 
 $$
-\sum_{k=1}^m\binom{m}{k}\binom{n}{k}=\binom{m+n}{m}\tag{12}
-$$
-
-可以通过组合意义证明。
-
-$$
-\sum_{i=0}^n\binom{n-i}{i}=F_{n+1}\tag{13}
+\sum_{i=0}^n\binom{n-i}{i}=F_{n+1}\tag{12}
 $$
 
 其中 $F$ 是斐波那契数列。
 
 $$
-\sum_{l=0}^n \binom{l}{k} = \binom{n+1}{k+1}\tag{14}
+\sum_{l=0}^n \binom{l}{k} = \binom{n+1}{k+1}\tag{13}
 $$
 
 通过组合分析——考虑 $S={a_1, a_2, \cdots, a_{n+1}}$ 的 $k+1$ 子集数可以得证。
index de85792..1ff6c98 100644 (file)
@@ -1,36 +1,33 @@
\9c¨å­¦ä¹ ä¹\8bå\89\8d请å\85\88学习 [分块](../ds/decompose.md) 。
\89\8dç½®ç\9f¥è¯\86ï¼\9a [分块](../ds/decompose.md) 。
 
\89\93表大家é\83½ç\9f¥é\81\93ï¼\8cå°±æ\98¯å\9c¨æ¯\94èµ\9bæ\97¶æ\8a\8aç­\94æ¡\88é\83½è¾\93å\87ºå\87ºæ\9d¥ï¼\8cç\84¶å\90\8eå¼\80个æ\95°ç»\84ï¼\8cæ\8a\8aç­\94æ¡\88ç\9b´æ\8e¥å­\98å\85¥æ\95°ç»\84é\87\8cã\80\82äº\8eæ\98¯ä½ ç\9a\84代ç \81æ\97¶é\97´å¤\8dæ\9d\82度就æ\98¯ $O(1)$ ç\9a\84äº\86
\9c´ç´ ç\9a\84æ\89\93表ï¼\8cæ\8c\87ç\9a\84æ\98¯å\9c¨æ¯\94èµ\9bæ\97¶æ\8a\8aæ\89\80æ\9c\89å\8f¯è\83½ç\9a\84è¾\93å\85¥å¯¹åº\94ç\9a\84ç­\94æ¡\88é\83½è®¡ç®\97å\87ºæ\9d¥å¹¶ä¿\9då­\98ä¸\8bæ\9d¥ï¼\8cç\84¶å\90\8eå\9c¨ä»£ç \81é\87\8cå¼\80个æ\95°ç»\84æ\8a\8aç­\94æ¡\88æ\94¾é\87\8cé\9d¢ï¼\8cç\9b´æ\8e¥è¾\93å\87ºå\8d³å\8f¯
 
-但是需要注意这个技巧只适用于类似输出某函数值类的问题。比如规定 $f(x)$ 为整数 $x$ 的二进制表示中 $1$ 的个数。输入一个正整数 $n$ ,输出 $\sum_{i=1}^nf^2(i)$ 。这样的话 $n$ 不大时,采用打表的方法可以做到 $O(1)$ 的复杂度
+注意这个技巧只适用于输入的值域不大(如,输入只有一个数,而且范围很小)的问题,否则可能会导致代码过长、MLE、打表需要的时间过长等问题
 
-注意到这个问题其实十分的简单,采用一般做法也可以做到 $O(n\log n)$ 的复杂度,但是 $n=10^9$ ?
+???+note "例题"
 
-还有一些时候,打出来的表十分大,如果对于每一个 $n$ ,都输出 $f(n)$ 的话,那么 MLE 之外,还有可能代码超过最大代码长度限制,导致编译前不通过(代码可能直接被 pass)
+    规定 $f(x)$ 为整数 $x$ 的二进制表示中 $1$ 的个数。输入一个正整数 $n$ ( $n\leq 10^9$ ),输出 $\sum_{i=1}^n f^2(i)$ 
 
-我们考虑优化这个答案表,借用分块思想,我们设置一个合理的步长 $m$ (这个步长一般视代码长度而定),对于第 $i$ 块,输出:
+如果对于每一个 $n$ ,都输出 $f(n)$ 的话,除了可能会 MLE 外,还有可能代码超过最大代码长度限制,导致编译不通过。
+
+我们考虑优化这个答案表。采用 [分块](../ds/decompose/) 的思想,我们设置一个合理的步长 $m$ (这个步长一般视代码长度而定),对于第 $i$ 块,计算出:
 
 $$
-\Large \sum_{k=\frac{n}{m}(i-1)+1}^{\frac{ni}{m}} f^2(k)
+\sum_{k=\frac{n}{m}(i-1)+1}^{\frac{ni}{m}} f^2(k)
 $$
 
 的值。
 
-然后输出答案时借用分块思想处理即可
+然后输出答案时采用分块思想处理即可。即,整块的答案用预处理的值计算,非整块的答案暴力计算
 
 一般来说,这样的问题对于处理单个函数值 $f(x)$ 很快,但是需要大量函数值求和(求积或某些可以快速合并的操作),枚举会超出时间限制,在找不到标准做法的情况下,分段打表是一个不错的选择。
 
-### 注意事项
+???+note "注意事项"
 
-1.  当上题中指数不是定值,但是范围较小,也可以考虑打表;
-2.  上题是本人为了介绍分段打表口胡出来的,如已有此题纯属巧合。
+    当上题中指数不是定值,但是范围较小,也可以考虑打表。
 
 ### 例题
 
- [「BZOJ 3798」特殊的质数](https://www.lydsy.com/JudgeOnline/problem.php?id=3798) :权限题……~~不过可以在各大 BZ 离线题库中看到。~~
-
- [题意简述](https://www.zhihu.com/question/60674478/answer/180805562) :求 $[l,r]$ 区间内有多少个质数可以分解为两个正整数的平方和。——via PoPoQQQ
-
- [「Luogu P1822」魔法指纹](https://www.luogu.org/problem/show?pid=P1822) :其实是一道暴搜,不过可以练练分段打表。
+ [「BZOJ 3798」特殊的质数](https://www.lydsy.com/JudgeOnline/problem.php?id=3798) :求 $[l,r]$ 区间内有多少个质数可以分解为两个正整数的平方和。
 
-~~明明是我先写的分段打表为什么你们这么熟练 QAQ,可以对比下 [我的题解](https://blog.csdn.net/HeRaNO/article/details/78379324) 的发布时间和 Luogu 中的。~~
+ [「Luogu P1822」魔法指纹](https://www.luogu.org/problem/show?pid=P1822) 
index 96b14a2..207baff 100644 (file)
@@ -14,7 +14,7 @@ author: hsfzLZH1, sshwy, StudyingFather, TrisolarisHD
 
  $\varphi(x)=\sum_{i=1}^x 1[\gcd(x,i)=1]$ 
 
- $\mu(x)=\begin{cases}1&\text{n=1}\\(-1)^k& \ \prod_{i=1}^k q_i=1\\0 &\ \max\{q_i\}>1\end{cases}$ 
+ $\mu(x)=\begin{cases}1&\ x=1 \\(-1)^k& \ \prod_{i=1}^k q_i=1\\0 &\ \max\{q_i\}>1\end{cases}$ 
 
 积性函数有如下性质:
 
@@ -71,7 +71,7 @@ $$
 
 ## 问题一
 
-??? note "[P4213【模板】杜教筛(Sum)](https://www.luogu.org/problemnew/show/P4213)"
+???+note "[P4213【模板】杜教筛(Sum)](https://www.luogu.org/problemnew/show/P4213)"
     题目大意:求 $S_1(n)= \sum_{i=1}^{n} \mu(i)$ 和 $S_2(n)= \sum_{i=1}^{n} \varphi(i)$ 的值, $n\le 2^{31} -1$ 。
 
 ### 莫比乌斯函数前缀和
@@ -121,73 +121,72 @@ $$
 \end{split}
 $$
 
-### 代码实现
-
-```cpp
-#include <algorithm>
-#include <cstdio>
-#include <cstring>
-#include <map>
-using namespace std;
-const int maxn = 2000010;
-typedef long long ll;
-ll T, n, pri[maxn], cur, mu[maxn], sum_mu[maxn];
-bool vis[maxn];
-map<ll, ll> mp_mu;
-ll S_mu(ll x) {
-  if (x < maxn) return sum_mu[x];
-  if (mp_mu[x]) return mp_mu[x];
-  ll ret = 1ll;
-  for (ll i = 2, j; i <= x; i = j + 1) {
-    j = x / (x / i);
-    ret -= S_mu(x / i) * (j - i + 1);
-  }
-  return mp_mu[x] = ret;
-}
-ll S_phi(ll x) {
-  ll ret = 0ll;
-  for (ll i = 1, j; i <= x; i = j + 1) {
-    j = x / (x / i);
-    ret += (S_mu(j) - S_mu(i - 1)) * (x / i) * (x / i);
-  }
-  return ((ret - 1) >> 1) + 1;
-}
-int main() {
-  scanf("%lld", &T);
-  mu[1] = 1;
-  for (int i = 2; i < maxn; i++) {
-    if (!vis[i]) {
-      pri[++cur] = i;
-      mu[i] = -1;
+??? note "代码实现"
+    ```cpp
+    #include <algorithm>
+    #include <cstdio>
+    #include <cstring>
+    #include <map>
+    using namespace std;
+    const int maxn = 2000010;
+    typedef long long ll;
+    ll T, n, pri[maxn], cur, mu[maxn], sum_mu[maxn];
+    bool vis[maxn];
+    map<ll, ll> mp_mu;
+    ll S_mu(ll x) {
+      if (x < maxn) return sum_mu[x];
+      if (mp_mu[x]) return mp_mu[x];
+      ll ret = 1ll;
+      for (ll i = 2, j; i <= x; i = j + 1) {
+        j = x / (x / i);
+        ret -= S_mu(x / i) * (j - i + 1);
+      }
+      return mp_mu[x] = ret;
+    }
+    ll S_phi(ll x) {
+      ll ret = 0ll;
+      for (ll i = 1, j; i <= x; i = j + 1) {
+        j = x / (x / i);
+        ret += (S_mu(j) - S_mu(i - 1)) * (x / i) * (x / i);
+      }
+      return ((ret - 1) >> 1) + 1;
     }
-    for (int j = 1; j <= cur && i * pri[j] < maxn; j++) {
-      vis[i * pri[j]] = true;
-      if (i % pri[j])
-        mu[i * pri[j]] = -mu[i];
-      else {
-        mu[i * pri[j]] = 0;
-        break;
+    int main() {
+      scanf("%lld", &T);
+      mu[1] = 1;
+      for (int i = 2; i < maxn; i++) {
+        if (!vis[i]) {
+          pri[++cur] = i;
+          mu[i] = -1;
+        }
+        for (int j = 1; j <= cur && i * pri[j] < maxn; j++) {
+          vis[i * pri[j]] = true;
+          if (i % pri[j])
+            mu[i * pri[j]] = -mu[i];
+          else {
+            mu[i * pri[j]] = 0;
+            break;
+          }
+        }
       }
+      for (int i = 1; i < maxn; i++) sum_mu[i] = sum_mu[i - 1] + mu[i];
+      while (T--) {
+        scanf("%lld", &n);
+        printf("%lld %lld\n", S_phi(n), S_mu(n));
+      }
+      return 0;
     }
-  }
-  for (int i = 1; i < maxn; i++) sum_mu[i] = sum_mu[i - 1] + mu[i];
-  while (T--) {
-    scanf("%lld", &n);
-    printf("%lld %lld\n", S_phi(n), S_mu(n));
-  }
-  return 0;
-}
-```
+    ```
 
 ## 问题二
 
-??? note "[「LuoguP3768」简单的数学题](https://www.luogu.org/problemnew/show/P3768)"
+???+note "[「LuoguP3768」简单的数学题](https://www.luogu.org/problemnew/show/P3768)"
     大意:求
-
+    
     $$
     \sum_{i=1}^n\sum_{j=1}^ni\cdot j\cdot\gcd(i,j)\pmod p
     $$
-
+    
     其中 $n\leq 10^{10},5\times 10^8\leq p\leq 1.1\times 10^9$ , $p$ 是质数。
 
 利用 $\varphi\ast1=ID$ 做莫比乌斯反演化为
@@ -236,72 +235,71 @@ S(n)&=\sum_{i=1}^n\left((ID^2\varphi)\ast ID^2\right)(i)-\sum_{i=2}^nID^2(i)S\le
 \end{split}
 $$
 
-非常友好的式子啊,分块求解即可
-
-### 代码实现
-
-```cpp
-#include <cmath>
-#include <cstdio>
-#include <map>
-using namespace std;
-const int N = 5e6, NP = 5e6, SZ = N;
-long long n, P, inv2, inv6, s[N];
-int phi[N], p[NP], cnt, pn;
-bool bp[N];
-map<long long, long long> s_map;
-long long ksm(long long a, long long m) {  // 求逆元用
-  long long res = 1;
-  while (m) {
-    if (m & 1) res = res * a % P;
-    a = a * a % P, m >>= 1;
-  }
-  return res;
-}
-void prime_work(int k) {  // 线性筛 phi,s
-  bp[0] = bp[1] = 1, phi[1] = 1;
-  for (int i = 2; i <= k; i++) {
-    if (!bp[i]) p[++cnt] = i, phi[i] = i - 1;
-    for (int j = 1; j <= cnt && i * p[j] <= k; j++) {
-      bp[i * p[j]] = 1;
-      if (i % p[j] == 0) {
-        phi[i * p[j]] = phi[i] * p[j];
-        break;
-      } else
-        phi[i * p[j]] = phi[i] * phi[p[j]];
+分块求解即可
+
+??? note "代码实现"
+    ```cpp
+    #include <cmath>
+    #include <cstdio>
+    #include <map>
+    using namespace std;
+    const int N = 5e6, NP = 5e6, SZ = N;
+    long long n, P, inv2, inv6, s[N];
+    int phi[N], p[NP], cnt, pn;
+    bool bp[N];
+    map<long long, long long> s_map;
+    long long ksm(long long a, long long m) {  // 求逆元用
+      long long res = 1;
+      while (m) {
+        if (m & 1) res = res * a % P;
+        a = a * a % P, m >>= 1;
+      }
+      return res;
+    }
+    void prime_work(int k) {  // 线性筛 phi,s
+      bp[0] = bp[1] = 1, phi[1] = 1;
+      for (int i = 2; i <= k; i++) {
+        if (!bp[i]) p[++cnt] = i, phi[i] = i - 1;
+        for (int j = 1; j <= cnt && i * p[j] <= k; j++) {
+          bp[i * p[j]] = 1;
+          if (i % p[j] == 0) {
+            phi[i * p[j]] = phi[i] * p[j];
+            break;
+          } else
+            phi[i * p[j]] = phi[i] * phi[p[j]];
+        }
+      }
+      for (int i = 1; i <= k; i++)
+        s[i] = (1ll * i * i % P * phi[i] % P + s[i - 1]) % P;
+    }
+    long long s3(long long k) {
+      return k %= P, (k * (k + 1) / 2) % P * ((k * (k + 1) / 2) % P) % P;
+    }  // 立方和
+    long long s2(long long k) {
+      return k %= P, k * (k + 1) % P * (k * 2 + 1) % P * inv6 % P;
+    }  // 平方和
+    long long calc(long long k) {  // 计算 S(k)
+      if (k <= pn) return s[k];
+      if (s_map[k]) return s_map[k];  // 对于超过 pn 的用 map 离散存储
+      long long res = s3(k), pre = 1, cur;
+      for (long long i = 2, j; i <= k; i = j + 1)
+        j = k / (k / i), cur = s2(j),
+        res = (res - calc(k / i) * (cur - pre) % P) % P, pre = cur;
+      return s_map[k] = (res + P) % P;
+    }
+    long long solve() {
+      long long res = 0, pre = 0, cur;
+      for (long long i = 1, j; i <= n; i = j + 1)
+        j = n / (n / i), cur = calc(j),
+        res = (res + (s3(n / i) * (cur - pre)) % P) % P, pre = cur;
+      return (res + P) % P;
     }
-  }
-  for (int i = 1; i <= k; i++)
-    s[i] = (1ll * i * i % P * phi[i] % P + s[i - 1]) % P;
-}
-long long s3(long long k) {
-  return k %= P, (k * (k + 1) / 2) % P * ((k * (k + 1) / 2) % P) % P;
-}  // 立方和
-long long s2(long long k) {
-  return k %= P, k * (k + 1) % P * (k * 2 + 1) % P * inv6 % P;
-}  // 平方和
-long long calc(long long k) {  // 计算 S(k)
-  if (k <= pn) return s[k];
-  if (s_map[k]) return s_map[k];  // 对于超过 pn 的用 map 离散存储
-  long long res = s3(k), pre = 1, cur;
-  for (long long i = 2, j; i <= k; i = j + 1)
-    j = k / (k / i), cur = s2(j),
-    res = (res - calc(k / i) * (cur - pre) % P) % P, pre = cur;
-  return s_map[k] = (res + P) % P;
-}
-long long solve() {
-  long long res = 0, pre = 0, cur;
-  for (long long i = 1, j; i <= n; i = j + 1)
-    j = n / (n / i), cur = calc(j),
-    res = (res + (s3(n / i) * (cur - pre)) % P) % P, pre = cur;
-  return (res + P) % P;
-}
-int main() {
-  scanf("%lld%lld", &P, &n);
-  inv2 = ksm(2, P - 2), inv6 = ksm(6, P - 2);
-  pn = (long long)pow(n, 0.666667);  // n^(2/3)
-  prime_work(pn);
-  printf("%lld", solve());
-  return 0;
-}  // 不要为了省什么内存把数组开小...... 卡了好几次 80
-```
+    int main() {
+      scanf("%lld%lld", &P, &n);
+      inv2 = ksm(2, P - 2), inv6 = ksm(6, P - 2);
+      pn = (long long)pow(n, 0.666667);  // n^(2/3)
+      prime_work(pn);
+      printf("%lld", solve());
+      return 0;
+    }  // 不要为了省什么内存把数组开小...... 卡了好几次 80
+    ```
index d0b65fb..a831baa 100644 (file)
@@ -6,9 +6,23 @@
 
 利用唯一分解定理,我们可以把一个整数唯一地分解为质数幂次的乘积,
 
-设 $n = p_1^{k_1}p_2^{k_2} \cdots p_s^{k_s}$ ,其中 $p_i$ 是质数,那么定义 $\varphi(n) = n \times \prod_{i = 1}^s{\frac{p_i - 1}{p_i}}$ 
+设 $n = \prod_{i=1}^{n}p_i^{k_i}$ ,其中 $p_i$ 是质数,那么 $\varphi(n) = n \times \prod_{i = 1}^s{\dfrac{p_i - 1}{p_i}}$ 
 
-## 欧拉函数的一些神奇性质
+#### 证明:
+
+引理(1):设 $x=p^k$ , 那么 $\varphi(x)=p^{k-1}\times(p-1)$ 
+
+证明:
+
+容易发现 $x\perp y (y\bmod p \ne 0)$ 。我们试着将 $x$ 划分为长度为 $p$ 的 $\dfrac{p^k}{p}=p^{k-1}$ 段,每一段都有 $p-1$ 个数与 $x$ 互质。所以与 $x$ 互质的数个数即为: $p^{k-1}\times(p-1)$ 
+
+接下来我们证明 $\varphi(n) = n \times \prod_{i = 1}^s{\dfrac{p_i - 1}{p_i}}$ 
+
+$$
+\because n=\prod_{i=1}^{n} p_i^{k_i} \\        \begin{align}\therefore \varphi(x) &= \prod_{i=1}^{n} \varphi(p_i^{k_i}) \\&= \prod_{i=1}^{n} (p_i-1)\times {p_i}^{k_i-1}\\&=\prod_{i=1}^{n} {p_i}^{k_i} \times(1 - \frac{1}{p_i})\\&=x~ \prod_{i=1}^{n} (1- \frac{1}{p_i})\end{align}
+$$
+
+## 欧拉函数的一些性质
 
 -   欧拉函数是积性函数。
 
@@ -31,7 +45,7 @@
 
 ## 如何求欧拉函数值
 
-如果只要求一个数的欧拉函数值,那么直接根据定义质因数分解的同时求就好了。
+如果只要求一个数的欧拉函数值,那么直接根据定义质因数分解的同时求就好了。这个过程可以用_Pollard Rho_算法优化。
 
 ```cpp
 int euler_phi(int n) {
index 7577be0..c409177 100644 (file)
@@ -4,6 +4,42 @@
 
 另一个形式:对于任意整数 $a$ ,有 $a^p \equiv a \pmod{p}$ 。
 
+## 费马小定理
+
+定理:( $p$ 为质数, $p\nmid a$ )
+
+$$
+a^{p-1}\equiv1\pmod p
+$$
+
+### 证明
+
+设一个质数为 $p$ ,我们取一个不为 $p$ 倍数的数 $a$ 。
+
+构造一个序列: $A=\{1,2,3\dots,p-1\}$ ,这个序列有着这样一个性质:
+
+$$
+\prod_{i=1}^{n}\space A_i\equiv\prod_{i=1}^{n} (A_i\times a) \pmod p
+$$
+
+证明:
+
+$$
+\because (A_i,p)=1,(A_i\times a,p)=1
+$$
+
+又因为每一个 $A_i\times a \pmod p$ 都是独一无二的,且 $A_i\times a \pmod p < p$ 
+
+得证(每一个 $A_i\times a$ 都对应了一个 $A_i$ )
+
+设 $f=(p-1)!$ , 则 $f\equiv a\times A_1\times a\times A_2\times a \times A_3 \dots \times  A_{p-1} \pmod p$ 
+
+$$
+a^{p-1}\times f \equiv f \pmod p \\    a^{p-1} \equiv 1 \pmod p
+$$
+
+证毕。
+
 ## 欧拉定理
 
 在了解欧拉定理(Euler's theorem)之前,请先了解 [欧拉函数](./euler.md) 。定理内容如下:
@@ -12,6 +48,8 @@
 
 ### 证明
 
+实际上这个证明过程跟上文费马小定理的证明过程是非常相似的: **构造一个与 $m$ 互质的数列** ,再进行操作。
+
 设 $r_1, r_2, \cdots, r_{\varphi(m)}$ 为模 $m$ 意义下的一个简化剩余系,则 $ar_1, ar_2, \cdots, ar_{\varphi(m)}$ 也为模 $m$ 意义下的一个简化剩余系。所以 $r_1r_2 \cdots r_{\varphi(m)} \equiv ar_1 \cdot ar_2 \cdots ar_{\varphi(m)} \equiv a^{\varphi(m)}r_1r_2 \cdots r_{\varphi(m)} \pmod{m}$ ,可约去 $r_1r_2 \cdots r_{\varphi(m)}$ ,即得 $a^{\varphi(m)} \equiv 1 \pmod{m}$ 。
 
 当 $m$ 为素数时,由于 $\varphi(m) = m - 1$ ,代入欧拉定理可立即得到费马小定理。
index a7cb4d4..b74add6 100644 (file)
@@ -282,85 +282,86 @@ $$
 0 & 1 & -2 \end{vmatrix} = 4
 $$
 
-附一个冗长的复杂的令人难过的高斯消元与 Matrix Tree 计数代码:
-
-```cpp
-#include <algorithm>
-#include <cassert>
-#include <cmath>
-#include <cstdio>
-#include <cstring>
-#include <iostream>
-using namespace std;
-#define MOD 100000007
-#define eps 1e-7
-struct matrix {
-  static const int maxn = 20;
-  int n, m;
-  double mat[maxn][maxn];
-  matrix() { memset(mat, 0, sizeof(mat)); }
-  void print() {
-    cout << "MATRIX " << n << " " << m << endl;
-    for (int i = 0; i < n; i++) {
-      for (int j = 0; j < m; j++) {
-        cout << mat[i][j] << "\t";
-      }
-      cout << endl;
-    }
-  }
-  void random(int n) {
-    this->n = n;
-    this->m = n;
-    for (int i = 0; i < n; i++)
-      for (int j = 0; j < n; j++) mat[i][j] = rand() % 100;
-  }
-  void initSquare() {
-    this->n = 4;
-    this->m = 4;
-    memset(mat, 0, sizeof(mat));
-    mat[0][1] = mat[0][3] = 1;
-    mat[1][0] = mat[1][2] = 1;
-    mat[2][1] = mat[2][3] = 1;
-    mat[3][0] = mat[3][2] = 1;
-    mat[0][0] = mat[1][1] = mat[2][2] = mat[3][3] = -2;
-    this->n--;  //去一行
-    this->m--;  //去一列
-  }
-  double gauss() {
-    double ans = 1;
-    for (int i = 0; i < n; i++) {
-      int sid = -1;
-      for (int j = i; j < n; j++)
-        if (abs(mat[j][i]) > eps) {
-          sid = j;
-          break;
-        }
-      if (sid == -1) continue;
-      if (sid != i) {
-        for (int j = 0; j < n; j++) {
-          swap(mat[sid][j], mat[i][j]);
-          ans = -ans;
+可以用高斯消元解决,时间复杂度为 $O(n^3)$ 。
+
+??? note "参考代码"
+    ```cpp
+    #include <algorithm>
+    #include <cassert>
+    #include <cmath>
+    #include <cstdio>
+    #include <cstring>
+    #include <iostream>
+    using namespace std;
+    #define MOD 100000007
+    #define eps 1e-7
+    struct matrix {
+      static const int maxn = 20;
+      int n, m;
+      double mat[maxn][maxn];
+      matrix() { memset(mat, 0, sizeof(mat)); }
+      void print() {
+        cout << "MATRIX " << n << " " << m << endl;
+        for (int i = 0; i < n; i++) {
+          for (int j = 0; j < m; j++) {
+            cout << mat[i][j] << "\t";
+          }
+          cout << endl;
         }
       }
-      for (int j = i + 1; j < n; j++) {
-        double ratio = mat[j][i] / mat[i][i];
-        for (int k = 0; k < n; k++) {
-          mat[j][k] -= mat[i][k] * ratio;
+      void random(int n) {
+        this->n = n;
+        this->m = n;
+        for (int i = 0; i < n; i++)
+          for (int j = 0; j < n; j++) mat[i][j] = rand() % 100;
+      }
+      void initSquare() {
+        this->n = 4;
+        this->m = 4;
+        memset(mat, 0, sizeof(mat));
+        mat[0][1] = mat[0][3] = 1;
+        mat[1][0] = mat[1][2] = 1;
+        mat[2][1] = mat[2][3] = 1;
+        mat[3][0] = mat[3][2] = 1;
+        mat[0][0] = mat[1][1] = mat[2][2] = mat[3][3] = -2;
+        this->n--;  //去一行
+        this->m--;  //去一列
+      }
+      double gauss() {
+        double ans = 1;
+        for (int i = 0; i < n; i++) {
+          int sid = -1;
+          for (int j = i; j < n; j++)
+            if (abs(mat[j][i]) > eps) {
+              sid = j;
+              break;
+            }
+          if (sid == -1) continue;
+          if (sid != i) {
+            for (int j = 0; j < n; j++) {
+              swap(mat[sid][j], mat[i][j]);
+              ans = -ans;
+            }
+          }
+          for (int j = i + 1; j < n; j++) {
+            double ratio = mat[j][i] / mat[i][i];
+            for (int k = 0; k < n; k++) {
+              mat[j][k] -= mat[i][k] * ratio;
+            }
+          }
         }
+        for (int i = 0; i < n; i++) ans *= mat[i][i];
+        return abs(ans);
       }
+    };
+    int main() {
+      srand(1);
+      matrix T;
+      // T.random(2);
+      T.initSquare();
+      T.print();
+      double ans = T.gauss();
+      T.print();
+      cout << ans << endl;
     }
-    for (int i = 0; i < n; i++) ans *= mat[i][i];
-    return abs(ans);
-  }
-};
-int main() {
-  srand(1);
-  matrix T;
-  // T.random(2);
-  T.initSquare();
-  T.print();
-  double ans = T.gauss();
-  T.print();
-  cout << ans << endl;
-}
-```
+    ```
index e9875b0..7fcf856 100644 (file)
@@ -62,17 +62,17 @@ int gcd(int a, int b) {
 
 用数学公式来表示就是 $x = p_1^{k_1}p_2^{k_2} \cdots p_s^{k_s}$ 
 
-设 $a = p_{a_1}^{k_{a_1}}p_{a_2}^{k_{a_2}} \cdots p_{a_s}^{k_{a_s}}$ , $b = p_{b_1}^{k_{b_1}}p_{b_2}^{k_{b_2}} \cdots p_{b_s}^{k_{b_s}}$ 
+设 $a = p_1^{k_{a_1}}p_2^{k_{a_2}} \cdots p_s^{k_{a_s}}$ , $b = p_1^{k_{b_1}}p_2^{k_{b_2}} \cdots p_s^{k_{b_s}}$ 
 
 我们发现,对于 $a$ 和 $b$ 的情况,二者的最大公约数等于
 
- $p_1^{k_{\min(a_1, b_1)}}p_2^{k_{\min(a_2, b_2)}} \cdots p_s^{k_{\min(a_s, b_s)}}$ 
+ $p_1^{\min(k_{a_1}, k_{b_1})}p_2^{\min(k_{a_2}, k_{b_2})} \cdots p_s^{\min(k_{a_s}, k_{b_s})}$ 
 
 最小公倍数等于
 
- $p_1^{k_{\max(a_1, b_1)}}p_2^{k_{\max(a_2, b_2)}} \cdots p_s^{k_{\max(a_s, b_s)}}$ 
+ $p_1^{\max(k_{a_1}, k_{b_1})}p_2^{\max(k_{a_2}, k_{b_2})} \cdots p_s^{\max(k_{a_s}, k_{b_s})}$ 
 
-由于 $a + b = \max(a, b) + \min(a, b)$ 
+由于 $k_a + k_b = \max(k_a, k_b) + \min(k_a, k_b)$ 
 
 所以得到结论是 $\gcd(a, b) \times \operatorname{lcm}(a, b) = a \times b$ 
 
index 87d429c..2699a9f 100644 (file)
@@ -110,17 +110,17 @@ $$
 
 ### 定义
 
-定义两个数论函数 $f,g$ 的 $\text{Dirichlet}$ 卷积为
+定义两个数论函数 $f,g$ 的 Dirichlet 卷积为
 
 $$
-(f*g)(n)=\sum_{d\mid n}f(d)g(\frac{n}{d})
+(f\ast g)(n)=\sum_{d\mid n}f(d)g(\frac{n}{d})
 $$
 
 ### 性质
 
- $\text{Dirichlet}$ 卷积满足交换律和结合律。
+Dirichlet 卷积满足交换律和结合律。
 
-其中 $\varepsilon$ 为 $\text{Dirichlet}$ 卷积的单位元(任何函数卷 $\varepsilon$ 都为其本身)
+其中 $\varepsilon$ 为 Dirichlet 卷积的单位元(任何函数卷 $\varepsilon$ 都为其本身)
 
 ### 例子
 
@@ -139,11 +139,7 @@ $$
 
 ### 定义
 
- $\mu$ 为莫比乌斯函数
-
-### 性质
-
-莫比乌斯函数不但是积性函数,还有如下性质:
+ $\mu$ 为莫比乌斯函数,定义为
 
 $$
 \mu(n)=
@@ -154,23 +150,36 @@ $$
 \end{cases}
 $$
 
-### 证明
+详细解释一下:
+
+令 $n=\prod_{i=1}^kp_i^{c_i}$ ,其中 $p_i$ 为质因子, $c_i\ge 1$ 。上述定义表示:
+
+1.   $n=1$ 时, $\mu(n)=1$ ;
+2.  对于 $n\not= 1$ 时:
+    1.  当存在 $i\in [1,k]$ ,使得 $c_i > 1$ 时, $\mu(n)=0$ ,也就是说只要某个质因子出现的次数超过一次, $\mu(n)$ 就等于 $0$ ;
+    2.  当任意 $i\in[1,k]$ ,都有 $c_i=1$ 时, $\mu(n)=(-1)^k$ ,也就是说每个质因子都仅仅只出现过一次时,即 $n=\prod_{i=1}^kp_i$ , $\{p_i\}_{i=1}^k$ 中个元素唯一时, $\mu(n)$ 等于 $-1$ 的 $k$ 次幂,此处 $k$ 指的便是仅仅只出现过一次的质因子的总个数。
+
+### 性质
+
+莫比乌斯函数不但是积性函数,还有如下性质:
 
 $$
-\varepsilon(n)=
+\sum_{d\mid n}\mu(d)=
 \begin{cases}
 1&n=1\\
 0&n\neq 1\\
 \end{cases}
 $$
 
-其中 $\displaystyle\varepsilon(n)=\sum_{d\mid n}\mu(d)$ 即 $\varepsilon=\mu*1$ 
+即 $\sum_{d\mid n}\mu(d)=\varepsilon(n)$ ,即 $\mu * 1 =\varepsilon$ 
+
+### 证明
 
 设 $\displaystyle n=\prod_{i=1}^k{p_i}^{c_i},n'=\prod_{i=1}^k p_i$ 
 
-那么 $\displaystyle\sum_{d\mid n}\mu(d)=\sum_{d\mid n'}\mu(d)=\sum_{i=0}^k C_k^i\cdot(-1)^k$ 
+那么 $\displaystyle\sum_{d\mid n}\mu(d)=\sum_{d\mid n'}\mu(d)=\sum_{i=0}^k C_k^i\cdot(-1)^i=(1+(-1))^k$ 
 
-根据二项式定理,易知该式子的值在 $k=0$ 即 $n=1$ 时值为 $1$ 否则为 $0$ ,这也同时证明了 $\displaystyle\sum_{d\mid n}\mu(d)=[n=1]$ 
+根据二项式定理,易知该式子的值在 $k=0$ 即 $n=1$ 时值为 $1$ 否则为 $0$ ,这也同时证明了 $\displaystyle\sum_{d\mid n}\mu(d)=[n=1]=\varepsilon(n)$ 以及 $\mu\ast 1=\varepsilon
 
 ### 补充结论
 
@@ -258,13 +267,13 @@ $$
 \sum_{d\mid n}\mu(d)f(\frac{n}{d})=\sum_{d\mid n}\mu(d)\sum_{k\mid \frac{n}{d}}g(k)=\sum_{k\mid n}g(k)\sum_{d\mid \frac{n}{k}}\mu(d)=g(n)
 $$
 
-用 $\displaystyle\sum_{d\mid n}g(d)$ 来替换 $f(\dfrac{n}{d})$ ,再变换求和顺序。最后一步转为的依据: $\displaystyle\sum_{d\mid n}\mu(d)=[n=1]$ ,因此在 $\dfrac{n}{k}=1$ 时第二个和式的值才为 $1$ 。此时 $n=k$ ,故原式等价于 $\displaystyle\sum_{k\mid n}[n=k]\cdot g(k)=g(n)$ 
+用 $\displaystyle\sum_{d\mid n}g(d)$ 来替换 $f(\dfrac{n}{d})$ ,再变换求和顺序。最后一步变换的依据: $\displaystyle\sum_{d\mid n}\mu(d)=[n=1]$ ,因此在 $\dfrac{n}{k}=1$ 时第二个和式的值才为 $1$ 。此时 $n=k$ ,故原式等价于 $\displaystyle\sum_{k\mid n}[n=k]\cdot g(k)=g(n)$ 
 
 方法二:运用卷积。
 
-原问题为:已知 $f=g*1$ ,证明 $g=f*\mu$ 
+原问题为:已知 $f=g\ast1$ ,证明 $g=f\ast\mu$ 
 
-易知如下转化: $f*\mu=g*1*\mu\implies f*\mu=g$ (其中 $1*\mu=\varepsilon$ )
+易知如下转化: $f\ast\mu=g*1*\mu\implies f\ast\mu=g$ (其中 $1\ast\mu=\varepsilon$ )。
 
 * * *
 
@@ -305,17 +314,16 @@ $$
 变换求和顺序,先枚举 $d\mid gcd(i,j)$ 可得
 
 $$
-\displaystyle\sum_{d=1}^{\lfloor\frac{n}{k}\rfloor}\mu(d)\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}d\mid i\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}d\mid j
+\displaystyle\sum_{d=1}\mu(d)\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}[d\mid i]\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[d\mid j]
 $$
 
-(其中 $d\mid i$ 表示 $i$ 是 $d$ 的倍数时对答案有 $1$ 的贡献)
 易知 $1\sim\lfloor\dfrac{n}{k}\rfloor$ 中 $d$ 的倍数有 $\lfloor\dfrac{n}{kd}\rfloor$ 个,故原式化为
 
 $$
-\displaystyle\sum_{d=1}^{\lfloor\frac{n}{k}\rfloor}\mu(d) \lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor
+\displaystyle\sum_{d=1}\mu(d)\lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor
 $$
 
-很显然,式子可以数论分块求解(注意:过程中默认 $n\leqslant m$ )
+很显然,式子可以数论分块求解。
 
  **时间复杂度 $\Theta(N+T\sqrt{n})$ ** 
 
@@ -380,13 +388,19 @@ $$
 \sum_{i=1}^n \frac{i\cdot n}{\gcd(i,n)}
 $$
 
-根据 $\gcd(a,n)=1$ 时一定有 $\gcd(n-a,n)=1$ ,可将原式化为
+将原式复制一份并且颠倒顺序,然后将 n 一项单独提出,可得
 
 $$
 \frac{1}{2}\cdot \left(\sum_{i=1}^{n-1}\frac{i\cdot n}{\gcd(i,n)}+\sum_{i=n-1}^{1}\frac{i\cdot n}{\gcd(i,n)}\right)+n
 $$
 
-上述式子中括号内的两个 $\sum$ 对应的项相等,故又可以化为
+根据 $gcd(i,n)=gcd(n-i,n)$ ,可将原式化为
+
+$$
+\frac{1}{2}\cdot \left(\sum_{i=1}^{n-1}\frac{i\cdot n}{\gcd(i,n)}+\sum_{i=n-1}^{1}\frac{i\cdot n}{\gcd(n-i,n)}\right)+n
+$$
+
+两个求和式中分母相同的项可以合并。
 
 $$
 \frac{1}{2}\cdot \sum_{i=1}^{n-1}\frac{n^2}{\gcd(i,n)}+n
@@ -412,41 +426,44 @@ $$
 \frac{1}{2}n\cdot\left(\sum_{d'\mid n}d'\cdot\varphi(d')+1\right)
 $$
 
-设 $\displaystyle \text{g}(n)=\sum_{d\mid n} d\cdot\varphi(d)$ ,已知 $\text{g}$ 为积性函数,于是可以 $\Theta(n)$ 预处理。最后枚举 $d$ ,统计贡献即可。
+设 $\displaystyle \text{g}(n)=\sum_{d\mid n} d\cdot\varphi(d)$ ,已知 $\text{g}$ 为积性函数,于是可以 $\Theta(n)$ 筛出。每次询问 $\Theta(1)$ 计算即可。
 
- **时间复杂度** : $\Theta(n\log n)$ 
+这个函数筛的时候比较特殊,当 $p_j\mid i$ 的时候,需要根据 $p_j\mid\dfrac{i}{p_j}$ 进行分类讨论。具体可以见代码。
+
+ **时间复杂度** : $\Theta(n+T)$ 
 
 ??? note "代码实现"
     ```cpp
     #include <cstdio>
     const int N = 1000000;
-    int tot, p[N + 5], phi[N + 5];
-    long long ans[N + 5];
+    int tot, p[N + 5];
+    long long g[N + 5];
     bool flg[N + 5];
     
     void solve() {
-      phi[1] = 1;
+      g[1] = 1;
       for (int i = 2; i <= N; ++i) {
-        if (!flg[i]) p[++tot] = i, phi[i] = i - 1;
+        if (!flg[i]) p[++tot] = i, g[i] = i * (i - 1) + 1;
         for (int j = 1; j <= tot && i * p[j] <= N; ++j) {
           flg[i * p[j]] = 1;
           if (i % p[j] == 0) {
-            phi[i * p[j]] = phi[i] * p[j];
+            if ((i / p[j]) % p[j] == 0) {
+              g[i * p[j]] = g[i] + (g[i] - g[i / p[j]]) * p[j] * p[j];
+            } else {
+              g[i * p[j]] = g[i] + g[i / p[j]] * (p[j] - 1) * p[j] * p[j] * p[j];
+            }
             break;
           }
-          phi[i * p[j]] = phi[i] * (p[j] - 1);
+          g[i * p[j]] = g[i] * g[p[j]];
         }
       }
-      for (int i = 1; i <= N; ++i)
-        for (int j = 1; i * j <= N; ++j) ans[i * j] += 1LL * j * phi[j] / 2;
-      for (int i = 1; i <= N; ++i) ans[i] = 1LL * i * ans[i] + i;
     }
     int main() {
       int T, n;
       solve();
       for (scanf("%d", &T); T; --T) {
         scanf("%d", &n);
-        printf("%lld\n", ans[n]);
+        printf("%lld\n", (g[n] + 1) * n / 2);
       }
       return 0;
     }
@@ -522,7 +539,7 @@ $$
 
 本题除了推式子比较复杂、代码细节较多之外,是一道很好的莫比乌斯反演练习题!(上述过程中,默认 $n\leqslant m$ )
 
-时间复杂度: $\Theta(n+m)$ (两次数论分块
+时间复杂度: $\Theta(n+m)$ (瓶颈为线性筛
 
 ??? note "代码实现"
     ```cpp
@@ -634,7 +651,7 @@ S\left(\left\lfloor\frac{m}{p}\right\rfloor\right)
 \end{split}
 $$
 
-那么 $O(n)$ 预处理 $\mu,d$ 的前缀和, $O(\sqrt{n})$ 分块处理询问,总复杂度 $O(n\sqrt{n})$ .
+那么 $O(n)$ 预处理 $\mu,d$ 的前缀和, $O(\sqrt{n})$ 分块处理询问,总复杂度 $O(n+T\sqrt{n})$ .
 
 ??? note "代码实现"
     ```cpp
@@ -721,7 +738,7 @@ $$
 \end{split}
 $$
 
-杜教筛(见 [杜教筛 - 例 3](https://sshwy.gitee.io/2019/01/11/5071/) )完了是这样的
+杜教筛(见 [杜教筛 - 例 3](../du/#_8) )完了是这样的
 
 $$
 S(n)=\left(\frac{1}{2}n(n+1)\right)^2-\sum_{i=2}^ni^2S\left(\left\lfloor\frac{n}{i}\right\rfloor\right)\\
@@ -847,7 +864,7 @@ $$
 
 ## 莫比乌斯反演扩展
 
-结尾补一个不常用的莫比乌斯反演非卷积形式的公式
+结尾补充一个莫比乌斯反演的非卷积形式。
 
 对于数论函数 $f,g$ 和完全积性函数 $t$ 且 $t(1)=1$ :
 
index ebe4ca1..921fb87 100644 (file)
@@ -51,7 +51,7 @@ int isqrt_newton(int n) {
   bool decreased = false;
   for (;;) {
     int nx = (x + n / x) >> 1;
-    if (x == nx || nx > x && decreased) break;
+    if (x == nx || (nx > x && decreased)) break;
     decreased = nx < x;
     x = nx;
   }
index 9386b4e..c41cede 100644 (file)
 author: AndrewWayne, GavinZhengOI. ChungZH, henryrabbit, Xeonacid, sshwy, Yukimaikoriya
 
-(本页面部分内容转载自 [桃酱的算法笔记](https://zhuanlan.zhihu.com/c_1005817911142838272) ,原文戳 [链接](https://zhuanlan.zhihu.com/p/41867199) ,已获得作者授权)
+前置知识: [复数](../complex.md) 。
 
-一直想学 FFT,之前牛客的多校有一道组合数学就用 FFT 写的,而且当时还傻乎乎的用唯一分解定理,但是自己好久没静下心学什么了,而且自己的数学功底又不好,导致一直学不会。看了很多人的博客也没看明白,尤其是原根。在我看了几十篇博客之后终于看懂了……所以想写一篇能够让大多数人都看得懂的教程。花费时间 3 天终于写完啦~~~~\~~
+本文将介绍一种算法,它支持在 $O(n\log n)$ 的时间内计算两个 $n$ 度的多项式的乘法,比朴素的 $O(n^2)$ 算法更高效。由于两个整数的乘法也可以被当作多项式乘法,因此这个算法也可以用来加速大整数的乘法计算。
 
-另外,本文 FFT 部分的代码实现全部参考 kuangbin 的模板(2018.7 更新)资源地址如下
+## 概述
 
- <https://download.csdn.net/download/qq_37136305/10562410> 
+离散傅里叶变换(Discrete Fourier Transform,缩写为 DFT),是傅里叶变换在时域和频域上都呈离散的形式,将信号的时域采样变换为其 DTFT 的频域采样。
 
-NTT 部分代码参考 CSDN 上的模板代码附网址,感谢博主!
+FFT 是一种高效实现 DFT 的算法,称为快速傅立叶变换(Fast Fourier Transform,FFT)。它对傅里叶变换的理论并没有新的发现,但是对于在计算机系统或者说数字系统中应用离散傅立叶变换,可以说是进了一大步。快速数论变换 (NTT) 是快速傅里叶变换(FFT)在数论基础上的实现。
 
-你搜索这个关键词就已经知道这一是个数学的东西了。只想学会用很简单,但是这远远不够。所以在看这个博客之前应该先学一下 [复数](../complex.md) 的基本知识
+在 1965 年,Cooley 和 Tukey 发表了快速傅里叶变换算法。事实上 FFT 早在这之前就被发现过了,但是在当时现代计算机并未问世,人们没有意识到 FFT 的重要性。一些调查者认为 FFT 是由 Runge 和 König 在 1924 年发现的。但事实上高斯早在 1805 年就发明了这个算法,但一直没有发表
 
-好了下面进入正文。
+## 多项式的表示
 
-## DFT IDFT FFT 官方定义?
+### 系数表示法
 
-> 离散傅里叶变换(Discrete Fourier Transform,缩写为 DFT),是傅里叶变换在时域和频域上都呈离散的形式,将信号的时域采样变换为其 DTFT 的频域采样。
->
-> FFT 是一种 DFT 的高效算法,称为快速傅立叶变换(Fast Fourier transform)。——百度百科
-
-在百度百科上能找到 DFT 和 FFT 这两个定义。正如定义,FFT 和 DFT 实际上按照结果来看的话是一样的,但是 FFT 比较快的计算 DFT 和 IDFT(离散反傅里叶变换)。
-
-快速数论变换 (NTT) 是快速傅里叶变换(FFT)在数论基础上的实现。
-
-是不是有点迷?既然是官方定义那肯定不能让你看懂才对嘛~下面我们一一解释~
-
-## 为什么要使用 FFT?
-
-我们在这里引入一个例子:求多项式乘积的朴素算法。
-
-大家平时求 $f(x)=a_1x^2+b_1x+c_1$ 与 $g(x) = a_2x^2+b_2x+c_2$ 的乘积时候,是怎么进行的呢?
-
-我们令
+系数表示法就是用一个多项式的各个项系数来表达这个多项式,即使用一个系数序列来表示多项式:
 
 $$
-K(x) = f(x)  \times  g(x) = a_1x^2 \times a_2x^2+a_1x^2 \times b_2x+a_1x^2 \times c_2+b_1x \times b_2x^2+b_1x \times b_2x+b_1x \times c_2+c_1 \times a_2x^2+c_1 \times b_2x+c_1 \times c_2
+f(x) = a_0+a_1x+a_2x^2+\cdots +a_{n}x^{n} \Leftrightarrow f(x) = \{a_0, a_1, \cdots,a_{n}\}
 $$
 
-那么很显然我们进行了 9 次运算,复杂度是 $O(n^2)$ (具体代码实现不再展开)
-
-但是如果数字足够大呢?比如 100000?那朴素算法可太慢啦!
+### 点值表示法
 
-## 什么是 FFT
+点值表示法是把这个多项式看成一个函数,从上面选取 $n+1$ 个点,从而利用这 $n+1$ 个点来唯一的表示这个函数。
 
-FFT,即为快速傅氏变换,是离散傅氏变换的快速算法,它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。它对傅氏变换的理论并没有新的发现,但是对于在计算机系统或者说数字系统中应用离散傅立叶变换,可以说是进了一大步。——360 百科
-
-如果上一个例子用朴素算法太慢啦!所以我们要用 FFT 进行优化,复杂度会降为 $O(n\log n)$ 
-
-### 多项式的系数表示法与点值表示法
-
-一个多项式,我们可以怎样来表示呢?
-
-系数表示法就是用一个多项式的各个项系数来表达这个多项式。比如:
-
-$$
-f(x) = a_1x^2+b_1x+c_1 \Leftrightarrow f(x) = \{a_1, b_1, c_1\}
-$$
+为什么用 $n+1$ 个点就能唯一的表示这个函数了呢?想一下高斯消元法,两点确定一条直线。再来一个点,能确定这个直线中的另一个参数,那么也就是说 $n+1$ 个点能确定 $n$ 个参数(不考虑倍数点之类的没用点)。
 
-点值表示法是把这个多项式看成一个函数,从上面选取 $n+1$ 个点,从而利用这 $n+1$ 个点来唯一的表示这个函数。为什么用 $n+1$ 个点就能唯一的表示这个函数了呢?想一下高斯消元法,两点确定一条直线。再来一个点,能确定这个直线中的另一个参数,那么也就是说 $n+1$ 个点能确定 $n$ 个参数(不考虑倍数点之类的没用点)。如下:
+设
 
 $$
 \begin{array}{c}
-f_1(x) = y_1 = a_0 + a_1x_1+a_2x_1^2+a_3x_1^3+ \cdots + a_nx_1^n\\
-f_2(x) = y_2 = a_0 + a_1x_2+a_2x_2^2+a_3x_2^3+ \cdots + a_nx_2^n\\
-f_3(x) = y_3 = a_0 + a_1x_3+a_2x_3^2+a_3x_3^3+ \cdots + a_nx_3^n\\
+f(x_0) = y_0 = a_0 + a_1x_0+a_2x_0^2+a_3x_0^3+ \cdots + a_nx_0^n\\
+f(x_1) = y_1 = a_0 + a_1x_1+a_2x_1^2+a_3x_1^3+ \cdots + a_nx_1^n\\
+f(x_2) = y_2 = a_0 + a_1x_2+a_2x_2^2+a_3x_2^3+ \cdots + a_nx_2^n\\
 \vdots\\
-f_{n+1}(x) = y_{n+1} = a_0 + a_1x_{n+1}+a_2x_{n+1}^2+a_3x_{n+1}^3+ \cdots + a_nx_{n+1}^n
+f(x_{n}) = y_{n} = a_0 + a_1x_{n}+a_2x_{n}^2+a_3x_{n}^3+ \cdots + a_nx_{n}^n
 \end{array}
 $$
 
-一个非常通俗易懂的解释:
+那么用点值表示法表示 $f(x)$ 如下
 
-多项式由系数表示法转为点值表示法的过程,就成为 DFT;
-
-相对地,把一个多项式的点值表示法转化为系数表示法的过程,就是 IDFT。
-
-而 FFT 就是通过取某些特殊的 $x$ 的点值来加速 DFT 和 FFT 的过程。
-
-### 复数的引入
-
-复数分为实数和虚数。实数就是我们日常最常用的有理数和无理数。大家记得我们在开始学平方的时候,老师会说所有数的平方大于等于 $0$ 对不对,那么虚数就引入了。虚数一般用 $i$ 表示,对于虚数 $i$ ,有 $i=\sqrt{-1}$ 
-
-。另外, $i$ 对于虚数的意义,与 $1$ 对于实数的意义是一样的。如果我说得不够明确,你可以看下面我引用的百科说明。
-
-> 在数学中,虚数就是形如 $a+b \times i$ 的数,其中 $a,b$ 是实数,且 $b \neq 0$ , $i^2 = - 1$ 。虚数这个名词是 17 世纪著名数学家笛卡尔创立,因为当时的观念认为这是真实不存在的数字。后来发现虚数 $a+b \times i$ 的实部 $a$ 可对应平面上的横轴,虚部 $b$ 与对应平面上的纵轴,这样虚数 $a+b \times i$ 可与平面内的点 $(a,b)$ 对应。
->
-> 可以将虚数 $bi$ 添加到实数 $a$ 以形成形式 $a + bi$ 的复数,其中实数 $a$ 和 $b$ 分别被称为复数的实部和虚部。一些作者使用术语纯虚数来表示所谓的虚数,虚数表示具有非零虚部的任何复数。——百度百科
-
-我们用一幅图来表示复数与复平面的关系(图源百度百科)
-
-![img](./images/fft1.jpg)
-
-其中横坐标是实数轴,纵坐标是虚数轴,这样就可以把每个虚数看为一个向量了,对应的,虚数可以用普通坐标和极坐标 $(r,\theta)$ (其中 $r$ 为虚数长度, $\theta$ 为虚数和实数轴正半轴夹角)来表示。
-
-接下来思考两个复数相乘是什么意义:
-
-1.   $(a+bi) \times (c+di) = (ac-bd) + (ad+bc)i$ 
-
-2.  长度相乘,角度相加: $(r_1, \theta_1)  \times  (r_2, \theta_2) = (r_1 \times r_2, \theta_1+\theta_2)$ 
-
-这么一看的话,我们很容易想到如果两个长度为 $1$ 的不同方向向量相乘,结果向量是不是一个长度依然为 $1$ 的新向量呢?
+$$
+f(x) = a_0+a_1x+a_2x^2+\cdots +a_{n}x^{n} \Leftrightarrow f(x) = \{(x_0,y_0),(x_1,y_1), \cdots,(x_n,y_{n})\}
+$$
 
-### 单位复根的引入
+通俗地说,多项式由系数表示法转为点值表示法的过程,就是 DFT 的过程。相对地,把一个多项式的点值表示法转化为系数表示法的过程,就是 IDFT。而 FFT 就是通过取某些特殊的 $x$ 的点值来加速 DFT 和 FFT 的过程。
 
-我们回到之前的问题:多项式(点值表示法)的乘积。
+## 单位复根
 
 考虑这样一个问题:
 
-刚刚说到了 DFT 是把多项式从系数表示转到了点值表示(复杂度为 $O(n)$ ),那么我们把点值相乘之后(选取相应位置,并且复杂度为 $O(n)$ ),如果能够快速还原成系数表示,是不是就完美解决我们的问题了呢?上述过程如下:
+DFT 是把多项式从系数表示转到了点值表示,那么我们把点值相乘之后,如果能够快速还原成系数表示,是不是就完美解决我们的问题了呢?上述过程如下:
 
 假设我们 DFT 过程对于两个多项式选取的 $x$ 序列相同,那么可以得到
 
 $$
-f(x)={(x_0, f(x_0), (x_1, f(x_1)), (x_2, f(x_2), \cdots, (x_n, f(x_n)))}
+f(x)={(x_0, f(x_0)), (x_1, f(x_1)), (x_2, f(x_2)), \cdots, (x_n, f(x_n))}\\
+g(x)={(x_0, g(x_0)), (x_1, g(x_1)), (x_2, g(x_2)), \cdots, (x_n, g(x_n))}
 $$
 
-$$
-g(x)={(x_0, g(x_0), (x_1, g(x_1)), (x_2, g(x_2), \cdots, (x_n, g(x_n)))}
-$$
-
-如果我们设 $F(x) = f(x) \times g(x)$ 
-
-那么很容易得到 $F(x)$ 的点值表达式:
+如果我们设 $F(x) = f(x) \cdot g(x)$ ,那么很容易得到 $F(x)$ 的点值表达式:
 
 $$
-F(x) = {(x_0, f(x_0)  \times  g(x_0), (x_1, f(x_1)  \times  g(x_1)), (x_2, f(x_2)  \times  g(x_2), \cdots, (x_n, f(x_n)  \times  g(x_n)))}
+F(x) = \{(x_0, f(x_0)g(x_0)), (x_1, f(x_1)g(x_1)), (x_2, f(x_2)g(x_2)), \cdots, (x_n, f(x_n)g(x_n))\}
 $$
 
 但是我们要的是系数表达式,接下来问题变成了从点值回到系数。如果我们带入到高斯消元法的方程组中去,会把复杂度变得非常高。光是计算 $x^i(0 \leq i \leq n)$ 就是 $n$ 项,这就已经 $O(n^2)$ 了,更别说还要把 $n+1$ 个方程进行消元……
 
-这里会不会觉得我们不去计算 $x^i$ 比较好呢? $1$ 和 $-1$ 的幂都很好算,但是也仅仅有两个不够啊,我们至少需要 $n+1$ 个 那怎么办呢!想到我们刚刚学的长度为 $1$ 的虚数了吗?不管怎么乘长度都是 $1$ !对就是它!我们需要的是 $\omega^k=1$ 中的 $\omega$ ,很容易想到 $-i$ 和 $1$ 是符合的。那其他的呢?
+这里会不会觉得我们不去计算 $x^i$ 比较好呢? $1$ 和 $-1$ 的幂都很好算,但是也仅仅有两个不够啊,我们至少需要 $n+1$ 个。想到我们刚刚学的长度为 $1$ 的虚数了吗?不管怎么乘长度都是 $1$ 。我们需要的是 $\omega^k=1$ 中的 $\omega$ ,很容易想到 $-i$ 和 $1$ 是符合的。那其他的呢?
 
 ![img](./images/fft2.jpg)
 
-现在我们看上图的圆圈。容易发现这是一个单位圆(圆心为原点,半径为 $1$ ),所有在圆上的复数的长度均为 $1$ ,也就是说它不管做多少次方 $r$ 永远为 $1$ ,结果也仅仅角度的变化而已。但是!进过旋转总会让角度 $\bmod 360 = 0$ 成立的,也就是结果为 $1$ 。我们把符合以上条件的复数成为复根,用 $\omega$ 表示。如果 $\omega^k=1$ 那么我们把 $\omega$ 称为 $1$ 的 $k$ 次复根,记作 $\omega_k^n$ (因为符合这个 $k$ 次之后等于 $1$ 的复数有很多,比如 $i$ 的 $4k$ 次幂永远为 $1$ ,所以,这个 $n$ 是一个编号,表示这是角度从小到大的第几个(从 $x$ 的正半轴开始逆时针))
+现在我们看上图的圆圈。容易发现这是一个单位圆(圆心为原点,半径为 $1$ ),单位圆上的向量模长均为 $1$ ,根据复数的运算法则,两个复数相乘,在复平面上表示为两个向量模长相乘,辐角相加。因此两个模长为 $1$ 的向量相乘,得到的仍是模长为 $1$ 的向量,辐角为两个向量辐角的和。因此我们可以将 $\omega^k=1$ 中的 $\omega$ 理解为复平面上的一个单位向量,满足它的辐角的 $k$ 倍恰好是 $360^\circ$ ——即把圆周 $k$ 等分的角。我们把符合以上条件的复数(复平面上的向量)称为复根,用 $\omega$ 表示。
 
-是不是有点雾啊,没事没事接下来我们举个栗子:
+### 定义
 
-![img](./images/fft3.jpg)
+严谨地,我们称 $x^n=1$ 在复数意义下的解是 $n$ 次复根。显然,这样的解有 $n$ 个,设 $\omega_n=e^{\frac{2\pi i}{n}}$ ,则 $x^n=1$ 的解集表示为 $\{w_n^k\mid k=0,1\cdots,n-1\}$ 。我们称 $w_n$ 是 $n$ 次单位复根(The $n$ -th roots of unity)。根据复平面的知识, $n$ 次单位复根是复平面把单位圆 $n$ 等分的第一个角所对应的向量。其他复根均可以用单位复根的幂表示。
 
-那么很容易发现当 $K = 4$ 的时候,相当于把单位圆等分 $K= 4$ 份。然后每一份按照极角编号。那么是不是(在 $K = 4$ 的时候)我们只要知道 $\omega_4^1$ 
+另一方面,根据欧拉公式,还可以得到 $\omega_n=e^{\frac{2\pi i}{n}}=\cos\left(\dfrac{2\pi i}{n}\right)+i\cdot \sin\left(\dfrac{2\pi i}{n}\right)$ 。
 
-(因为他的角度是相当于单位角度),就能知道 $\omega_4^0, \omega_4^1, \omega_4^2, \omega_4^3$ 了呢?当然是这样的……
+举个例子,当 $n=4$ 时, $w_n=i$ ,即 $i$ 就是 $4$ 次单位复根:
 
- $\omega_4^0$ 恒等于 $1$ , $\omega_4^2$ 的角度是 $\omega_4^0$ 的两倍,所以 $\omega_4^2 = (\omega_4^1)^2 = i^2=-1$ ,依次以此类推。
+![img](./images/fft3.jpg)
 
-因此,我们只要知道 $\omega_k^1$ ,就能求出 $\omega_k^n$ 。所以我们把 $\omega_k^1$ 称为单位复根,简写为 $\omega_k$ 
+那么很容易发现当 $n = 4$ 的时候,相当于把单位圆等分 $n= 4$ 份。然后每一份按照极角编号。那么是不是(在 $n = 4$ 的时候)我们只要知道 $\omega_4^1$ (因为他的角度是相当于单位角度),就能知道 $\omega_4^0, \omega_4^1, \omega_4^2, \omega_4^3$ 。
 
-## FFT 的流程
+ $\omega_4^0$ 恒等于 $1$ , $\omega_4^2$ 的角度是 $\omega_4^0$ 的两倍,所以 $\omega_4^2 = (\omega_4^1)^2 = i^2=-1$ ,依次以此类推。
 
-终于写到核心部分了,也就是,FFT 到底怎么来写呢?
+### 性质
 
-### FFT 流程第一步之 DFT(共两步)
+单位复根有三个重要的性质。对于任意正整数 $n$ 和整数 $k$ :
 
-FFT 之所以快,是因为他采用了分治的思想。
+$$
+\omega_n^n=1\\
+\omega_n^k=\omega_{2n}^{2k}\\
+\omega_{2n}^{k+n}=-\omega_{2n}^k\\
+$$
 
-就 DFT(将系数表达转换成点值表达)来说,它分治的来求当当前的 $x=\omega_n^k$ 
+## 快速傅里叶变换
 
-的时候整个式子的值。他的分治思想体现在将多项式分为奇次项和偶次项处理。
+FFT 算法的基本思想是分治。就 DFT 来说,它分治地来求当 $x=\omega_n^k$ 的时候 $f(x)$ 的值。他的分治思想体现在将多项式分为奇次项和偶次项处理。
 
-对于一共 $8$ 项的多项式
+举个例子,对于一共 $8$ 项的多项式
 
 $$
-f(x0) = y_1 = a_0 + a_1x + a_2x^2+a_3x^3+a_4x^4+a_5x^5+a_6x^6+a_7x^7
+f(x) = a_0 + a_1x + a_2x^2+a_3x^3+a_4x^4+a_5x^5+a_6x^6+a_7x^7
 $$
 
 按照次数的奇偶来分成两组,然后右边提出来一个 $x$ 
 
 $$
-f(x) = (a_0+a_2x^2+a_4x^4+a_6x^6) + (a_1x+a_3x^3+a_5x^5+a_7x^7)
-$$
-
-$$
-f(x) = (a_0+a_2x^2+a_4x^4+a_6x^6) + x(a_1+a_3x^2+a_5x^4+a_7x^6)
+\begin{split}
+f(x) &= (a_0+a_2x^2+a_4x^4+a_6x^6) + (a_1x+a_3x^3+a_5x^5+a_7x^7)\\
+     &= (a_0+a_2x^2+a_4x^4+a_6x^6) + x(a_1+a_3x^2+a_5x^4+a_7x^6)
+\end{split}
 $$
 
-分别用奇偶次次项数建立新的方程
+分别用奇偶次次项数建立新的函数
 
 $$
-G(x) = a_0+a_2x+a_4x^2+a_6x^3
+G(x) = a_0+a_2x+a_4x^2+a_6x^3\\
+H(x)=a_1+a_3x+a_5x^2+a_7x^3
 $$
 
+那么原来的 $f(x)$ 用新函数表示为
+
 $$
-H(x)=a_1+a_3x+a_5x^2+a_7x^3
+F(x)=G\left(x^2\right) + x  \times  H\left(x^2\right)
 $$
 
-那么原来的 $f(x)$ 由新函数来表示(是不是我们二分了一个多项式呢~)
+利用单位复根的性质得到
 
 $$
-F(x)=G(x^2) + x  \times  H(x^2)
+\begin{split}
+\operatorname{DFT}(f(\omega_n^k))
+&=\operatorname{DFT}(G((\omega_n^k)^2)) + \omega_n^k  \times \operatorname{DFT}(H((\omega_n^k)^2))\\
+&=\operatorname{DFT}(G(\omega_n^{2k})) + \omega_n^k  \times \operatorname{DFT}(H(\omega_n^{2k}))\\
+&=\operatorname{DFT}(G(\omega_{n/2}^k)) + \omega_n^k  \times \operatorname{DFT}(H(\omega_{n/2}^k))
+\end{split}
 $$
 
-给函数带个帽子表示此时在进行的是 DFT 过程,把 x 代进去,即有
+同理可得
 
 $$
-DFT(f(\omega_n^k))=DFT(G((\omega_n^k)^2)) + \omega_n^k  \times  DFT(H((\omega_n^k)^2))
+\begin{split}
+\operatorname{DFT}(f(\omega_n^{k+n/2}))
+&=\operatorname{DFT}(G(\omega_n^{2k+n})) + \omega_n^{k+n/2}  \times \operatorname{DFT}(H(\omega_n^{2k+n}))\\
+&=\operatorname{DFT}(G(\omega_n^{2k})) - \omega_n^k  \times \operatorname{DFT}(H(\omega_n^{2k}))\\
+&=\operatorname{DFT}(G(\omega_{n/2}^k)) - \omega_n^k  \times \operatorname{DFT}(H(\omega_{n/2}^k))
+\end{split}
 $$
 
-!前方高能:
+因此我们求出了 $\operatorname{DFT}(G(\omega_{n/2}^k))$ 和 $\operatorname{DFT}(H(\omega_{n/2}^k))$ 后,就可以同时求出 $\operatorname{DFT}(f(\omega_n^k))$ 和 $\operatorname{DFT}(f(\omega_n^{k+n/2}))$ 。于是对 $G$ 和 $H$ 分别递归 DFT 即可。
 
¿\99个å\87½æ\95°è\83½å¤\84ç\90\86ç\9a\84å¤\9a项å¼\8fé\95¿åº¦å\8fªè\83½æ\98¯ $2^m$ ( $m \in N^ \ast$ )ï¼\8cå\90¦å\88\99å\9c¨å\88\86æ²»ç\9a\84æ\97¶å\80\99å·¦å\8f³ä¸\8dä¸\80æ ·é\95¿ï¼\8cå\8f³è¾¹å\8f\96ä¸\8då\88°ç³»æ\95°äº\86ï¼\8cç¨\8båº\8f没æ³\95è¿\9bè¡\8cã\80\82æ\89\80以è¦\81å\9c¨ç¬¬ä¸\80次 DFT ä¹\8bå\89\8då°±æ\8a\8aåº\8få\88\97å\90\91ä¸\8aè¡¥æ\88\90é\95¿åº¦ä¸º $2^m$ ( $m \in N^ \ast$ )ï¼\88é«\98次系æ\95°è¡¥ $0$ ï¼\89ã\80\81æ\9c\80é«\98项次æ\95°ä¸º $n-1$ ç\9a\84å¤\9a项å¼\8fã\80\82ä¸\80å®\9aè¦\81é¢\84å¤\84ç\90\86å\93¦
\80\83è\99\91å\88°å\88\86æ²» DFT è\83½å¤\84ç\90\86ç\9a\84å¤\9a项å¼\8fé\95¿åº¦å\8fªè\83½æ\98¯ $2^m(m \in N^ \ast )$ ï¼\8cå\90¦å\88\99å\9c¨å\88\86æ²»ç\9a\84æ\97¶å\80\99å·¦å\8f³ä¸\8dä¸\80æ ·é\95¿ï¼\8cå\8f³è¾¹å°±å\8f\96ä¸\8då\88°ç³»æ\95°äº\86ã\80\82æ\89\80以è¦\81å\9c¨ç¬¬ä¸\80次 DFT ä¹\8bå\89\8då°±æ\8a\8aåº\8få\88\97å\90\91ä¸\8aè¡¥æ\88\90é\95¿åº¦ä¸º $2^m(m \in N^\ast )$ ï¼\88é«\98次系æ\95°è¡¥ $0$ ï¼\89ã\80\81æ\9c\80é«\98项次æ\95°ä¸º $2^m-1$ ç\9a\84å¤\9a项å¼\8f
 
-然后我在代入值的时候,因为要代入 $n$ 个不同值,所以我们就代入 $\omega_n^0,\omega_n^1,\omega_n^2,\cdots, \omega_n^{n-1} (n=2^m(m \in N^ \times ))$ 
+在代入值的时候,因为要代入 $n$ 个不同值,所以我们代入 $\omega_n^0,\omega_n^1,\omega_n^2,\cdots, \omega_n^{n-1} (n=2^m(m \in N^ \ast ))$ 一共 $2^m$ 个不同值。
 
¸\80å\85± $2^m$ ä¸ªä¸\8då\90\8cå\80¼
»£ç \81å®\9eç\8e°æ\96¹é\9d¢ï¼\8cSTL æ\8f\90ä¾\9bäº\86è\99\9aæ\95°ç\9a\84模æ\9d¿ï¼\8cå½\93ç\84¶ä¹\9få\8f¯ä»¥æ\89\8bå\8a¨å®\9eç\8e°ã\80\82两è\80\85å\8cºå\88«å\9c¨äº\8eï¼\8c使ç\94¨ STL ç\9a\84 `complex` å\8f¯ä»¥è°\83ç\94¨ `exp` å\87½æ\95°æ±\82å\87º $\omega_n$ ã\80\82ä½\86äº\8bå®\9eä¸\8a使ç\94¨æ¬§æ\8b\89å\85¬å¼\8få¾\97å\88°ç\9a\84è\99\9aæ\95°æ\9d¥æ±\82 $\omega_n$ ä¹\9fæ\98¯ç­\89ä»·ç\9a\84
 
-```cpp
-/*
- * 做 FFT
- *len 必须是 2^k 形式
- *on == 1 时是 DFT,on == -1 时是 IDFT
- */
-void fft(Complex y[], int len, int on) {
-  change(y, len);
-  for (int h = 2; h <= len; h <<= 1) {
-    Complex wn(cos(2 * PI / h), sin(on * 2 * PI / h));
-    for (int j = 0; j < len; j += h) {
-      Complex w(1, 0);
-      for (int k = j; k < j + h / 2; k++) {
-        Complex u = y[k];
-        Complex t = w * y[k + h / 2];
-        y[k] = u + t;
-        y[k + h / 2] = u - t;
-        w = w * wn;
+???+ note "递归版 FFT"
+    ```cpp
+    #include <cmath>
+    #include <complex>
+    
+    typedef std::complex<double> Comp;  // STL complex
+    
+    const Comp I(0, 1);  // i
+    const int MAX_N = 1 << 20;
+    
+    Comp tmp[MAX_N];
+    
+    void DFT(Comp *f, int n, int rev) {  // rev=1,DFT; rev=-1,IDFT
+      if (n == 1) return;
+      for (int i = 0; i < n; ++i) tmp[i] = f[i];
+      for (int i = 0; i < n; ++i) {  //偶数放左边,奇数放右边
+        if (i & 1)
+          f[n / 2 + i / 2] = tmp[i];
+        else
+          f[i / 2] = tmp[i];
+      }
+      Comp *g = f, *h = f + n / 2;
+      DFT(g, n / 2, rev), DFT(h, n / 2, rev);  //递归DFT
+      Comp cur(1, 0), step(cos(2 * M_PI / n), sin(2 * M_PI * rev / n));
+      // Comp step=exp(I*(2*M_PI/n*rev));//两个step定义是等价的
+      for (int k = 0; k < n / 2; ++k) {
+        tmp[k] = g[k] + cur * h[k];
+        tmp[k + n / 2] = g[k] - cur * h[k];
+        cur *= step;
       }
+      for (int i = 0; i < n; ++i) f[i] = tmp[i];
     }
-  }
-}
-```
+    ```
+
+时间复杂度 $O(n\log n)$ 。
 
-但是这个算法还需要从“分治”的角度继续优化。我们每一次都会把整个多项式的奇数次项和偶数次项系数分开,一只分到只剩下一个系数。但是,这个递归的过程需要更多的内存。因此,我们可以先“模仿递归”把这些系数在原数组中“拆分”,然后再“倍增”地去合并这些算出来的值。然而我们又要如何去拆分这些数呢?
+### 蝴蝶变换
+
+这个算法还可以从“分治”的角度继续优化。我们每一次都会把整个多项式的奇数次项和偶数次项系数分开,一只分到只剩下一个系数。但是,这个递归的过程需要更多的内存。因此,我们可以先“模仿递归”把这些系数在原数组中“拆分”,然后再“倍增”地去合并这些算出来的值。然而我们又要如何去拆分这些数呢?
 
 设初始序列为 $\{x_0, x_1, x_2, x_3, x_4, x_5, x_6, x_7\}$ 
 
@@ -240,73 +209,70 @@ void fft(Complex y[], int len, int on) {
 
 三次二分之后 $\{x_0\}\{x_4\}\{x_2\}\{x_6\}\{x_1\}\{x_5\}\{x_3\}\{x_7 \}$ 
 
-有啥规律呢?其实就是原来的那个序列,每个数用二进制表示,然后把二进制翻转对称一下,就是最终那个位置的下标。比如 $x_1$ 是 001,翻转是 100,也就是 4,而且最后那个位置确实是 4,是不是很神奇啊\~\~~
-
-这里附上代码
-
-```cpp
-/*
- * 进行 FFT 和 IFFT 前的反置变换
- * 位置 i 和 i 的二进制反转后的位置互换
- *len 必须为 2 的幂
- */
-void change(Complex y[], int len) {
-  int i, j, k;
-  for (int i = 1, j = len / 2; i < len - 1; i++) {
-    if (i < j) swap(y[i], y[j]);
-    // 交换互为小标反转的元素,i<j 保证交换一次
-    // i 做正常的 + 1,j 做反转类型的 + 1,始终保持 i 和 j 是反转的
-    k = len / 2;
-    while (j >= k) {
-      j = j - k;
-      k = k / 2;
+有啥规律呢?其实就是原来的那个序列,每个数用二进制表示,然后把二进制翻转对称一下,就是最终那个位置的下标。比如 $x_1$ 是 001,翻转是 100,也就是 4,而且最后那个位置确实是 4。我们称这个变换为蝴蝶变换。根据它的定义,我们可以在 $O(n\log n)$ 的时间内求出每个数蝴蝶变换的结果:
+
+???+ note "蝴蝶变换实现"
+    ```cpp
+    /*
+     * 进行 FFT 和 IFFT 前的反置变换
+     * 位置 i 和 i 的二进制反转后的位置互换
+     *len 必须为 2 的幂
+     */
+    void change(Complex y[], int len) {
+      int i, j, k;
+      for (int i = 1, j = len / 2; i < len - 1; i++) {
+        if (i < j) swap(y[i], y[j]);
+        // 交换互为小标反转的元素,i<j 保证交换一次
+        // i 做正常的 + 1,j 做反转类型的 + 1,始终保持 i 和 j 是反转的
+        k = len / 2;
+        while (j >= k) {
+          j = j - k;
+          k = k / 2;
+        }
+        if (j < k) j += k;
+      }
     }
-    if (j < k) j += k;
-  }
-}
-```
+    ```
 
-### FFT 流程第二步之 IDFT(共两步)
+## 快速傅里叶逆变换
 
 这一步 IDFT(傅里叶反变换)的作用我说的已经很清楚啦,就是把上一步获得的目标多项式的点值形式转换成系数形式。但是似乎并不简单呢……但是,我们把单位复根代入多项式之后,就是下面这个样子(矩阵表示方程组)
 
 $$
- \begin{bmatrix}y[0] \\ y[1] \\ y[2] \\ y[3] \\ \dots \\ y[n-1] \end{bmatrix}
-\begin{matrix}= \\ = \\ = \\ = \\ \\ = \end{matrix}
-\begin{bmatrix}1 & 1 & 1 & 1 & \dots & 1 \\
-1 & \omega_n^1 & \omega_n^2 & \omega_n^3 & \dots & \omega_n^{n-1} \\
-1 & \omega_n^2 & \omega_n^4 & \omega_n^6 & \dots & \omega_n^{2(n-1)} \\
-1 & \omega_n^3 & \omega_n^6 & \omega_n^9 & \dots & \omega_n^{3(n-1)} \\
-\dots & \dots & \dots & \dots & \dots & \dots \\
-1 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \omega_n^{3(n-1)} & \dots & \omega_n^{(n-1)^2} \end{bmatrix}
-\begin{bmatrix} a[0] \\ a[1] \\ a[2] \\ a[3] \\ \dots \\ a[n-1] \end{bmatrix}
+\begin{bmatrix}y_0 \\ y_1 \\ y_2 \\ y_3 \\ \vdots \\ y_{n-1} \end{bmatrix}
+=
+\begin{bmatrix}1 & 1 & 1 & 1 & \cdots & 1 \\
+1 & \omega_n^1 & \omega_n^2 & \omega_n^3 & \cdots & \omega_n^{n-1} \\
+1 & \omega_n^2 & \omega_n^4 & \omega_n^6 & \cdots & \omega_n^{2(n-1)} \\
+1 & \omega_n^3 & \omega_n^6 & \omega_n^9 & \cdots & \omega_n^{3(n-1)} \\
+\vdots & \vdots & \vdots & \vdots & \ddots & \vdots \\
+1 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \omega_n^{3(n-1)} & \cdots & \omega_n^{(n-1)^2} \end{bmatrix}
+\begin{bmatrix} a_0 \\ a_1 \\ a_2 \\ a_3 \\ \vdots \\ a_{n-1} \end{bmatrix}
 $$
 
-而且现在我们已经得到最左边的结果了,中间的 $x$ 值在目标多项式的点值表示中也是一一对应的,所以,根据矩阵的基础知识,我们只要在式子两边左乘中间那个大矩阵的逆矩阵就行了。由于这个矩阵的元素非常特殊,他的逆矩阵也有特殊的性质,就是每一项取倒数,再除以 $n$ ,就能得到他的逆矩阵(这边根据的是单位原根的两个特殊性质推出来的,具体比较麻烦。如果想知道的话私我吧。)
+而且现在我们已经得到最左边的结果了,中间的 $x$ 值在目标多项式的点值表示中也是一一对应的,所以,根据矩阵的基础知识,我们只要在式子两边左乘中间那个大矩阵的逆矩阵就行了。由于这个矩阵的元素非常特殊,他的逆矩阵也有特殊的性质,就是每一项取倒数,再除以 $n$ ,就能得到他的逆矩阵
 
-如何改变我们的操作才能使计算的结果文原来的倒数呢?我们当然可以重新写一遍,但是这里有更简单的实现。这就要看我们求“单位复根的过程了”:根据“欧拉定理” $e^{i\theta} = \cos \theta + i\sin \theta$ ,我么可以得到 $e^{2\pi i}=1$ 。如果我要找到一个数,它的 $k$ 次方 $= 1$ ,那么这个数 $\omega[k]=e^{2\pi \frac{i}{k}}$ (因为 $(e^{2\pi \frac{i}{k}})^k=e^{2\pi i}=1$ )。而如果我要使这个数值变成 $\frac{1}{\omega[k]}$ 也就是 $(\omega[k])^-1$ ,我们可以尝试着把 $π$ 取成 - 3.14159…,这样我们的计算结果就会变成原来的倒数,而其它的操作过程与 DFT 是完全相同的(这真是极好的)。我们可以定义一个函数,向里面掺一个参数 $1$ 或者是 $-1$ ,然后把它乘到 $π$ 的身上。传入 $1$ 就是 DFT,传入 $-1$ 就是 IDFT,十分的智能。
+如何改变我们的操作才能使计算的结果为原来的倒数呢?根据单位复根的性质并结合欧拉公式,可以得到
 
-#### 对 IDFT 操作的证明
+$$
+\frac{1}{\omega_k}=\omega_k^{-1}=e^{-\frac{2\pi i}{k}}=\cos\left(\frac{2\pi i}{k}\right)+i\cdot \sin\left(-\frac{2\pi i}{k}\right)
+$$
 
\8e\9fæ\9c¬ç\9a\84å¤\9a项å¼\8fæ\98¯ $f(x)=a_0+a_1x+a_2x^2+\cdots+a_{n-1}x^{n-1}=\sum_{i=0}^{n-1}a_ix^i$ 
\9b æ­¤æ\88\91们å\8f¯ä»¥å°\9dè¯\95ç\9d\80æ\8a\8a $Ï\80$ å\8f\96æ\88\90 - 3.14159â\80¦ï¼\8cè¿\99æ ·æ\88\91们ç\9a\84计ç®\97ç»\93æ\9e\9cå°±ä¼\9aå\8f\98æ\88\90å\8e\9fæ\9d¥ç\9a\84å\80\92æ\95°ï¼\8cè\80\8cå\85¶å®\83ç\9a\84æ\93\8dä½\9cè¿\87ç¨\8bä¸\8e DFT æ\98¯å®\8cå\85¨ç\9b¸å\90\8cç\9a\84ã\80\82æ\88\91们å\8f¯ä»¥å®\9aä¹\89ä¸\80个å\87½æ\95°ï¼\8cå\9c¨é\87\8cé\9d¢å\8a ä¸\80个å\8f\82æ\95° $1$ æ\88\96è\80\85æ\98¯ $-1$ ï¼\8cç\84¶å\90\8eæ\8a\8aå®\83ä¹\98å\88° $Ï\80$ ç\9a\84身ä¸\8aã\80\82ä¼ å\85¥ $1$ å°±æ\98¯ DFTï¼\8cä¼ å\85¥ $-1$ å°±æ\98¯ IDFTã\80\82
 
-而 IDFT 就是把你变换完成的单位根点值表示还原为系数表示
+### 对 IDFT 操作的证明
 
-这东西怎么做呢?我们考虑 **构造法** 。我们已知 $y[i]=f\left( \omega_n^i \right),i\in\{0,1,\cdots,n-1\}$ ,求 $\{a_0,a_1,\cdots,a_{n-1}\}$ 
+由于上述矩阵的逆矩阵并未给出严格的推理过程,因此这里提供另一种对 IDFT 操作的证明。考虑原本的多项式是 $f(x)=a_0+a_1x+a_2x^2+\cdots+a_{n-1}x^{n-1}=\sum_{i=0}^{n-1}a_ix^i$ 。而 IDFT 就是把你的点值表示还原为系数表示
 
-那么构造多项式如下
+考虑 **构造法** 。我们已知 $y_i=f\left( \omega_n^i \right),i\in\{0,1,\cdots,n-1\}$ ,求 $\{a_0,a_1,\cdots,a_{n-1}\}$ 。构造多项式如下
 
 $$
-A(x)=\sum_{i=0}^{n-1}y[i]x^{i}
+A(x)=\sum_{i=0}^{n-1}y_ix^i
 $$
 
-相当于把 $\{y[0],y[1],y[2],\cdots,y[n-1]\}$ 当做多项式 $A$ 的系数表示法。那么给定点 $b_i=\omega_n^{-i}$ ,则多项式 $A$ 的点值表示法为
+相当于把 $\{y_0,y_1,y_2,\cdots,y_{n-1}\}$ 当做多项式 $A$ 的系数表示法。设 $b_i=\omega_n^{-i}$ ,则多项式 $A$ 在 $x=b_0,b_1,\cdots,b_{n-1}$ 处的点值表示法为 $\left\{ A(b_0),A(b_1),\cdots,A(b_{n-1}) \right\}$ 。
 
-$$
-\left\{ A(b_0),A(b_1),\cdots,A(b_{n-1}) \right\}
-$$
-
-计算 $A(b_k)$ 的值
+对 $A(x)$ 的定义式做一下变换,可以将 $A(b_k)$ 表示为
 
 $$
 \begin{split}
@@ -348,48 +314,50 @@ $$
 也就是说给定点 $b_i=\omega_n^{-i}$ ,则 $A$ 的点值表示法为
 
 $$
-\left\{ A(b_0),A(b_1),\cdots,A(b_{n-1}) \right\}=\left\{ a_0\cdot n,a_1\cdot n,\cdots,a_{n-1}\cdot n \right\}=n\left\{ a_0,a_1,\cdots,a_{n-1}\right\}
-$$
-
-那么事情就很好办啦,我们把取单位根为其倒数,对 $\{y[0],y[1],y[2],\cdots,y[n-1]\}$ 跑一遍 FFT,然后除以 n 即可得到系数序列啦
-
-所以我们 fft 函数可以集 DFT 和 IDFT 于一身。见下
-
-```cpp
-/*
- * 做 FFT
- *len 必须是 2^k 形式
- *on == 1 时是 DFT,on == -1 时是 IDFT
- */
-void fft(Complex y[], int len, int on) {
-  change(y, len);
-  for (int h = 2; h <= len; h <<= 1) {                  // 模拟合并过程
-    Complex wn(cos(2 * PI / h), sin(on * 2 * PI / h));  // 计算当前单位复根
-    for (int j = 0; j < len; j += h) {
-      Complex w(1, 0);  // 计算当前单位复根
-      for (int k = j; k < j + h / 2; k++) {
-        Complex u = y[k];
-        Complex t = w * y[k + h / 2];
-        y[k] = u + t;  // 这就是吧两部分分治的结果加起来
-        y[k + h / 2] = u - t;
-        // 后半个 “step” 中的ω一定和 “前半个” 中的成相反数
-        //“红圈”上的点转一整圈“转回来”,转半圈正好转成相反数
-        // 一个数相反数的平方与这个数自身的平方相等
-        w = w * wn;
+\begin{split}
+&\left\{ (b_0,A(b_0)),(b_1,A(b_1)),\cdots,(b_{n-1},A(b_{n-1})) \right\}\\
+=&\left\{ (b_0,a_0\cdot n),(b_1,a_1\cdot n),\cdots,(b_{n-1},a_{n-1}\cdot n) \right\}
+\end{split}
+$$
+
+综上所述,我们取单位根为其倒数,对 $\{y_0,y_1,y_2,\cdots,y_{n-1}\}$ 跑一遍 FFT,然后除以 $n$ 即可得到 $f(x)$ 的系数序列,这就是 IDFT 操作的过程。
+
+所以我们 FFT 函数可以集 DFT 和 IDFT 于一身。代码实现如下:
+
+???+ note "非递归版 FFT"
+    ```cpp
+    /*
+     * 做 FFT
+     *len 必须是 2^k 形式
+     *on == 1 时是 DFT,on == -1 时是 IDFT
+     */
+    void fft(Complex y[], int len, int on) {
+      change(y, len);
+      for (int h = 2; h <= len; h <<= 1) {                  // 模拟合并过程
+        Complex wn(cos(2 * PI / h), sin(on * 2 * PI / h));  // 计算当前单位复根
+        for (int j = 0; j < len; j += h) {
+          Complex w(1, 0);  // 计算当前单位复根
+          for (int k = j; k < j + h / 2; k++) {
+            Complex u = y[k];
+            Complex t = w * y[k + h / 2];
+            y[k] = u + t;  // 这就是吧两部分分治的结果加起来
+            y[k + h / 2] = u - t;
+            // 后半个 “step” 中的ω一定和 “前半个” 中的成相反数
+            //“红圈”上的点转一整圈“转回来”,转半圈正好转成相反数
+            // 一个数相反数的平方与这个数自身的平方相等
+            w = w * wn;
+          }
+        }
+      }
+      if (on == -1) {
+        for (int i = 0; i < len; i++) {
+          y[i].x /= len;
+        }
       }
     }
-  }
-  if (on == -1) {
-    for (int i = 0; i < len; i++) {
-      y[i].x /= len;
-    }
-  }
-}
-```
-
-好了现在附上全部代码( [HDU 1402](http://acm.hdu.edu.cn/showproblem.php?pid=1402) ),序言说过代码来自 kuangbin 的模板~~~~~
+    ```
 
-??? "FFT"
+??? "FFT 模板( [HDU 1402](http://acm.hdu.edu.cn/showproblem.php?pid=1402) )"
     ```cpp
     #include <cmath>
     #include <cstdio>
@@ -492,12 +460,12 @@ void fft(Complex y[], int len, int on) {
     }
     ```
 
-至此,FFT 算是告一段落了。
+## 快速数论变换
 
-但是,算竞选手可能像我一样有下面的疑问:
+若要计算的多项式系数是别的具有特殊意义的整数,那么 FFT 全部用浮点数运算,从时间上比整数运算慢,且只能用 long double 类型。
 
\81\87å¦\82æ\88\91è¦\81计ç®\97ç\9a\84å¤\9a项å¼\8fç³»æ\95°æ\98¯å\88«ç\9a\84å\85·æ\9c\89ç\89¹æ®\8aæ\84\8fä¹\89ç\9a\84æ\95´æ\95°ï¼\8cé\82£ä¹\88æ\88\91é\80\9aç¯\87é\83½å\9c¨ç\94¨æµ®ç\82¹æ\95°è¿\90ç®\97ï¼\8cé¦\96å\85\88ä»\8eæ\97¶é\97´ä¸\8aå°±ä¼\9aæ¯\94æ\95´æ\95°è¿\90ç®\97æ\85¢ï¼\8cå\8f¦å¤\96æ\88\91æ\9c\80å¤\9aå\8fªè\83½ç\94¨ long double ä¸\8dè\83½ç\94¨ long long ç±»å\9e\8bï¼\8cæ\88\91è\83½ä¸\8dè\83½åº\94ç\94¨æ\95°è®ºç\9a\84å\8f\98å\8c\96ä»\8eè\80\8cé\81¿å¼\80æµ®ç\82¹è¿\90ç®\97ï¼\8cè¾¾å\88°â\80\9cæ\9b´é«\98æ\9b´å¿«æ\9b´å¼ºâ\80\9då\91¢ï¼\9f
\8f¯å\90¦åº\94ç\94¨æ\95°è®ºå\8f\98å\8c\96ä»\8eè\80\8cé\81¿å¼\80æµ®ç\82¹è¿\90ç®\97ï¼\8cå¿«é\80\9fæ±\82解ï¼\9få\8f\82è§\81 [å¿«é\80\9fæ\95°è®ºå\8f\98æ\8d¢](/math/poly/ntt) ã\80\82
 
-## 算竞选手看过来~ NTT(数论优化的快速傅里叶变换)
+## 参考文献
 
-戳~ [NTT](/math/poly/ntt) 
+1.   [桃酱的算法笔记](https://zhuanlan.zhihu.com/p/41867199) .
index 9b973a0..ba7ef79 100644 (file)
@@ -1,6 +1,6 @@
 ## Description
 
-给定多项式 $f\left(x\right)$ ,求模 $x^{n}$ 意义下的 $\ln{f\left(x\right)}$ 与 $\exp{f\left(x\right)}$ 。
+给定多项式 $f(x)$ ,求模 $x^{n}$ 意义下的 $\ln{f(x)}$ 与 $\exp{f(x)}$ 。
 
 ## Methods
 
@@ -8,58 +8,62 @@
 
 * * *
 
-首先,对于多项式 $f\left(x\right)$ ,若 $\ln{f\left(x\right)}$ 存在,则由其 [定义](../intro/#_5) ,其必须满足:
+首先,对于多项式 $f(x)$ ,若 $\ln{f(x)}$ 存在,则由其 [定义](../intro/#_5) ,其必须满足:
 
 $$
-\left[x^{0}\right]f\left(x\right)=1
+[x^{0}]f(x)=1
 $$
 
-对 $\ln{f\left(x\right)}$ 求导再积分,可得:
+对 $\ln{f(x)}$ 求导再积分,可得:
 
 $$
 \begin{aligned}
-    \left(\ln{f\left(x\right)}\right)'&\equiv\frac{f'\left(x\right)}{f\left(x\right)}&\pmod{x^{n}}\\
-    \ln{f\left(x\right)}&\equiv\int\frac{f'\left(x\right)}{f\left(x\right)}&\pmod{x^{n}}
+    \frac{\mathrm{d} \ln{f(x)}}{\mathrm{d} x} & \equiv \frac{f'(x)}{f(x)} & \pmod{x^{n}} \\
+    \ln{f(x)} & \equiv \int \mathrm{d} \ln{x} \equiv \int\frac{f'(x)}{f(x)} \mathrm{d} x & \pmod{x^{n}}
 \end{aligned}
 $$
 
-多项式的求导,积分时间复杂度为 $O\left(n\right)$ ,求逆时间复杂度为 $O\left(n\log{n}\right)$ ,故多项式求 $\ln$ 时间复杂度 $O\left(n\log{n}\right)$ 。
+多项式的求导,积分时间复杂度为 $O(n)$ ,求逆时间复杂度为 $O(n\log{n})$ ,故多项式求 $\ln$ 时间复杂度 $O(n\log{n})$ 。
 
 * * *
 
-首先,对于多项式 $f\left(x\right)$ ,若 $\exp{f\left(x\right)}$ 存在,则其必须满足:
+首先,对于多项式 $f(x)$ ,若 $\exp{f(x)}$ 存在,则其必须满足:
 
 $$
-\left[x^{0}\right]f\left(x\right)=0
+[x^{0}]f(x)=0
 $$
 
-否则 $\exp{f\left(x\right)}$ 的常数项不收敛。
+否则 $\exp{f(x)}$ 的常数项不收敛。
 
-对 $\exp{f\left(x\right)}$ 求导,可得:
+对 $\exp{f(x)}$ 求导,可得:
 
 $$
-\exp'{f\left(x\right)}\equiv\exp{f\left(x\right)}f'\left(x\right)\pmod{x^{n}}
+\frac{\mathrm{d} \exp{f(x)}}{\mathrm{d} x} \equiv \exp{f(x)}f'(x)\pmod{x^{n}}
 $$
 
 比较两边系数可得:
 
 $$
-\left(n+1\right)\left[x^{n}\right]\exp{f\left(x\right)}=\sum_{i=0}^{n}\left[x^{i}\right]\exp{f\left(x\right)}\left(n-i+1\right)\left[x^{n-i}\right]f\left(x\right)
+[x^{n-1}]\frac{\mathrm{d} \exp{f(x)}}{\mathrm{d} x} = \sum_{i = 0}^{n - 1} \left([x^{i}]\exp{f(x)}\right) \left([x^{n-i-1}]f'(x)\right)
 $$
 
-又 $\left[x^{0}\right]f\left(x\right)=0$ ,则:
+$$
+n[x^{n}]\exp{f(x)} = \sum_{i = 0}^{n} \left([x^{i}]\exp{f(x)}\right) \left((n - i + 1)[x^{n - i}]f(x)\right)
+$$
+
+又 $[x^{0}]f(x)=0$ ,则:
 
 $$
-\left(n+1\right)\left[x^{n}\right]\exp{f\left(x\right)}=\sum_{i=0}^{n-1}\left[x^{i}\right]\exp{f\left(x\right)}\left(n-i+1\right)\left[x^{n-i}\right]f\left(x\right)
+n[x^{n}]\exp{f(x)} = \sum_{i = 0}^{n - 1} \left([x^{i}]\exp{f(x)}\right) \left((n - i + 1)[x^{n - i}]f(x)\right)
 $$
 
 使用分治 FFT 即可解决。
 
-时间复杂度 $O\left(n\log^{2}{n}\right)$ 。
+时间复杂度 $O(n\log^{2}{n})$ 。
 
 ### Newton's Method
 
-使用 [ **Newton's Method** ](./newton.md#newtons-method) 即可在 $O\left(n\log{n}\right)$ 的时间复杂度内解决多项式 $\exp$ 。
+使用 [ **Newton's Method** ](./newton.md#newtons-method) 即可在 $O(n\log{n})$ 的时间复杂度内解决多项式 $\exp$ 。
 
 ## Code
 
@@ -126,20 +130,20 @@ $$
 
 ## Examples
 
-1.  计算 $f^{k}\left(x\right)$ 
+1.  计算 $f^{k}(x)$ 
 
-普通做法为多项式快速幂,时间复杂度 $O\left(n\log{n}\log{k}\right)$ 。
+普通做法为多项式快速幂,时间复杂度 $O(n\log{n}\log{k})$ 。
 
-当 $\left[x^{0}\right]f\left(x\right)=1$ 时,有:
+当 $[x^{0}]f(x)=1$ 时,有:
 
 $$
-f^{k}\left(x\right)=\exp{\left(k\ln{f\left(x\right)}\right)}
+f^{k}(x)=\exp{(k\ln{f(x)})}
 $$
 
-当 $\left[x^{0}\right]f\left(x\right)\neq 1$ 时,设 $f\left(x\right)$ 的最低次项为 $f_{i}x^{i}$ ,则:
+当 $[x^{0}]f(x)\neq 1$ 时,设 $f(x)$ 的最低次项为 $f_{i}x^{i}$ ,则:
 
 $$
-f^{k}\left(x\right)=f_{i}^{k}x^{ik}\exp{\left(k\ln{\frac{f\left(x\right)}{f_{i}x^{i}}}\right)}
+f^{k}(x)=f_{i}^{k}x^{ik}\exp{(k\ln{\frac{f(x)}{f_{i}x^{i}}})}
 $$
 
-时间复杂度 $O\left(n\log{n}\right)$ 。
+时间复杂度 $O(n\log{n})$ 。
index 0d4bc4d..8e5fec9 100644 (file)
@@ -14,7 +14,7 @@ NTT 解决的是多项式乘法带模数的情况,可以说有些受模数的
 
 子群:群 $(S,⊕), (S′,⊕)$ ,满足 $S′⊂S$ ,则 $(S′,⊕)$ 是 $(S,⊕)$ 的子群
 
-拉格朗日定理: $|S′|∣|S |$ 证明需要用到陪集,得到陪集大小等于子群大小,每个陪集要么不交要么相等,所有陪集的并是集合 $S$ ,那么显然成立。
+拉格朗日定理: $|S′|∣|S |$ 证明需要用到陪集,得到陪集大小等于子群大小,每个陪集要么不交要么相等,所有陪集的并是集合 $S$ ,那么显然成立。
 
 生成子群: $a \in S$ 的生成子群 $\left<a\right> = \{a^{(k)}, k \geq 1 \}$ , $a$ 是 $\left< a \right>$ 的生成元
 
index b8b257e..b1c8b80 100644 (file)
@@ -47,10 +47,6 @@ $$
 
 ??? 参考代码
     ```cpp
-    // ===================================
-    //   author: M_sea
-    //   website: http://m-sea-blog.com/
-    // ===================================
     #include <algorithm>
     #include <cmath>
     #include <cstdio>
@@ -177,18 +173,18 @@ inline bool check(double mid) {
 另外本题存在一种复杂度 $O(nm)$ 的算法,如果有兴趣可以阅读 [这篇文章](https://www.cnblogs.com/y-clever/p/7043553.html) 。
 
 ```cpp
-inline int SPFA(int u, double mid)  //判负环 {
-    vis[u] = 1;
-for (int i = head[u]; i; i = e[i].nxt) {
-  int v = e[i].v;
-  double w = e[i].w - mid;
-  if (dis[u] + w < dis[v]) {
-    dis[v] = dis[u] + w;
-    if (vis[v] || SPFA(v, mid)) return 1;
+inline int SPFA(int u, double mid) {  //判负环
+  vis[u] = 1;
+  for (int i = head[u]; i; i = e[i].nxt) {
+    int v = e[i].v;
+    double w = e[i].w - mid;
+    if (dis[u] + w < dis[v]) {
+      dis[v] = dis[u] + w;
+      if (vis[v] || SPFA(v, mid)) return 1;
+    }
   }
-}
-vis[u] = 0;
-return 0;
+  vis[u] = 0;
+  return 0;
 }
 
 inline bool check(double mid) {  //如果有负环返回 true
index 86b8a12..caea9a6 100644 (file)
@@ -43,7 +43,7 @@ void solve() {
 
 以下的情况在 $n$ 和 $m$ 同阶的前提下讨论。
 
-é¦\96å\85\88æ\98¯å\88\86å\9d\97è¿\99ä¸\80æ­¥ï¼\8cè¿\99ä¸\80æ­¥ç\9a\84æ\97¶é\97´å¤\8dæ\9d\82度毫æ\97 ç\96\91é\97®å\9c°æ\98¯ $O(\sqrt{n}\cdot\sqrt{n}\log\sqrt{n}+n\log n)=O(n\log n)$ ;
+首先是分块这一步,这一步的时间复杂度是 $O(\sqrt{n}\cdot\sqrt{n}\log\sqrt{n}+n\log n)=O(n\log n)$ ;
 
 接着就到了莫队算法的精髓了,下面我们用通俗易懂的初中方法来证明它的时间复杂度是 $O(n\sqrt{n})$ ;
 
@@ -100,7 +100,7 @@ $$
 
 对于区间 $[i,i]$ ,由于区间只有一个元素,我们很容易就能知道答案。然后一步一步从当前区间(已知答案)向下一个区间靠近。
 
-我们设 $col[i]$ 表示当前颜色 i 出现了多少次, $ans$ 当前共有多少种可行的配对方案(有多少种可以选到一双颜色相同的袜子),表示然后每次移动的时候更新答案——设当前颜色为 $k$ ,如果是增长区间就是 $ans$ 加上 $C_{col[k]+1}^2-C_{col[k]}^2$ ,如果是缩短就是 $ans$ 减去 $C_{col[k]}^2-C_{col[k]-1}^2$ 。这应该很好理解
+我们设 $col[i]$ 表示当前颜色 $i$ 出现了多少次, $ans$ 当前共有多少种可行的配对方案(有多少种可以选到一双颜色相同的袜子),表示然后每次移动的时候更新答案——设当前颜色为 $k$ ,如果是增长区间就是 $ans$ 加上 $C_{col[k]+1}^2-C_{col[k]}^2$ ,如果是缩短就是 $ans$ 减去 $C_{col[k]}^2-C_{col[k]-1}^2$ 
 
 而这个询问的答案就是 $\displaystyle \frac{ans}{C_{r-l+1}^2}$ 。
 
@@ -110,11 +110,6 @@ $$
 
 所以 $C_{col[k]+1}^2-C_{col[k]}^2=col[k]$ 。
 
-这样我们少算了很多东西呢!
-至少我的代码在 BZOJ 上测快了一倍。
-
-还有,算 $C_a^2$ 可以用位运算, `a/2` 可以写成 `a>>1` 。
-
 算法总复杂度: $O(n\sqrt{n} )$ 
 
 下面的代码中 `mot` 表示答案的分母 (mother), `sub` 表示分子, `sqn` 表示块的大小: $\sqrt{n}$ , `arr` 是输入的数组, `node` 是存储询问的结构体, `tab` 是询问序列(排序后的), `col` 同上所述。
diff --git a/docs/string/images/pam3.png b/docs/string/images/pam3.png
new file mode 100644 (file)
index 0000000..060616d
Binary files /dev/null and b/docs/string/images/pam3.png differ
diff --git a/docs/string/images/pam4.png b/docs/string/images/pam4.png
new file mode 100644 (file)
index 0000000..29663eb
Binary files /dev/null and b/docs/string/images/pam4.png differ
diff --git a/docs/string/images/pam5.png b/docs/string/images/pam5.png
new file mode 100644 (file)
index 0000000..8985e3c
Binary files /dev/null and b/docs/string/images/pam5.png differ
diff --git a/docs/string/images/pam6.png b/docs/string/images/pam6.png
new file mode 100644 (file)
index 0000000..d664383
Binary files /dev/null and b/docs/string/images/pam6.png differ
index ea42902..b7b7f0e 100644 (file)
@@ -18,27 +18,28 @@ $$
 
 ## simple 的暴力
 
-我们直接比较与 $S$ 同构的所有字符串,共 $n$ 个。
-
-每次保留当前字典序最小的字符串与剩余的字符串比较。
+我们每次比较 $i$ 和 $j$ 开始的循环同构,把当前比较到的位置记作 $k$ ,每次遇到不一样的字符时便把大的跳过,最后剩下的就是最优解。
 
 ```cpp
 int k = 0, i = 0, j = 1;
-for (; j < n; j++) {
+while (k < n && i < n && j < n) {
   if (sec[(i + k) % n] == sec[(j + k) % n]) {
-    k++;
+    ++k;
   } else {
-    if (sec[(i + k) % n] > sec[(j + k) % n] % n) {
-      i = j;
-    }
+    if (sec[(i + k) % n] > sec[(j + k) % n])
+      ++i;
+    else
+      ++j;
     k = 0;
+    if (i == j) i++;
   }
 }
+i = min(i, j);
 ```
 
 随机数据下表现良好,但是可以构造特殊数据卡掉。
 
-例如:对于 $aaa\cdots aaa$ , 不难发现这个算法的复杂度退化为 $O(n^2)$ 
+例如:对于 $aaa\cdots aab$ , 不难发现这个算法的复杂度退化为 $O(n^2)$ 。
 
 我们发现,当字符串中出现多个连续重复子串时,此算法效率降低,我们考虑优化这个过程。
 
index 800c14e..fd0e0da 100644 (file)
@@ -1,10 +1,14 @@
-### 结构
+## 概述
+
+回文树 (EER Tree,Palindromic Tree,也被称为回文自动机)是一种可以存储一个串中所有回文子串的高效数据结构,最初是由 Mikhail Rubinchik 和 Arseny M. Shur 在 2015 年发表。它的灵感来源于后缀树等字符串后缀数据结构,使用回文树可以简单高效地解决一系列涉及回文串的问题。
+
+## 结构
 
 回文树大概长这样
 
 ![](./images/pam1.png)
 
-和其它自动机(但是它却叫「回文树」)类似的,它也是由转移边和 fail 指针组成,每个节点都可以代表所有对应它的回文子串。
+和其它自动机类似的,回文树也是由转移边和后缀链接 (fail 指针)组成,每个节点都可以代表一个回文子串。
 
 因为回文串长度分为奇数和偶数,我们可以像 manacher 那样加入一个不在字符集中的字符(如 '#')作为分隔符来将所有回文串的长度都变为奇数,但是这样过于麻烦了。有没有更好的办法呢?
 
 
 和其它的自动机一样,一个节点的 fail 指针指向的是这个节点所代表的回文串的最长回文后缀所对应的节点,但是转移边并非代表在原节点代表的回文串后加一个字符,而是表示在原节点代表的回文串前后各加一个相同的字符(不难理解,因为要保证存的是回文串)。
 
-我们还需要在每个节点上维护此节点对应回文子串的长度 len,这个信息保证了我们可以轻松地构造出回文自动机
+我们还需要在每个节点上维护此节点对应回文子串的长度 len,这个信息保证了我们可以轻松地构造出回文
 
-### 建造
+## 建造
 
-回文自动机不同于其他自动机的地方在于它有两个初始状态,分别代表长度为 $-1,0$ 的回文串。我们可以称它们为奇根,偶根。它们不表示任何实际的字符串,仅作为初始状态存在,这与其他自动机的根节点是异曲同工的。
+回文有两个初始状态,分别代表长度为 $-1,0$ 的回文串。我们可以称它们为奇根,偶根。它们不表示任何实际的字符串,仅作为初始状态存在,这与其他自动机的根节点是异曲同工的。
 
 偶根的 fail 指针指向奇根,而我们并不关心奇根的 fail 指针,因为奇根不可能失配(奇根转移出的下一个状态长度为 $1$ ,即单个字符。一定是回文子串)
 
-类似后缀自动机,我们增量构造回文自动机。
+类似后缀自动机,我们增量构造回文树。
+
+考虑构造完前 $p-1$ 个字符的回文树后,向自动机中添加在原串里位置为 $p$ 的字符。
 
-考虑构造完前 $p-1$ 个字符的回文自动机后,向自动机中添加在原串里位置为 $p$ 的字符。
 我们从以上一个字符结尾的最长回文子串对应的节点开始,不断沿着 fail 指针走,直到找到一个节点满足 $s_{p}=s_{p-len-1}$ ,即满足此节点所对应回文子串的上一个字符与待添加字符相同。
 
 这里贴出论文中的那张图
 
 如果 fail 没匹配到,那么将它连向长度为 $0$ 的那个节点,显然这是可行的(因为这是所有节点的后缀)。
 
-### 正确性证明
+## 线性状态数证明
+
+定理:对于一个字符串 $s$ ,它的本质不同回文子串个数最多只有 $|s|$ 个。
+
+证明:考虑使用数学归纳法。
+
+-   当 $|s| =1$ 时, $s$ 只有一个字符,同时也只有一个子串,并且这个子串是回文的,因此结论成立。
+
+-   当 $|s| >1$ 时,设 $t=sc$ ,其中 $t$ 表示 $s$ 最后增加一个字符 $c$ 后形成的字符串,假设结论对 $s$ 串成立。考虑以最后一个字符 $c$ 结尾的回文子串,假设它们的左端点由小到大排序为 $l_1,l_2,\dots,l_k$ 。由于 $t[l_1..|t|]$ 是回文串,因此对于所有位置 $l_1 \le p \le |t|$ ,有 $t[p..|t|]=t[l_1..l_1+|t|-p]$ 。所以,对于 $1 < i \le k$ , $t[l_i..|t|]$ 已经在 $t[1..|t|-1]$ 中出现过。因此,每次增加一个字符,本质不同的回文子串个数最多增加 $1$ 个。
+
+由数学归纳法,可知该定理成立。
+
+因此回文树状态数是 $O(|s|)$ 的。对于每一个状态,它实际只代表一个本质不同的回文子串,即转移到该节点的状态唯一,因此总转移数也是 $O(|s|)$ 的。
+
+## 正确性证明
+
+以上图为例,增加当前字符 `X` ,由线性状态数的证明,我们只需要找到包含最后一个字符 `X` 的最长回文后缀,也就是 `XAX` 。继续寻找 `XAX` 的最长回文后缀 `XBX` ,建立后缀链接。 `XBX` 对应状态已经在回文树中出现,包含最后一个字符的回文后缀就是 `XAX` , `XBX` 本身及其对应状态在 fail 树上的所有祖先。
+
+对于 $s$ 回文树的构造,令 $n=|s|$ ,显然除了跳 fail 指针的其他操作都是 $O(n)$ 的。
+
+加入字符时,在上一次的基础上,每次跳 fail 后对应节点在 fail 树的深度 $-1$ ,而连接 fail 后,仅为深度 + 1(但 fail 为 $0$ 时(即到 $-1$ 才符合),深度相当于在 $-1$ 的基础上 $+2$ )。
+
+因为只加入 $n$ 个字符,所以只会加 $n$ 次深度,最多也只会跳 $2n$ 次 fail。
+
+因此,构造 $s$ 的回文树的时间复杂度是 $O(|s|)$ 。
+
+## 应用
+
+### 本质不同回文子串个数
+
+由线性状态数的证明,容易知道一个串的本质不同回文子串个数等于回文树的状态数(排除奇根和偶根两个状态)。
+
+### 回文子串出现次数
+
+建出回文树,使用类似后缀自动机统计出现次数的方法。
+
+由于回文树的构造过程中,节点本身就是按照拓扑序插入,因此只需要逆序枚举所有状态,将当前状态的出现次数加到其 fail 指针对应状态的出现次数上即可。
+
+例题: [「APIO2014」回文串](https://www.luogu.org/problem/P3649) 
+
+定义 $s$ 的一个子串的存在值为这个子串在 $s$ 中出现的次数乘以这个子串的长度。对于给定的字符串 $s$ ,求所有回文子串中的最大存在值。
+
+??? note "参考代码"
+    ```cpp
+    #include <bits/stdc++.h>
+    using namespace std;
+    typedef long long ll;
+    const int maxn = 300000 + 5;
+    namespace pam {
+    int sz, tot, last;
+    int cnt[maxn], ch[maxn][26], len[maxn], fail[maxn];
+    char s[maxn];
+    int node(int l) {
+      sz++;
+      memset(ch[sz], 0, sizeof(ch[sz]));
+      len[sz] = l;
+      fail[sz] = cnt[sz] = 0;
+      return sz;
+    }
+    void clear() {
+      sz = -1;
+      last = 0;
+      s[tot = 0] = '$';
+      node(0);
+      node(-1);
+      fail[0] = 1;
+    }
+    int getfail(int x) {
+      while (s[tot - len[x] - 1] != s[tot]) x = fail[x];
+      return x;
+    }
+    void insert(char c) {
+      s[++tot] = c;
+      int now = getfail(last);
+      if (!ch[now][c - 'a']) {
+        int x = node(len[now] + 2);
+        fail[x] = ch[getfail(fail[now])][c - 'a'];
+        ch[now][c - 'a'] = x;
+      }
+      last = ch[now][c - 'a'];
+      cnt[last]++;
+    }
+    ll solve() {
+      ll ans = 0;
+      for (int i = sz; i >= 0; i--) {
+        cnt[fail[i]] += cnt[i];
+      }
+      for (int i = 1; i <= sz; i++) {
+        ans = max(ans, 1ll * len[i] * cnt[i]);
+      }
+      return ans;
+    }
+    }  // namespace pam
+    char s[maxn];
+    int main() {
+      pam::clear();
+      scanf("%s", s + 1);
+      for (int i = 1; s[i]; i++) {
+        pam::insert(s[i]);
+      }
+      printf("%lld\n", pam::solve());
+      return 0;
+    }
+    ```
+
+### 最小回文划分
+
+> 给定一个字符串 $s(1\le |s| \le 10^5)$ ,求最小的 $k$ ,使得存在 $s_1,s_2,\dots,s_k$ ,满足 $s_i(1\le i \le k)$ 均为回文串,且 $s_1,s_2, \dots ,s_k$ 依次连接后得到的字符串等于 $s$ 。
+
+考虑动态规划,记 $dp[i]$ 表示 $s$ 长度为 $i$ 的前缀的最小划分数,转移只需要枚举以第 $i$ 个字符结尾的所有回文串
+
+$$
+dp[i]=1+\min_{ s[j+1..i] \text{ 为回文串} } dp[j]
+$$
+
+由于一个字符串最多会有 $O(n^2)$ 个回文子串,因此上述算法的时间复杂度为 $O(n^2)$ ,无法接受,为了优化转移过程,下面给出一些引理。
+
+记字符串 $s$ 长度为 $i$ 的前缀为 $pre(s,i)$ ,长度为 $i$ 的后缀为 $suf(s,i)$ 。
+
+周期:若 $0< p \le |s|$ , $\forall 1 \le i \le |s|-p,s[i]=s[i+p]$ ,就称 $p$ 是 $s$ 的周期。
+
+border:若 $0 \le r < |s|$ , $pre(s,r)=suf(s,r)$ ,就称 $pre(s,r)$ 是 $s$ 的 border。
+
+周期和 border 的关系: $t$ 是 $s$ 的 border,当且仅当 $|s|-|t|$ 是 $s$ 的周期。
+
+证明:
+
+若 $t$ 是 $s$ 的 border,那么 $pre(s,|t|)=suf(s,|t|)$ ,因此 $\forall 1\le i \le |t|, s[i]=s[|s|-|t|+i]$ ,所以 $|s|-|t|$ 就是 $s$ 的周期。
+
+若 $|s|-|t|$ 为 $s$ 周期,则 $\forall 1 \le i \le |s|-(|s|-|t|)=|t|,s[i]=s[|s|-|t|+i]$ ,因此 $pre(s,|t|)=suf(s,|t|)$ ,所以 $t$ 是 $s$ 的 border。
 
-还是在图上
+引理 $1$ : $t$ 是回文串 $s$ 的后缀, $t$ 是 $s$ 的 border 当且仅当 $t$ 是回文串。
 
-增加当前字符 `X` ,如果 `XAX` 的后缀没有被包含在树中,那才是不正确的,相反如果每次增加时所有后缀都在树上就是正确的
+证明:
 
-我们找之前 `XAX` 的 fail 的时候,已经证明了 `XBX` 已经被包含在树中了
+对于 $1 \le i \le |t|$ ,由 $s$ 和 $t$ 为回文串,因此有 $s[i]=s[|s|-i+1]=s[|s|-|t|+i]$ ,所以 $t$ 是 $s$ 的 border。
 
\90\8cç\90\86æ\89¾ `XBX` ç\9a\84 fail æ\97¶ä¼\9aè¯\81æ\98\8eä¸\80个æ¯\94 `XBX` ç\9f­ç\9a\84å\90\8eç¼\80å\9c¨æ \91中
¯¹äº\8e $1 \le i \le |t|$ ï¼\8cç\94± $t$ æ\98¯ $s$ ç\9a\84 borderï¼\8cæ\9c\89 $s[i]=s[|s|-|t|+i]$ ï¼\8cç\94± $s$ æ\98¯å\9b\9eæ\96\87串ï¼\8cæ\9c\89 $s[i]=s[|s|-i+1]$ ï¼\8cå\9b æ­¤ $s[|s|-i+1]=s[|s|-|t|+i]$ ï¼\8cæ\89\80以 $t$ æ\98¯å\9b\9eæ\96\87串ã\80\82
 
-类似归纳法递归下去,所有回文串就都会在树中,于是这是正确的
+下图中,相同颜色的位置表示字符对应相同。
 
-因为每次至多增加一个回文串,所以这是 $O(n)$ 的
+![](./images/pam3.png)
 
-显然除了跳 fail 指针的其他操作都是 $O(n)$ 的
+引理 $2$ : $t$ 是回文串 $s$ 的 border ( $|s|\le 2|t|$ ), $s$ 是回文串当且仅当 $t$ 是回文串。
 
-加入字符时,在上一次的基础上,每次跳 fail 后对应节点在 fail 树的深度 $-1$ ,而连接 fail 后,仅为深度 + 1(但 fail 为 $0$ 时(即到 $-1$ 才符合),深度相当于在 $-1$ 的基础上 $+2$ )
+证明:
 
-因为只加入 $n$ 个字符,所以只会加 $n$ 次深度,最多也只会跳 $2n$ 次 fail
+若 $s$ 是回文串,由引理 $1$ , $t$ 也是回文串。
 
-### 例题
+若 $t$ 是回文串,由 $t$ 是 $s$ 的 border,因此 $\forall 1 \le i \le |t|, s[i]=s[|s|-|t|+i]=s[|s|-i+1]$ ,因为 $|s| \le 2|t|$ ,所以 $s$ 也是回文串。
 
- [「APIO2014」回文串](https://www.luogu.org/problem/P3649) 
+引理 $3$ : $t$ 是字符串 $s$ 的 border,则 $|s|-|t|$ 是 $s$ 的周期, $|s|-|t|$ 为 $s$ 的最小周期,当且仅当 $t$ 是 $s$ 的最长回文真后缀。
 
»ºå\87ºæ \91æ\9d¥ï¼\8c类似å\90\8eç¼\80è\87ªå\8a¨æ\9cºç»\9f计å\87ºç\8e°æ¬¡æ\95°å\8d³å\8f¯
¼\95ç\90\86 $4$ ï¼\9a $x$ æ\98¯ä¸\80个å\9b\9eæ\96\87串ï¼\8c $y$ æ\98¯ $x$ ç\9a\84æ\9c\80é\95¿å\9b\9eæ\96\87ç\9c\9få\90\8eç¼\80ï¼\8c $z$ æ\98¯ $y$ ç\9a\84æ\9c\80é\95¿å\9b\9eæ\96\87ç\9c\9få\90\8eç¼\80ã\80\82令 $u,v$ å\88\86å\88«ä¸ºæ»¡è¶³ $x=uy,y=vz$ ç\9a\84å­\97符串ï¼\8cå\88\99æ\9c\89ä¸\8bé\9d¢ä¸\89æ\9d¡æ\80§è´¨
 
-```cpp
-//变量名与上文基本相同,其中ptr为转移指针,数组大小应为字符集大小
-class PA {
- private:
-  static const int N = 100010;
-  struct Node {
-    int len;
-    int ptr[26], fail;
-    Node(int len = 0) : len(len), fail(0) { memset(ptr, 0, sizeof(ptr)); }
-  } nd[N];
+1.   $|u| \ge |v|$ ;
 
-  int size, cnt;  // size为字符串长度,cnt为节点个数
-  int cur;  //当前指针停留的位置,即最后插入字符所对应的节点
-  char s[N];
+2.  如果 $|u| > |v|$ ,那么 $|u| > |z|$ ;
 
-  int getfail(int x)  //沿着fail指针找到第一个回文后缀
-  {
-    while (s[size - nd[x].len - 1] != s[size]) {
-      x = nd[x].fail;
+3.  如果 $|u| = |v|$ ,那么 $u=v$ 。
+
+![](./images/pam4.png)
+
+证明:
+
+1.  由引理 $3$ 的推论, $|u|=|x|-|y|$ 是 $x$ 的最小周期, $|v|=|y|-|z|$ 是 $y$ 的最小周期。考虑反证法,假设 $|u| < |v|$ ,因为 $y$ 是 $x$ 的后缀,所以 $u$ 既是 $x$ 的周期,也是 $y$ 的周期,而 $|v|$ 是 $y$ 的最小周期,矛盾。所以 $|u| \ge |v|$ 。
+
+2.  因为 $y$ 是 $x$ 的 border,所以 $v$ 是 $x$ 的前缀,设字符串 $w$ ,满足 $x=vw$ (如下图所示),其中 $z$ 是 $w$ 的 border。考虑反证法,假设 $|u| \le |z|$ ,那么 $|zu| \le 2|z|$ ,所以由引理 $2$ , $w$ 是回文串,由引理 $1$ , $w$ 是 $x$ 的 border,又因为 $|u| > |v|$ ,所以 $|w| > |y|$ ,矛盾。所以 $|u| > |z|$ 。
+
+3.   $u,v$ 都是 $x$ 的前缀, $|u|=|v|$ ,所以 $u=v$ 。
+
+![](./images/pam5.png)
+
+推论: $s$ 的所有回文后缀按照长度排序后,可以划分成 $\log |s|$ 段等差数列。
+
+证明:
+
+设 $s$ 的所有回文后缀长度从小到大排序为 $l_1,l_2,\dots,l_k$ 。对于任意 $2 \le i \le k-1$ ,若 $l_{i}-l_{i-1}=l_{i+1}-l_{i}$ ,则 $l_{i-1},l_{i},l_{i+1}$ 构成一个等差数列。否则 $l_{i}-l_{i-1}\neq l_{i+1}-l_{i}$ ,由引理 $4$ ,有 $l_{i+1}-l_{i}>l_{i}-l_{i-1}$ ,且 $l_{i+1}-l_{i}>l_{i-1}$ , $l_{i+1}>2l_{i-1}$ 。因此,若相邻两对回文后缀的长度之差发生变化,那么这个最大长度一定会相对于最小长度翻一倍。显然,长度翻倍最多只会发生 $O(\log |s|)$ 次,也就是 $s$ 的回文后缀长度可以划分成 $\log |s|$ 段等差数列。
+
+该推论也可以通过使用弱周期引理,对 $s$ 的最长回文后缀的所有 border 按照长度 $x$ 分类, $x \in [2^0,2^1),[2^1,2^2),\dots,[2^k,n)$ ,考虑这 $\log |s|$ 组内每组的最长 border 进行证明。详细证明可以参考金策的《字符串算法选讲》和陈孙立的 2019 年 IOI 国家候选队论文《子串周期查询问题的相关算法及其应用》。
+
+有了这个结论后,我们现在可以考虑如何优化 $dp$ 的转移。
+
+回文树上的每个节点 $u$ 需要多维护两个信息, $diff[u]$ 和 $slink[u]$ 。 $diff[u]$ 表示节点 $u$ 和 $fail[u]$ 所代表的回文串的长度差,即 $len[u]-len[fail[u]]$ 。 $slink[u]$ 表示 $u$ 一直沿着 fail 向上跳到第一个节点 $v$ ,使得 $diff[v] \neq diff[u]$ ,也就是 $u$ 所在等差数列中长度最小的那个节点。
+
+根据上面证明的结论,如果使用 $slink$ 指针向上跳的话,每向后填加一个字符,只需要向上跳 $O(\log |s|)$ 次。因此,可以考虑将一个等差数列表示的所有回文串的 $dp$ 值之和(在原问题中指 $\min$ ),记录到最长的那一个回文串对应节点上。
+
+ $g[v]$ 表示 $v$ 所在等差数列的 $dp$ 值之和,且 $v$ 是这个等差数列中长度最长的节点,则 $g[v]=\sum_{slink[x]=v} dp[i-len[x]]$ 。
+
+下面我们考虑如何更新 $g$ 数组和 $dp$ 数组。以下图为例,假设当前枚举到第 $i$ 个字符,回文树上对应节点为 $x$ 。 $g[x]$ 为橙色三个位置的 $dp$ 值之和(最短的回文串 $slink[x]$ 算在下一个等差数列中)。 $fail[x]$ 上一次出现位置是 $i-diff[x]$ (在 $i-diff[x]$ 处结束), $g[fail[x]]$ 包含的 $dp$ 值是蓝色位置。因此, $g[x]$ 实际上等于 $g[fail[x]]$ 和多出来一个位置的 $dp$ 值之和,多出来的位置是 $i-(len[slink[x]]+diff[x])$ 。最后再用 $g[x]$ 去更新 $dp[i]$ ,这部分等差数列的贡献就计算完毕了,不断跳 $slink[x]$ ,重复这个过程即可。具体实现方式可参考例题代码。
+
+![](./images/pam6.png)
+
+最后,上述做法的正确性依赖于:如果 $x$ 和 $fail[x]$ 属于同一个等差数列,那么 $fail[x]$ 上一次出现位置是 $i-diff[x]$ 。
+
+证明:
+
+根据引理 $1$ , $fail[x]$ 是 $x$ 的 border,因此其在 $i-diff[x]$ 处出现。
+
+假设 $fail[x]$ 在 $(i-diff[x],i)$ 中的 $j$ 位置出现。由于 $x$ 和 $fail[x]$ 属于同一个等差数列,因此 $2|fail[x]| \ge x$ 。多余的 $fail[x]$ 和 $i-diff[x]$ 处的 $fail[x]$ 有交集,记交集为 $w$ ,设串 $u$ 满足 $uw=fail[x]$ 。用类似引理 $1$ 的方式可以证明, $w$ 是回文串,而 $x$ 的前缀 $s[i-len[x]+1..j]=uwu$ 也是回文串,这与 $fail[x]$ 是 $x$ 的最长回文前缀(后缀)矛盾。
+
+例题: [Codeforces 932G Palindrome Partition](https://codeforces.com/problemset/problem/932/G) 
+
+给定一个字符串 $s$ ,要求将 $s$ 划分为 $t_1, t_2, \dots, t_k$ ,其中 $k$ 是偶数,且 $t_i=t_{k-i}$ ,求这样的划分方案数。
+
+??? note "题解"
+    构造字符串 $t= s[0]s[n - 1]s[1]s[n - 2]s[2]s[n - 3] \dots s[n / 2 - 1]s[n / 2]$ ,问题等价于求 $t$ 的偶回文划分方案数,把上面的转移方程改成求和形式并且只在偶数位置更新 $dp$ 数组即可。时间复杂度 $O(n \log n)$ ,空间复杂度 $O(n)$ 。
+
+??? note "参考代码"
+    ```cpp
+    #include <bits/stdc++.h>
+    using namespace std;
+    typedef long long ll;
+    const int mod = 1e9 + 7;
+    const int maxn = 1000000 + 5;
+    inline int add(int x, int y) {
+      x += y;
+      return x >= mod ? x -= mod : x;
+    }
+    namespace pam {
+    int sz, tot, last;
+    int ch[maxn][26], len[maxn], fail[maxn];
+    int cnt[maxn], dep[maxn], dif[maxn], slink[maxn];
+    char s[maxn];
+    int node(int l) {
+      sz++;
+      memset(ch[sz], 0, sizeof(ch[sz]));
+      len[sz] = l;
+      fail[sz] = 0;
+      cnt[sz] = 0;
+      dep[sz] = 0;
+      return sz;
+    }
+    void clear() {
+      sz = -1;
+      last = 0;
+      s[tot = 0] = '$';
+      node(0);
+      node(-1);
+      fail[0] = 1;
+    }
+    int getfail(int x) {
+      while (s[tot - len[x] - 1] != s[tot]) x = fail[x];
+      return x;
     }
-    return x;
-  }
-
- public:
-  PA() : size(0), cnt(0), cur(0) {
-    nd[cnt] = Node(0);
-    nd[cnt].fail = 1;
-    nd[++cnt] = Node(-1);
-    nd[cnt].fail = 0;
-    s[0] = '$';
-  }
-
-  void extend(char c) {
-    s[++size] = c;
-    int now = getfail(cur);  //找到插入的位置
-    if (!nd[now].ptr[c - 'a'])  //若没有这个节点,则新建并求出它的fail指针
-    {
-      int tmp = ++cnt;
-      nd[tmp] = Node(nd[now].len + 2);
-      nd[tmp].fail = nd[getfail(nd[now].fail)].ptr[c - 'a'];
-      nd[now].ptr[c - 'a'] = tmp;
+    void insert(char c) {
+      s[++tot] = c;
+      int now = getfail(last);
+      if (!ch[now][c - 'a']) {
+        int x = node(len[now] + 2);
+        fail[x] = ch[getfail(fail[now])][c - 'a'];
+        dep[x] = dep[fail[x]] + 1;
+        ch[now][c - 'a'] = x;
+        dif[x] = len[x] - len[fail[x]];
+        if (dif[x] == dif[fail[x]])
+          slink[x] = slink[fail[x]];
+        else
+          slink[x] = fail[x];
+      }
+      last = ch[now][c - 'a'];
+      cnt[last]++;
     }
-    cur = nd[now].ptr[c - 'a'];
-  }
+    }  // namespace pam
+    using pam::dif;
+    using pam::fail;
+    using pam::len;
+    using pam::slink;
+    int n, dp[maxn], g[maxn];
+    char s[maxn], t[maxn];
+    int main() {
+      pam::clear();
+      scanf("%s", s + 1);
+      n = strlen(s + 1);
+      for (int i = 1, j = 0; i <= n; i++) t[++j] = s[i], t[++j] = s[n - i + 1];
+      dp[0] = 1;
+      for (int i = 1; i <= n; i++) {
+        pam::insert(t[i]);
+        for (int x = pam::last; x > 1; x = slink[x]) {
+          g[x] = dp[i - len[slink[x]] - dif[x]];
+          if (dif[x] == dif[fail[x]]) g[x] = add(g[x], g[fail[x]]);
+          if (i % 2 == 0) dp[i] = add(dp[i], g[x]);
+        }
+      }
+      printf("%d", dp[n]);
+      return 0;
+    }
+    ```
+
+## 例题
+
+-    [最长双回文串](https://www.luogu.org/problem/P4555) 
+
+-    [拉拉队排练](https://www.luogu.org/problem/P1659) 
+
+-    [「SHOI2011」双倍回文](https://www.luogu.org/problem/P4287) 
+
+-    [HDU 5421 Victor and String](http://acm.hdu.edu.cn/showproblem.php?pid=5421) 
+
+-    [CodeChef Palindromeness](https://www.codechef.com/LTIME23/problems/PALPROB) 
+
+## 相关资料
+
+-    [EERTREE: An Efficient Data Structure for Processing Palindromes in Strings](https://arxiv.org/pdf/1506.04862) 
+
+-    [Palindromic tree](http://adilet.org/blog/palindromic-tree/) 
+
+-   2017 年 IOI 国家候选队论文集 回文树及其应用 翁文涛
+
+
+-   2019 年 IOI 国家候选队论文集 子串周期查询问题的相关算法及其应用 陈孙立
+
+-   字符串算法选讲 金策
+
+-    [A bit more about palindromes](https://codeforces.com/blog/entry/19193) 
 
-  int qlen() { return nd[cur].len; }
-} A, B;
-```
+-    [A Subquadratic Algorithm for Minimum Palindromic Factorization](https://arxiv.org/pdf/1403.2431.pdf) 
index 9af8b48..21d99e8 100644 (file)
@@ -61,7 +61,7 @@
       n = strlen(s + 1);
       for (i = 1; i <= n; ++i) rk[i] = s[i];
     
-      for (w = 1; w < n; ++w) {
+      for (w = 1; w < n; w <<= 1) {
         for (i = 1; i <= n; ++i) sa[i] = i;
         sort(sa + 1, sa + n + 1, [](int x, int y) {
           return rk[x] == rk[y] ? rk[x + w] < rk[y + w] : rk[x] < rk[y];
 
 ### 一些常数优化
 
-如果你把上面那份代码交到 LOJ 上:
+如果你把上面那份代码交到 [LOJ #111: 后缀排序](https://loj.ac/problem/111) 上:
 
 ![](./images/sa3.png)
 
index d901507..6d2ecd0 100644 (file)
@@ -142,7 +142,7 @@ $$
 -    $s$ 的子串可以根据它们结束的位置 $endpos$ 被划分为多个等价类;
 -   SAM 由初始状态 $t_0$ 和与每一个 $endpos$ 等价类对应的每个状态组成;
 -   对于每一个状态 $v$ ,一个或多个子串与之匹配。我们记 $longest(v)$ 为其中最长的一个字符串,记 $len(v)$ 为它的长度。类似地,记 $shortest(v)$ 为最短的子串,它的长度为 $minlen(v)$ 。那么对应这个状态的所有字符串都是字符串 $longest(v)$ 的不同的后缀,且所有字符串的长度恰好覆盖区间 $[minlength(v),len(v)]$ 中的每一个整数。
--   对于任意不是 $t_0$ 的状态 $v$ ,定义后缀链接为连接到对应字符串 $longest(u)$ 的长度为 $minlen(v)-1$ 的后缀的一条边。从根节点 $t_0$ 出发的后缀链接可以形成一棵树。这棵树也表示 $endpos$ 集合间的包含关系。
+-   对于任意不是 $t_0$ 的状态 $v$ ,定义后缀链接为连接到对应字符串 $longest(v)$ 的长度为 $minlen(v)-1$ 的后缀的一条边。从根节点 $t_0$ 出发的后缀链接可以形成一棵树。这棵树也表示 $endpos$ 集合间的包含关系。
 -   对于 $t_0$ 以外的状态 $v$ ,可用后缀链接 $link(v)$ 表达 $minlen(v)$ :
 
 $$
index 158acc0..fa2b546 100644 (file)
@@ -36,13 +36,13 @@ Four russian 是一个由四位俄罗斯籍的计算机科学家提出来的基
 
 询问的时候,我们可以将询问区间划分为不超过 1 个数组 B 上的连续块区间和不超过 2 个数组 A 上的整块内的连续区间。显然这些问题我们通过 ST 表上的区间查询解决。
 
-在 $S=\log n$ 时候,预处理复杂度达到最优。为 $O((n / \log n)\log n+(n / \log n)\times\log n\times\log \log n)=O(n\log \log n)$ 
+在 $S=\log n$ 时候,预处理复杂度达到最优,为 $O((n / \log n)\log n+(n / \log n)\times\log n\times\log \log n)=O(n\log \log n)$ 。
 
 时间复杂度 $O(n\log \log n)-O(1)$ 
 
 空间复杂度 $O(n\log \log n)$ 
 
-当然询问由于要跑三个 ST 表,该实现方法的时间复杂度较大。
+当然询问由于要跑三个 ST 表,该实现方法的常数较大。
 
 !!! note "一些小小的算法改进"
     我们发现,在询问的两个端点在数组 A 中属于不同的块的时候,数组 A 中块内的询问是关于每一块前缀或者后缀的询问。
index edb6b41..fe692cc 100644 (file)
@@ -11,7 +11,7 @@ repo_url: 'https://github.com/OI-wiki/OI-wiki'
 edit_uri: 'https://oi-wiki.org/edit-landing/?ref='
 
 # Copyright
-copyright: 'Copyright &copy; 2016 - 2019 OI Wiki Team'
+copyright: 'Copyright &copy; 2016 - 2020 OI Wiki Team'
 google_analytics:
   - 'UA-124485594-1'
   - 'auto'
@@ -56,16 +56,19 @@ nav:
       - Eclipse: lang/editor/eclipse.md
       - Notepad++: lang/editor/npp.md
       - Dev-C++: lang/editor/devcpp.md
+      - Geany: lang/editor/geany.md
     - C++ 基础:
       - Hello, World!: lang/helloworld.md
       - C++ 语法基础: lang/basic.md
       - 变量: lang/var.md
       - 运算: lang/op.md
-      - 数组: lang/array.md
-      - 结构体: lang/struct.md
-      - 指针: lang/pointer.md
-      - 分支: lang/branch.md
-      - 循环: lang/loop.md
+      - 流程控制语句:
+        - 分支: lang/branch.md
+        - 循环: lang/loop.md
+      - 高级数据类型:
+        - 数组: lang/array.md
+        - 结构体: lang/struct.md
+        - 指针: lang/pointer.md
       - 函数: lang/func.md
       - 文件操作: lang/file-op.md
     - C++ 标准库:
@@ -144,7 +147,6 @@ nav:
     - 计数 DP: dp/count.md
     - 动态 DP: dp/dynamic.md
     - DP 优化:
-      - 二进制分组解多重背包: dp/opt/binary-knapsack.md
       - 单调队列/单调栈优化: dp/opt/monotonous-queue-stack.md
       - 斜率优化: dp/opt/slope.md
       - 四边形不等式优化: dp/opt/quadrangle.md
@@ -166,7 +168,7 @@ nav:
     - 广义后缀自动机: string/general-sam.md
     - 后缀树: string/suffix-tree.md
     - Manacher: string/manacher.md
-    - 回文自动机: string/pam.md
+    - 回文: string/pam.md
     - 序列自动机: string/seq-automaton.md
     - 最小表示法: string/minimal-string.md
     - Lyndon 分解: string/lyndon.md
@@ -288,7 +290,8 @@ nav:
     - 析合树: ds/divide-combine.md
   - 图论:
     - 图论部分简介: graph/index.md
-    - 图论基础: graph/basic.md
+    - 图论相关概念: graph/concept.md
+    - 图的存储: graph/save.md
     - DFS(图论): graph/dfs.md
     - BFS(图论): graph/bfs.md
     - 树上问题:
@@ -313,8 +316,8 @@ nav:
     - 连通性相关:
       - 强连通分量: graph/scc.md
       - 双连通分量: graph/bcc.md
-      - 割点和桥: graph/bridge.md
-      - 2-SAT: graph/2-sat.md
+      - 割点和桥: graph/cut.md
+    - 2-SAT: graph/2-sat.md
     - 欧拉图: graph/euler.md
     - 哈密顿图: graph/hamilton.md
     - 二分图: graph/bi-graph.md
@@ -330,7 +333,6 @@ nav:
     - Prufer 序列: graph/prufer.md
     - LGV 引理: graph/lgv.md
     - 弦图: graph/chord.md
-    - 图论杂项: graph/misc.md
   - 计算几何:
     - 计算几何部分简介: geometry/index.md
     - 二维计算几何基础: geometry/2d.md
index 8bc4b6a..1343ec9 100644 (file)
@@ -9,33 +9,51 @@
       "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
       "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw=="
     },
+    "@types/unist": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
+      "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ=="
+    },
     "abab": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz",
-      "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w=="
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz",
+      "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg=="
     },
     "acorn": {
-      "version": "5.7.2",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.2.tgz",
-      "integrity": "sha512-cJrKCNcr2kv8dlDnbw+JPUGjHZzo4myaxOLmpOX8a+rgX94YeTcTMv/LFJUSByRpc+i4GgVnnhLxvMu/2Y+rqw=="
+      "version": "5.7.3",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
+      "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
     },
     "acorn-globals": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.1.0.tgz",
-      "integrity": "sha512-KjZwU26uG3u6eZcfGbTULzFcsoz6pegNKtHPksZPOUsiKo5bUmiBPa38FuHZ/Eun+XYh/JCCkS9AS3Lu4McQOQ==",
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz",
+      "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==",
       "requires": {
-        "acorn": "^5.0.0"
+        "acorn": "^6.0.1",
+        "acorn-walk": "^6.0.1"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz",
+          "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw=="
+        }
       }
     },
+    "acorn-walk": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz",
+      "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA=="
+    },
     "ajv": {
-      "version": "5.5.2",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
-      "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
+      "version": "6.11.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz",
+      "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==",
       "requires": {
-        "co": "^4.6.0",
-        "fast-deep-equal": "^1.0.0",
+        "fast-deep-equal": "^3.1.1",
         "fast-json-stable-stringify": "^2.0.0",
-        "json-schema-traverse": "^0.3.0"
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
       }
     },
     "alphanum-sort": {
@@ -76,8 +94,8 @@
     },
     "anymatch": {
       "version": "2.0.0",
-      "resolved": "http://registry.npm.taobao.org/anymatch/download/anymatch-2.0.0.tgz",
-      "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+      "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
       "requires": {
         "micromatch": "^3.1.4",
         "normalize-path": "^2.1.1"
     },
     "append-buffer": {
       "version": "1.0.2",
-      "resolved": "http://registry.npm.taobao.org/append-buffer/download/append-buffer-1.0.2.tgz",
+      "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz",
       "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=",
       "requires": {
         "buffer-equal": "^1.0.0"
     },
     "archy": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/archy/download/archy-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
       "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA="
     },
     "argparse": {
     },
     "arr-filter": {
       "version": "1.1.2",
-      "resolved": "http://registry.npm.taobao.org/arr-filter/download/arr-filter-1.1.2.tgz",
+      "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz",
       "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=",
       "requires": {
         "make-iterator": "^1.0.0"
     },
     "arr-flatten": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/arr-flatten/download/arr-flatten-1.1.0.tgz",
-      "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE="
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
     },
     "arr-map": {
       "version": "2.0.2",
-      "resolved": "http://registry.npm.taobao.org/arr-map/download/arr-map-2.0.2.tgz",
+      "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz",
       "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=",
       "requires": {
         "make-iterator": "^1.0.0"
     },
     "array-each": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/array-each/download/array-each-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
       "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8="
     },
     "array-equal": {
     },
     "array-initial": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/array-initial/download/array-initial-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz",
       "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=",
       "requires": {
         "array-slice": "^1.0.0",
       "dependencies": {
         "is-number": {
           "version": "4.0.0",
-          "resolved": "http://registry.npm.taobao.org/is-number/download/is-number-4.0.0.tgz",
-          "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8="
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ=="
         }
       }
     },
     "array-last": {
       "version": "1.3.0",
-      "resolved": "http://registry.npm.taobao.org/array-last/download/array-last-1.3.0.tgz",
-      "integrity": "sha1-eqdwc/7FZd2rJJP1+IGF9ASp0zY=",
+      "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz",
+      "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==",
       "requires": {
         "is-number": "^4.0.0"
       },
       "dependencies": {
         "is-number": {
           "version": "4.0.0",
-          "resolved": "http://registry.npm.taobao.org/is-number/download/is-number-4.0.0.tgz",
-          "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8="
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ=="
         }
       }
     },
     "array-slice": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/array-slice/download/array-slice-1.1.0.tgz",
-      "integrity": "sha1-42jqFfibxwaff/uJrsOmx9SsItQ="
+      "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
+      "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w=="
     },
     "array-sort": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/array-sort/download/array-sort-1.0.0.tgz",
-      "integrity": "sha1-5MBTVkU/VvU1EqfR1hI/LFTAqIo=",
+      "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz",
+      "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==",
       "requires": {
         "default-compare": "^1.0.0",
         "get-value": "^2.0.6",
       "dependencies": {
         "kind-of": {
           "version": "5.1.0",
-          "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-5.1.0.tgz",
-          "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0="
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
         }
       }
     },
     },
     "array-unique": {
       "version": "0.3.2",
-      "resolved": "http://registry.npm.taobao.org/array-unique/download/array-unique-0.3.2.tgz",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
       "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
     },
     "asn1": {
       "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
     },
     "async-done": {
-      "version": "1.3.1",
-      "resolved": "http://registry.npm.taobao.org/async-done/download/async-done-1.3.1.tgz",
-      "integrity": "sha1-FLe3Nme4ZMjwK1slP8nG7dt3fz4=",
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz",
+      "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==",
       "requires": {
         "end-of-stream": "^1.1.0",
         "once": "^1.3.2",
-        "process-nextick-args": "^1.0.7",
+        "process-nextick-args": "^2.0.0",
         "stream-exhaust": "^1.0.1"
       }
     },
     "async-each": {
-      "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/async-each/download/async-each-1.0.1.tgz",
-      "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0="
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ=="
     },
     "async-limiter": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
-      "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+      "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
     },
     "async-settle": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/async-settle/download/async-settle-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz",
       "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=",
       "requires": {
         "async-done": "^1.2.2"
       "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
     },
     "aws4": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
-      "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
+      "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
     },
     "bach": {
       "version": "1.2.0",
-      "resolved": "http://registry.npm.taobao.org/bach/download/bach-1.2.0.tgz",
+      "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz",
       "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=",
       "requires": {
         "arr-filter": "^1.1.1",
     },
     "base": {
       "version": "0.11.2",
-      "resolved": "http://registry.npm.taobao.org/base/download/base-0.11.2.tgz",
-      "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
       "requires": {
         "cache-base": "^1.0.1",
         "class-utils": "^0.3.5",
       "dependencies": {
         "define-property": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
           "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
           "requires": {
             "is-descriptor": "^1.0.0"
         },
         "is-accessor-descriptor": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
           "requires": {
             "kind-of": "^6.0.0"
           }
         },
         "is-data-descriptor": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
           "requires": {
             "kind-of": "^6.0.0"
           }
         },
         "is-descriptor": {
           "version": "1.0.2",
-          "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz",
-          "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
           "requires": {
             "is-accessor-descriptor": "^1.0.0",
             "is-data-descriptor": "^1.0.0",
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
       "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
-      "optional": true,
       "requires": {
         "tweetnacl": "^0.14.3"
       }
       "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak="
     },
     "binary-extensions": {
-      "version": "1.12.0",
-      "resolved": "http://registry.npm.taobao.org/binary-extensions/download/binary-extensions-1.12.0.tgz",
-      "integrity": "sha1-wteA9T1Fu6gxeokC1M7q86Y4WxQ="
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+      "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw=="
+    },
+    "bindings": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+      "optional": true,
+      "requires": {
+        "file-uri-to-path": "1.0.0"
+      }
     },
     "boolbase": {
       "version": "1.0.0",
     },
     "braces": {
       "version": "2.3.2",
-      "resolved": "http://registry.npm.taobao.org/braces/download/braces-2.3.2.tgz",
-      "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+      "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
       "requires": {
         "arr-flatten": "^1.1.0",
         "array-unique": "^0.3.2",
       "dependencies": {
         "extend-shallow": {
           "version": "2.0.1",
-          "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
           "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
           "requires": {
             "is-extendable": "^0.1.0"
       }
     },
     "browser-process-hrtime": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz",
-      "integrity": "sha1-Ql1opY00R/AqBKqJQYf86K+Le44="
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz",
+      "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw=="
     },
     "browserslist": {
       "version": "4.5.2",
     },
     "buffer-equal": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/buffer-equal/download/buffer-equal-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
       "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74="
     },
     "buffer-from": {
       "version": "1.1.1",
-      "resolved": "http://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz",
-      "integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8="
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
     },
     "builtin-modules": {
       "version": "1.1.1",
     },
     "cache-base": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/cache-base/download/cache-base-1.0.1.tgz",
-      "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
       "requires": {
         "collection-visit": "^1.0.0",
         "component-emitter": "^1.2.1",
       "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
       "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
     },
+    "ccount": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz",
+      "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw=="
+    },
     "chalk": {
       "version": "1.1.3",
       "resolved": "http://registry.npm.taobao.org/chalk/download/chalk-1.1.3.tgz",
         }
       }
     },
+    "character-entities-html4": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
+      "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g=="
+    },
+    "character-entities-legacy": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+      "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA=="
+    },
     "chokidar": {
-      "version": "2.0.4",
-      "resolved": "http://registry.npm.taobao.org/chokidar/download/chokidar-2.0.4.tgz",
-      "integrity": "sha1-NW/04rDo5D4yLRijckYLvPOszSY=",
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+      "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
       "requires": {
         "anymatch": "^2.0.0",
-        "async-each": "^1.0.0",
-        "braces": "^2.3.0",
-        "fsevents": "^1.2.2",
+        "async-each": "^1.0.1",
+        "braces": "^2.3.2",
+        "fsevents": "^1.2.7",
         "glob-parent": "^3.1.0",
-        "inherits": "^2.0.1",
+        "inherits": "^2.0.3",
         "is-binary-path": "^1.0.0",
         "is-glob": "^4.0.0",
-        "lodash.debounce": "^4.0.8",
-        "normalize-path": "^2.1.1",
+        "normalize-path": "^3.0.0",
         "path-is-absolute": "^1.0.0",
-        "readdirp": "^2.0.0",
-        "upath": "^1.0.5"
+        "readdirp": "^2.2.1",
+        "upath": "^1.1.1"
+      },
+      "dependencies": {
+        "normalize-path": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
+        }
       }
     },
     "clang-format": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/clang-format/-/clang-format-1.2.4.tgz",
-      "integrity": "sha512-sw+nrGUp3hvmANd1qF8vZPuezSYQAiXgGBiEtkXTtJnnu6b00fCqkkDIsnRKrNgg4nv6NYZE92ejvOMIXZoejw==",
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/clang-format/-/clang-format-1.4.0.tgz",
+      "integrity": "sha512-NrdyUnHJOGvMa60vbWk7GJTvOdhibj3uK5C0FlwdNG4301OUvqEJTFce9I9x8qw2odBbIVrJ+9xbsFS3a4FbDA==",
       "requires": {
         "async": "^1.5.2",
         "glob": "^7.0.0",
     },
     "class-utils": {
       "version": "0.3.6",
-      "resolved": "http://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz",
-      "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
       "requires": {
         "arr-union": "^3.1.0",
         "define-property": "^0.2.5",
       "dependencies": {
         "define-property": {
           "version": "0.2.5",
-          "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
           "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
           "requires": {
             "is-descriptor": "^0.1.0"
     },
     "clone": {
       "version": "2.1.2",
-      "resolved": "http://registry.npm.taobao.org/clone/download/clone-2.1.2.tgz",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
       "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18="
     },
     "clone-buffer": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/clone-buffer/download/clone-buffer-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
       "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg="
     },
     "clone-stats": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/clone-stats/download/clone-stats-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
       "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA="
     },
     "cloneable-readable": {
-      "version": "1.1.2",
-      "resolved": "http://registry.npm.taobao.org/cloneable-readable/download/cloneable-readable-1.1.2.tgz",
-      "integrity": "sha1-1ZHe5Kj4vBXaQ86X3O66E9Q+KmU=",
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz",
+      "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==",
       "requires": {
         "inherits": "^2.0.1",
         "process-nextick-args": "^2.0.0",
         "readable-stream": "^2.3.5"
-      },
-      "dependencies": {
-        "process-nextick-args": {
-          "version": "2.0.0",
-          "resolved": "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.0.tgz",
-          "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o="
-        }
       }
     },
-    "co": {
-      "version": "4.6.0",
-      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
-      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
-    },
     "coa": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
       "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
       "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
     },
+    "collapse-white-space": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
+      "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ=="
+    },
     "collection-map": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/collection-map/download/collection-map-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz",
       "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=",
       "requires": {
         "arr-map": "^2.0.2",
     },
     "collection-visit": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/collection-visit/download/collection-visit-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
       "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
       "requires": {
         "map-visit": "^1.0.0",
       "integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI="
     },
     "combined-stream": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
-      "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
       "requires": {
         "delayed-stream": "~1.0.0"
       }
     },
+    "comma-separated-tokens": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz",
+      "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw=="
+    },
     "commander": {
       "version": "2.17.1",
       "resolved": "http://registry.npm.taobao.org/commander/download/commander-2.17.1.tgz",
       "integrity": "sha1-vXerfebelCBc6sxy8XFtKfIKd78="
     },
     "component-emitter": {
-      "version": "1.2.1",
-      "resolved": "http://registry.npm.taobao.org/component-emitter/download/component-emitter-1.2.1.tgz",
-      "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
     },
     "concat-map": {
       "version": "0.0.1",
     },
     "concat-stream": {
       "version": "1.6.2",
-      "resolved": "http://registry.npm.taobao.org/concat-stream/download/concat-stream-1.6.2.tgz",
-      "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
       "requires": {
         "buffer-from": "^1.0.0",
         "inherits": "^2.0.3",
       }
     },
     "convert-source-map": {
-      "version": "1.6.0",
-      "resolved": "http://registry.npm.taobao.org/convert-source-map/download/convert-source-map-1.6.0.tgz",
-      "integrity": "sha1-UbU3qMQ+DwTewZk7/83VBOdYrCA=",
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+      "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
       "requires": {
         "safe-buffer": "~5.1.1"
       }
     },
     "copy-descriptor": {
       "version": "0.1.1",
-      "resolved": "http://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
       "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
     },
     "copy-props": {
       "version": "2.0.4",
-      "resolved": "http://registry.npm.taobao.org/copy-props/download/copy-props-2.0.4.tgz",
-      "integrity": "sha1-k7scrfr9MdpbuKnUtB9HHsOnLf4=",
+      "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz",
+      "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==",
       "requires": {
         "each-props": "^1.3.0",
         "is-plain-object": "^2.0.1"
       }
     },
     "cssom": {
-      "version": "0.3.4",
-      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz",
-      "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog=="
+      "version": "0.3.8",
+      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
+      "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
     },
     "cssstyle": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.1.1.tgz",
-      "integrity": "sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==",
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz",
+      "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==",
       "requires": {
         "cssom": "0.3.x"
       }
     },
     "d": {
-      "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/d/download/d-1.0.0.tgz",
-      "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
       "requires": {
-        "es5-ext": "^0.10.9"
+        "es5-ext": "^0.10.50",
+        "type": "^1.0.1"
       }
     },
     "dashdash": {
       }
     },
     "data-urls": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.0.1.tgz",
-      "integrity": "sha512-0HdcMZzK6ubMUnsMmQmG0AcLQPvbvb47R0+7CCZQCYgcd8OUWG91CG7sM6GoXgjz+WLl4ArFzHtBMy/QqSF4eg==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz",
+      "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==",
       "requires": {
         "abab": "^2.0.0",
-        "whatwg-mimetype": "^2.1.0",
+        "whatwg-mimetype": "^2.2.0",
         "whatwg-url": "^7.0.0"
       },
       "dependencies": {
         "whatwg-url": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
-          "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
+          "version": "7.1.0",
+          "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
+          "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
           "requires": {
             "lodash.sortby": "^4.7.0",
             "tr46": "^1.0.1",
     },
     "debug": {
       "version": "2.6.9",
-      "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz",
-      "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
       "requires": {
         "ms": "2.0.0"
       }
     },
     "default-compare": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/default-compare/download/default-compare-1.0.0.tgz",
-      "integrity": "sha1-y2ETGESthNhHiPto/QFoHKd4Gi8=",
+      "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz",
+      "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==",
       "requires": {
         "kind-of": "^5.0.2"
       },
       "dependencies": {
         "kind-of": {
           "version": "5.1.0",
-          "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-5.1.0.tgz",
-          "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0="
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
         }
       }
     },
     "default-resolution": {
       "version": "2.0.0",
-      "resolved": "http://registry.npm.taobao.org/default-resolution/download/default-resolution-2.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz",
       "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ="
     },
     "define-properties": {
     },
     "define-property": {
       "version": "2.0.2",
-      "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-2.0.2.tgz",
-      "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
       "requires": {
         "is-descriptor": "^1.0.2",
         "isobject": "^3.0.1"
       "dependencies": {
         "is-accessor-descriptor": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
           "requires": {
             "kind-of": "^6.0.0"
           }
         },
         "is-data-descriptor": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
           "requires": {
             "kind-of": "^6.0.0"
           }
         },
         "is-descriptor": {
           "version": "1.0.2",
-          "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz",
-          "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
           "requires": {
             "is-accessor-descriptor": "^1.0.0",
             "is-data-descriptor": "^1.0.0",
       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
       "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
     },
+    "detab": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.3.tgz",
+      "integrity": "sha512-Up8P0clUVwq0FnFjDclzZsy9PadzRn5FFxrr47tQQvMHqyiFYVbpH8oXDzWtF0Q7pYy3l+RPmtBl+BsFF6wH0A==",
+      "requires": {
+        "repeat-string": "^1.5.4"
+      }
+    },
     "detect-file": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/detect-file/download/detect-file-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
       "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc="
     },
     "dom-serializer": {
       }
     },
     "duplexify": {
-      "version": "3.6.1",
-      "resolved": "http://registry.npm.taobao.org/duplexify/download/duplexify-3.6.1.tgz",
-      "integrity": "sha1-saeinEq/1jlYXvrszoDWZrHjQSU=",
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+      "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
       "requires": {
         "end-of-stream": "^1.0.0",
         "inherits": "^2.0.1",
     },
     "each-props": {
       "version": "1.3.2",
-      "resolved": "http://registry.npm.taobao.org/each-props/download/each-props-1.3.2.tgz",
-      "integrity": "sha1-6kWkFNFt1c+kGbGoFyDVygaJIzM=",
+      "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz",
+      "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==",
       "requires": {
         "is-plain-object": "^2.0.1",
         "object.defaults": "^1.1.0"
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
       "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
-      "optional": true,
       "requires": {
         "jsbn": "~0.1.0",
         "safer-buffer": "^2.1.0"
       }
     },
     "es5-ext": {
-      "version": "0.10.46",
-      "resolved": "http://registry.npm.taobao.org/es5-ext/download/es5-ext-0.10.46.tgz",
-      "integrity": "sha1-79mfZ8Wn7Hibqj2qf3mHA4j39XI=",
+      "version": "0.10.53",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz",
+      "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==",
       "requires": {
         "es6-iterator": "~2.0.3",
-        "es6-symbol": "~3.1.1",
-        "next-tick": "1"
+        "es6-symbol": "~3.1.3",
+        "next-tick": "~1.0.0"
       }
     },
     "es6-iterator": {
       "version": "2.0.3",
-      "resolved": "http://registry.npm.taobao.org/es6-iterator/download/es6-iterator-2.0.3.tgz",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
       "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
       "requires": {
         "d": "1",
       }
     },
     "es6-symbol": {
-      "version": "3.1.1",
-      "resolved": "http://registry.npm.taobao.org/es6-symbol/download/es6-symbol-3.1.1.tgz",
-      "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+      "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
       "requires": {
-        "d": "1",
-        "es5-ext": "~0.10.14"
+        "d": "^1.0.1",
+        "ext": "^1.1.2"
       }
     },
     "es6-weak-map": {
-      "version": "2.0.2",
-      "resolved": "http://registry.npm.taobao.org/es6-weak-map/download/es6-weak-map-2.0.2.tgz",
-      "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
+      "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
       "requires": {
         "d": "1",
-        "es5-ext": "^0.10.14",
-        "es6-iterator": "^2.0.1",
+        "es5-ext": "^0.10.46",
+        "es6-iterator": "^2.0.3",
         "es6-symbol": "^3.1.1"
       }
     },
       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
     },
     "escodegen": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz",
-      "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==",
+      "version": "1.13.0",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.13.0.tgz",
+      "integrity": "sha512-eYk2dCkxR07DsHA/X2hRBj0CFAZeri/LyDMc0C8JT1Hqi6JnVpMhJ7XFITbb0+yZS3lVkaPL2oCkZ3AVmeVbMw==",
       "requires": {
-        "esprima": "^3.1.3",
+        "esprima": "^4.0.1",
         "estraverse": "^4.2.0",
         "esutils": "^2.0.2",
         "optionator": "^0.8.1",
       }
     },
     "esprima": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
-      "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
     },
     "estraverse": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
-      "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
     },
     "esutils": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
-      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
     },
     "execa": {
       "version": "0.7.0",
     },
     "expand-brackets": {
       "version": "2.1.4",
-      "resolved": "http://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
       "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
       "requires": {
         "debug": "^2.3.3",
       "dependencies": {
         "define-property": {
           "version": "0.2.5",
-          "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
           "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
           "requires": {
             "is-descriptor": "^0.1.0"
         },
         "extend-shallow": {
           "version": "2.0.1",
-          "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
           "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
           "requires": {
             "is-extendable": "^0.1.0"
     },
     "expand-tilde": {
       "version": "2.0.2",
-      "resolved": "http://registry.npm.taobao.org/expand-tilde/download/expand-tilde-2.0.2.tgz",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
       "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
       "requires": {
         "homedir-polyfill": "^1.0.1"
       }
     },
+    "ext": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz",
+      "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==",
+      "requires": {
+        "type": "^2.0.0"
+      },
+      "dependencies": {
+        "type": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz",
+          "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow=="
+        }
+      }
+    },
     "extend": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
     },
     "extglob": {
       "version": "2.0.4",
-      "resolved": "http://registry.npm.taobao.org/extglob/download/extglob-2.0.4.tgz",
-      "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
       "requires": {
         "array-unique": "^0.3.2",
         "define-property": "^1.0.0",
       "dependencies": {
         "define-property": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
           "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
           "requires": {
             "is-descriptor": "^1.0.0"
         },
         "extend-shallow": {
           "version": "2.0.1",
-          "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
           "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
           "requires": {
             "is-extendable": "^0.1.0"
         },
         "is-accessor-descriptor": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
           "requires": {
             "kind-of": "^6.0.0"
           }
         },
         "is-data-descriptor": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
           "requires": {
             "kind-of": "^6.0.0"
           }
         },
         "is-descriptor": {
           "version": "1.0.2",
-          "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz",
-          "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
           "requires": {
             "is-accessor-descriptor": "^1.0.0",
             "is-data-descriptor": "^1.0.0",
       }
     },
     "fast-deep-equal": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
-      "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+      "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
     },
     "fast-json-stable-stringify": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
-      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
     },
     "fast-levenshtein": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
       "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
     },
+    "file-uri-to-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+      "optional": true
+    },
     "fill-range": {
       "version": "4.0.0",
-      "resolved": "http://registry.npm.taobao.org/fill-range/download/fill-range-4.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
       "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
       "requires": {
         "extend-shallow": "^2.0.1",
       "dependencies": {
         "extend-shallow": {
           "version": "2.0.1",
-          "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
           "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
           "requires": {
             "is-extendable": "^0.1.0"
       }
     },
     "findup-sync": {
-      "version": "2.0.0",
-      "resolved": "http://registry.npm.taobao.org/findup-sync/download/findup-sync-2.0.0.tgz",
-      "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
+      "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
       "requires": {
         "detect-file": "^1.0.0",
-        "is-glob": "^3.1.0",
+        "is-glob": "^4.0.0",
         "micromatch": "^3.0.4",
         "resolve-dir": "^1.0.1"
-      },
-      "dependencies": {
-        "is-glob": {
-          "version": "3.1.0",
-          "resolved": "http://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz",
-          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
-          "requires": {
-            "is-extglob": "^2.1.0"
-          }
-        }
       }
     },
     "fined": {
-      "version": "1.1.1",
-      "resolved": "http://registry.npm.taobao.org/fined/download/fined-1.1.1.tgz",
-      "integrity": "sha1-ldiP8ykSPdGmlQ/fzTIfdGJx4B8=",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz",
+      "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==",
       "requires": {
         "expand-tilde": "^2.0.2",
         "is-plain-object": "^2.0.3",
     },
     "flagged-respawn": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/flagged-respawn/download/flagged-respawn-1.0.1.tgz",
-      "integrity": "sha1-595vEnnd2cqarIpZcdYYYGs6q0E="
+      "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz",
+      "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q=="
     },
     "flush-write-stream": {
-      "version": "1.0.3",
-      "resolved": "http://registry.npm.taobao.org/flush-write-stream/download/flush-write-stream-1.0.3.tgz",
-      "integrity": "sha1-xdWG7zivYJdlC0m8QbVfq7GfNb0=",
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+      "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
       "requires": {
-        "inherits": "^2.0.1",
-        "readable-stream": "^2.0.4"
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.3.6"
       }
     },
     "for-in": {
       "version": "1.0.2",
-      "resolved": "http://registry.npm.taobao.org/for-in/download/for-in-1.0.2.tgz",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
       "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
     },
     "for-own": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/for-own/download/for-own-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
       "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
       "requires": {
         "for-in": "^1.0.1"
       "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
     },
     "form-data": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
-      "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+      "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
       "requires": {
         "asynckit": "^0.4.0",
-        "combined-stream": "1.0.6",
+        "combined-stream": "^1.0.6",
         "mime-types": "^2.1.12"
       }
     },
     "fragment-cache": {
       "version": "0.2.1",
-      "resolved": "http://registry.npm.taobao.org/fragment-cache/download/fragment-cache-0.2.1.tgz",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
       "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
       "requires": {
         "map-cache": "^0.2.2"
     },
     "fs-mkdirp-stream": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/fs-mkdirp-stream/download/fs-mkdirp-stream-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
       "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=",
       "requires": {
         "graceful-fs": "^4.1.11",
       "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
     },
     "fsevents": {
-      "version": "1.2.9",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
-      "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
+      "version": "1.2.11",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz",
+      "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==",
       "optional": true,
       "requires": {
+        "bindings": "^1.5.0",
         "nan": "^2.12.1",
-        "node-pre-gyp": "^0.12.0"
+        "node-pre-gyp": "*"
       },
       "dependencies": {
         "abbrev": {
           }
         },
         "chownr": {
-          "version": "1.1.1",
+          "version": "1.1.3",
           "bundled": true,
           "optional": true
         },
           "optional": true
         },
         "debug": {
-          "version": "4.1.1",
+          "version": "3.2.6",
           "bundled": true,
           "optional": true,
           "requires": {
           "optional": true
         },
         "fs-minipass": {
-          "version": "1.2.5",
+          "version": "1.2.7",
           "bundled": true,
           "optional": true,
           "requires": {
-            "minipass": "^2.2.1"
+            "minipass": "^2.6.0"
           }
         },
         "fs.realpath": {
           }
         },
         "glob": {
-          "version": "7.1.3",
+          "version": "7.1.6",
           "bundled": true,
           "optional": true,
           "requires": {
           }
         },
         "ignore-walk": {
-          "version": "3.0.1",
+          "version": "3.0.3",
           "bundled": true,
           "optional": true,
           "requires": {
           }
         },
         "inherits": {
-          "version": "2.0.3",
+          "version": "2.0.4",
           "bundled": true,
           "optional": true
         },
           "optional": true
         },
         "minipass": {
-          "version": "2.3.5",
+          "version": "2.9.0",
           "bundled": true,
           "optional": true,
           "requires": {
           }
         },
         "minizlib": {
-          "version": "1.2.1",
+          "version": "1.3.3",
           "bundled": true,
           "optional": true,
           "requires": {
-            "minipass": "^2.2.1"
+            "minipass": "^2.9.0"
           }
         },
         "mkdirp": {
           }
         },
         "ms": {
-          "version": "2.1.1",
+          "version": "2.1.2",
           "bundled": true,
           "optional": true
         },
         "needle": {
-          "version": "2.3.0",
+          "version": "2.4.0",
           "bundled": true,
           "optional": true,
           "requires": {
-            "debug": "^4.1.0",
+            "debug": "^3.2.6",
             "iconv-lite": "^0.4.4",
             "sax": "^1.2.4"
           }
         },
         "node-pre-gyp": {
-          "version": "0.12.0",
+          "version": "0.14.0",
           "bundled": true,
           "optional": true,
           "requires": {
             "rc": "^1.2.7",
             "rimraf": "^2.6.1",
             "semver": "^5.3.0",
-            "tar": "^4"
+            "tar": "^4.4.2"
           }
         },
         "nopt": {
           }
         },
         "npm-bundled": {
-          "version": "1.0.6",
+          "version": "1.1.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "npm-normalize-package-bin": "^1.0.1"
+          }
+        },
+        "npm-normalize-package-bin": {
+          "version": "1.0.1",
           "bundled": true,
           "optional": true
         },
         "npm-packlist": {
-          "version": "1.4.1",
+          "version": "1.4.7",
           "bundled": true,
           "optional": true,
           "requires": {
           "optional": true
         },
         "process-nextick-args": {
-          "version": "2.0.0",
+          "version": "2.0.1",
           "bundled": true,
           "optional": true
         },
           }
         },
         "rimraf": {
-          "version": "2.6.3",
+          "version": "2.7.1",
           "bundled": true,
           "optional": true,
           "requires": {
           "optional": true
         },
         "semver": {
-          "version": "5.7.0",
+          "version": "5.7.1",
           "bundled": true,
           "optional": true
         },
           "optional": true
         },
         "tar": {
-          "version": "4.4.8",
+          "version": "4.4.13",
           "bundled": true,
           "optional": true,
           "requires": {
             "chownr": "^1.1.1",
             "fs-minipass": "^1.2.5",
-            "minipass": "^2.3.4",
-            "minizlib": "^1.1.1",
+            "minipass": "^2.8.6",
+            "minizlib": "^1.2.1",
             "mkdirp": "^0.5.0",
             "safe-buffer": "^5.1.2",
-            "yallist": "^3.0.2"
+            "yallist": "^3.0.3"
           }
         },
         "util-deprecate": {
           "optional": true
         },
         "yallist": {
-          "version": "3.0.3",
+          "version": "3.1.1",
           "bundled": true,
           "optional": true
         }
     },
     "get-value": {
       "version": "2.0.6",
-      "resolved": "http://registry.npm.taobao.org/get-value/download/get-value-2.0.6.tgz",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
       "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
     },
     "getpass": {
     },
     "glob-parent": {
       "version": "3.1.0",
-      "resolved": "http://registry.npm.taobao.org/glob-parent/download/glob-parent-3.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
       "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
       "requires": {
         "is-glob": "^3.1.0",
       "dependencies": {
         "is-glob": {
           "version": "3.1.0",
-          "resolved": "http://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
           "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
           "requires": {
             "is-extglob": "^2.1.0"
     },
     "glob-stream": {
       "version": "6.1.0",
-      "resolved": "http://registry.npm.taobao.org/glob-stream/download/glob-stream-6.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz",
       "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=",
       "requires": {
         "extend": "^3.0.0",
     },
     "glob-watcher": {
       "version": "5.0.3",
-      "resolved": "http://registry.npm.taobao.org/glob-watcher/download/glob-watcher-5.0.3.tgz",
-      "integrity": "sha1-iKir8cTRMeuTkomUvEpZPC5d1iY=",
+      "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz",
+      "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==",
       "requires": {
         "anymatch": "^2.0.0",
         "async-done": "^1.2.0",
     },
     "global-modules": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/global-modules/download/global-modules-1.0.0.tgz",
-      "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+      "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
       "requires": {
         "global-prefix": "^1.0.1",
         "is-windows": "^1.0.1",
     },
     "global-prefix": {
       "version": "1.0.2",
-      "resolved": "http://registry.npm.taobao.org/global-prefix/download/global-prefix-1.0.2.tgz",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
       "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
       "requires": {
         "expand-tilde": "^2.0.2",
       "integrity": "sha1-/7cD4QZuig7qpMi4C6klPu77+wA="
     },
     "gulp": {
-      "version": "4.0.0",
-      "resolved": "http://registry.npm.taobao.org/gulp/download/gulp-4.0.0.tgz",
-      "integrity": "sha1-lXZsYB2t5Kd+0+eyttwDiBtZY2Y=",
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz",
+      "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==",
       "requires": {
-        "glob-watcher": "^5.0.0",
-        "gulp-cli": "^2.0.0",
-        "undertaker": "^1.0.0",
+        "glob-watcher": "^5.0.3",
+        "gulp-cli": "^2.2.0",
+        "undertaker": "^1.2.1",
         "vinyl-fs": "^3.0.0"
       },
       "dependencies": {
         "ansi-regex": {
           "version": "2.1.1",
-          "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
           "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
         },
         "camelcase": {
           "version": "3.0.0",
-          "resolved": "http://registry.npm.taobao.org/camelcase/download/camelcase-3.0.0.tgz",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
           "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
         },
         "cliui": {
           "version": "3.2.0",
-          "resolved": "http://registry.npm.taobao.org/cliui/download/cliui-3.2.0.tgz",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
           "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
           "requires": {
             "string-width": "^1.0.1",
           }
         },
         "gulp-cli": {
-          "version": "2.0.1",
-          "resolved": "http://registry.npm.taobao.org/gulp-cli/download/gulp-cli-2.0.1.tgz",
-          "integrity": "sha1-eEfiIMs2YvK+im1XK/FOF75amUs=",
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.2.0.tgz",
+          "integrity": "sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA==",
           "requires": {
             "ansi-colors": "^1.0.1",
             "archy": "^1.0.0",
             "gulplog": "^1.0.0",
             "interpret": "^1.1.0",
             "isobject": "^3.0.1",
-            "liftoff": "^2.5.0",
+            "liftoff": "^3.1.0",
             "matchdep": "^2.0.0",
             "mute-stdout": "^1.0.0",
             "pretty-hrtime": "^1.0.0",
         },
         "is-fullwidth-code-point": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-1.0.0.tgz",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
           "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
           "requires": {
             "number-is-nan": "^1.0.0"
         },
         "os-locale": {
           "version": "1.4.0",
-          "resolved": "http://registry.npm.taobao.org/os-locale/download/os-locale-1.4.0.tgz",
+          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
           "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
           "requires": {
             "lcid": "^1.0.0"
         },
         "string-width": {
           "version": "1.0.2",
-          "resolved": "http://registry.npm.taobao.org/string-width/download/string-width-1.0.2.tgz",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
           "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
           "requires": {
             "code-point-at": "^1.0.0",
         },
         "strip-ansi": {
           "version": "3.0.1",
-          "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
           "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
           "requires": {
             "ansi-regex": "^2.0.0"
         },
         "which-module": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/which-module/download/which-module-1.0.0.tgz",
+          "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
           "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8="
         },
         "yargs": {
           "version": "7.1.0",
-          "resolved": "http://registry.npm.taobao.org/yargs/download/yargs-7.1.0.tgz",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
           "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
           "requires": {
             "camelcase": "^3.0.0",
         },
         "yargs-parser": {
           "version": "5.0.0",
-          "resolved": "http://registry.npm.taobao.org/yargs-parser/download/yargs-parser-5.0.0.tgz",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
           "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
           "requires": {
             "camelcase": "^3.0.0"
       "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
     },
     "har-validator": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz",
-      "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==",
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+      "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
       "requires": {
-        "ajv": "^5.3.0",
+        "ajv": "^6.5.5",
         "har-schema": "^2.0.0"
       }
     },
     },
     "has-value": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/has-value/download/has-value-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
       "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
       "requires": {
         "get-value": "^2.0.6",
     },
     "has-values": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/has-values/download/has-values-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
       "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
       "requires": {
         "is-number": "^3.0.0",
       "dependencies": {
         "kind-of": {
           "version": "4.0.0",
-          "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-4.0.0.tgz",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
           "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
           "requires": {
             "is-buffer": "^1.1.5"
         }
       }
     },
+    "hast-util-is-element": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.0.3.tgz",
+      "integrity": "sha512-C62CVn7jbjp89yOhhy7vrkSaB7Vk906Gtcw/Ihd+Iufnq+2pwOZjdPmpzpKLWJXPJBMDX3wXg4FqmdOayPcewA=="
+    },
+    "hast-util-to-html": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-6.1.0.tgz",
+      "integrity": "sha512-IlC+LG2HGv0Y8js3wqdhg9O2sO4iVpRDbHOPwXd7qgeagpGsnY49i8yyazwqS35RA35WCzrBQE/n0M6GG/ewxA==",
+      "requires": {
+        "ccount": "^1.0.0",
+        "comma-separated-tokens": "^1.0.1",
+        "hast-util-is-element": "^1.0.0",
+        "hast-util-whitespace": "^1.0.0",
+        "html-void-elements": "^1.0.0",
+        "property-information": "^5.2.0",
+        "space-separated-tokens": "^1.0.0",
+        "stringify-entities": "^2.0.0",
+        "unist-util-is": "^3.0.0",
+        "xtend": "^4.0.1"
+      },
+      "dependencies": {
+        "unist-util-is": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
+          "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A=="
+        }
+      }
+    },
+    "hast-util-whitespace": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.3.tgz",
+      "integrity": "sha512-AlkYiLTTwPOyxZ8axq2/bCwRUPjIPBfrHkXuCR92B38b3lSdU22R5F/Z4DL6a2kxWpekWq1w6Nj48tWat6GeRA=="
+    },
     "he": {
       "version": "1.2.0",
       "resolved": "http://registry.npm.taobao.org/he/download/he-1.2.0.tgz",
       "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
     },
     "homedir-polyfill": {
-      "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/homedir-polyfill/download/homedir-polyfill-1.0.1.tgz",
-      "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
       "requires": {
         "parse-passwd": "^1.0.0"
       }
         "uglify-js": "3.4.x"
       }
     },
+    "html-void-elements": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz",
+      "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w=="
+    },
     "http-signature": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
       }
     },
     "iconv-lite": {
-      "version": "0.4.23",
-      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
-      "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
       "requires": {
         "safer-buffer": ">= 2.1.2 < 3"
       }
     },
     "ini": {
       "version": "1.3.5",
-      "resolved": "http://registry.npm.taobao.org/ini/download/ini-1.3.5.tgz",
-      "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc="
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
     },
     "interpret": {
-      "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/interpret/download/interpret-1.1.0.tgz",
-      "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
+      "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw=="
     },
     "invert-kv": {
       "version": "1.0.0",
     },
     "is-absolute": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/is-absolute/download/is-absolute-1.0.0.tgz",
-      "integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=",
+      "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+      "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
       "requires": {
         "is-relative": "^1.0.0",
         "is-windows": "^1.0.1"
     },
     "is-accessor-descriptor": {
       "version": "0.1.6",
-      "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
       "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
       "requires": {
         "kind-of": "^3.0.2"
       "dependencies": {
         "kind-of": {
           "version": "3.2.2",
-          "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
           "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
           "requires": {
             "is-buffer": "^1.1.5"
         }
       }
     },
+    "is-alphabetical": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
+      "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="
+    },
+    "is-alphanumerical": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
+      "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
+      "requires": {
+        "is-alphabetical": "^1.0.0",
+        "is-decimal": "^1.0.0"
+      }
+    },
     "is-arrayish": {
       "version": "0.2.1",
       "resolved": "http://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.2.1.tgz",
     },
     "is-binary-path": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/is-binary-path/download/is-binary-path-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
       "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
       "requires": {
         "binary-extensions": "^1.0.0"
     },
     "is-buffer": {
       "version": "1.1.6",
-      "resolved": "http://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz",
-      "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4="
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
     },
     "is-builtin-module": {
       "version": "1.0.0",
     },
     "is-data-descriptor": {
       "version": "0.1.4",
-      "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
       "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
       "requires": {
         "kind-of": "^3.0.2"
       "dependencies": {
         "kind-of": {
           "version": "3.2.2",
-          "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
           "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
           "requires": {
             "is-buffer": "^1.1.5"
       "resolved": "http://registry.npm.taobao.org/is-date-object/download/is-date-object-1.0.1.tgz",
       "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
     },
+    "is-decimal": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
+      "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw=="
+    },
     "is-descriptor": {
       "version": "0.1.6",
-      "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-0.1.6.tgz",
-      "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
       "requires": {
         "is-accessor-descriptor": "^0.1.6",
         "is-data-descriptor": "^0.1.4",
       "dependencies": {
         "kind-of": {
           "version": "5.1.0",
-          "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-5.1.0.tgz",
-          "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0="
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
         }
       }
     },
     },
     "is-extendable": {
       "version": "0.1.1",
-      "resolved": "http://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
       "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
     },
     "is-extglob": {
       "version": "2.1.1",
-      "resolved": "http://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
       "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
     },
     "is-fullwidth-code-point": {
       "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
     },
     "is-glob": {
-      "version": "4.0.0",
-      "resolved": "http://registry.npm.taobao.org/is-glob/download/is-glob-4.0.0.tgz",
-      "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
       "requires": {
         "is-extglob": "^2.1.1"
       }
     },
+    "is-hexadecimal": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
+      "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw=="
+    },
     "is-negated-glob": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/is-negated-glob/download/is-negated-glob-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
       "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI="
     },
     "is-number": {
       "version": "3.0.0",
-      "resolved": "http://registry.npm.taobao.org/is-number/download/is-number-3.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
       "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
       "requires": {
         "kind-of": "^3.0.2"
       "dependencies": {
         "kind-of": {
           "version": "3.2.2",
-          "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
           "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
           "requires": {
             "is-buffer": "^1.1.5"
     },
     "is-relative": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/is-relative/download/is-relative-1.0.0.tgz",
-      "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=",
+      "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+      "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
       "requires": {
         "is-unc-path": "^1.0.0"
       }
     },
     "is-unc-path": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/is-unc-path/download/is-unc-path-1.0.0.tgz",
-      "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=",
+      "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+      "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
       "requires": {
         "unc-path-regex": "^0.1.2"
       }
     },
     "is-utf8": {
       "version": "0.2.1",
-      "resolved": "http://registry.npm.taobao.org/is-utf8/download/is-utf8-0.2.1.tgz",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
       "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
     },
     "is-valid-glob": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/is-valid-glob/download/is-valid-glob-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
       "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao="
     },
     "is-windows": {
       "version": "1.0.2",
-      "resolved": "http://registry.npm.taobao.org/is-windows/download/is-windows-1.0.2.tgz",
-      "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0="
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
     },
     "isarray": {
       "version": "1.0.0",
     "jsbn": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
-      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
-      "optional": true
+      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
     },
     "jsdom": {
       "version": "11.12.0",
       "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
     },
     "json-schema-traverse": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
-      "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
     },
     "json-stable-stringify-without-jsonify": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/json-stable-stringify-without-jsonify/download/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
       "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
     },
     "json-stringify-safe": {
     },
     "just-debounce": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/just-debounce/download/just-debounce-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz",
       "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo="
     },
     "kind-of": {
-      "version": "6.0.2",
-      "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-6.0.2.tgz",
-      "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE="
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
     },
     "last-run": {
       "version": "1.1.1",
-      "resolved": "http://registry.npm.taobao.org/last-run/download/last-run-1.1.1.tgz",
+      "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz",
       "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=",
       "requires": {
         "default-resolution": "^2.0.0",
     },
     "lazystream": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/lazystream/download/lazystream-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
       "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
       "requires": {
         "readable-stream": "^2.0.5"
     },
     "lead": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/lead/download/lead-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz",
       "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=",
       "requires": {
         "flush-write-stream": "^1.0.2"
       }
     },
     "liftoff": {
-      "version": "2.5.0",
-      "resolved": "http://registry.npm.taobao.org/liftoff/download/liftoff-2.5.0.tgz",
-      "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
+      "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==",
       "requires": {
         "extend": "^3.0.0",
-        "findup-sync": "^2.0.0",
+        "findup-sync": "^3.0.0",
         "fined": "^1.0.1",
         "flagged-respawn": "^1.0.0",
         "is-plain-object": "^2.0.4",
     },
     "load-json-file": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/load-json-file/download/load-json-file-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
       "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
       "requires": {
         "graceful-fs": "^4.1.2",
       "resolved": "http://registry.npm.taobao.org/lodash._root/download/lodash._root-3.0.1.tgz",
       "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI="
     },
-    "lodash.debounce": {
-      "version": "4.0.8",
-      "resolved": "http://registry.npm.taobao.org/lodash.debounce/download/lodash.debounce-4.0.8.tgz",
-      "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
-    },
     "lodash.escape": {
       "version": "3.2.0",
       "resolved": "http://registry.npm.taobao.org/lodash.escape/download/lodash.escape-3.2.0.tgz",
     },
     "make-iterator": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/make-iterator/download/make-iterator-1.0.1.tgz",
-      "integrity": "sha1-KbM/MSqo9UfEpeSQ9Wr87JkTOtY=",
+      "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
+      "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
       "requires": {
         "kind-of": "^6.0.2"
       }
     },
     "map-cache": {
       "version": "0.2.2",
-      "resolved": "http://registry.npm.taobao.org/map-cache/download/map-cache-0.2.2.tgz",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
       "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
     },
     "map-visit": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/map-visit/download/map-visit-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
       "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
       "requires": {
         "object-visit": "^1.0.0"
     },
     "matchdep": {
       "version": "2.0.0",
-      "resolved": "http://registry.npm.taobao.org/matchdep/download/matchdep-2.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
       "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=",
       "requires": {
         "findup-sync": "^2.0.0",
         "micromatch": "^3.0.4",
         "resolve": "^1.4.0",
         "stack-trace": "0.0.10"
+      },
+      "dependencies": {
+        "findup-sync": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+          "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
+          "requires": {
+            "detect-file": "^1.0.0",
+            "is-glob": "^3.1.0",
+            "micromatch": "^3.0.4",
+            "resolve-dir": "^1.0.1"
+          }
+        },
+        "is-glob": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+          "requires": {
+            "is-extglob": "^2.1.0"
+          }
+        }
       }
     },
     "mathjax": {
-      "version": "2.7.5",
-      "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.5.tgz",
-      "integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ=="
+      "version": "2.7.7",
+      "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.7.tgz",
+      "integrity": "sha512-OOl0B2/0tSJAtAZarXnQuLDBLgTNRqiI9VqHTQzPsxf4okT2iIpDrvaklK9x2QEMD1sDj4yRn11Ygci41DxMAQ=="
     },
     "mathjax-node": {
       "version": "2.1.1",
       }
     },
     "mathjax-node-page": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/mathjax-node-page/-/mathjax-node-page-3.0.1.tgz",
-      "integrity": "sha512-LlkChMBprwRqiNIhQ6eSuIG/FNt7HUzy0wkm2BD9/guGRLGvYxAmUC+cGbupmmqnuv0S1p0Un04BBoZAWdPqrQ==",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/mathjax-node-page/-/mathjax-node-page-3.2.0.tgz",
+      "integrity": "sha512-06891FqPo9+IPoxFteF9vu8g09cHNUMvIrClTj2EmAOITJWtd2v1JC7V4FL40nZriMcMIkADkZw7eq+fpAA4Ww==",
       "requires": {
         "mathjax-node": "^2.0.0",
         "yargs": "^11.0.0"
       }
     },
     "mdast-comment-marker": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/mdast-comment-marker/-/mdast-comment-marker-1.0.3.tgz",
-      "integrity": "sha512-FZXxBBYeJ/R6k9zgyVGygHWka6FDJdzSbP6kcvB+L4Yqz62po57rZlnA2I14LIKsb3XPEky4vgP0Y83tZXTw7Q=="
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/mdast-comment-marker/-/mdast-comment-marker-1.1.1.tgz",
+      "integrity": "sha512-TWZDaUtPLwKX1pzDIY48MkSUQRDwX/HqbTB4m3iYdL/zosi/Z6Xqfdv0C0hNVKvzrPjZENrpWDt4p4odeVO0Iw=="
+    },
+    "mdast-util-definitions": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-1.2.5.tgz",
+      "integrity": "sha512-CJXEdoLfiISCDc2JB6QLb79pYfI6+GcIH+W2ox9nMc7od0Pz+bovcHsiq29xAQY6ayqe/9CsK2VzkSJdg1pFYA==",
+      "requires": {
+        "unist-util-visit": "^1.0.0"
+      }
     },
     "mdast-util-heading-style": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/mdast-util-heading-style/-/mdast-util-heading-style-1.0.4.tgz",
-      "integrity": "sha512-n4fUvwpR5Uj1Ti658KxYDq9gR0UF3FK1UVTVig12imrSOssQU2OpUysje8nps5Cb85b6eau5akpWW7Zkxtv1XA=="
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/mdast-util-heading-style/-/mdast-util-heading-style-1.0.5.tgz",
+      "integrity": "sha512-8zQkb3IUwiwOdUw6jIhnwM6DPyib+mgzQuHAe7j2Hy1rIarU4VUxe472bp9oktqULW3xqZE+Kz6OD4Gi7IA3vw=="
+    },
+    "mdast-util-to-hast": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-6.0.2.tgz",
+      "integrity": "sha512-GjcOimC9qHI0yNFAQdBesrZXzUkRdFleQlcoU8+TVNfDW6oLUazUx8MgUoTaUyCJzBOnE5AOgqhpURrSlf0QwQ==",
+      "requires": {
+        "collapse-white-space": "^1.0.0",
+        "detab": "^2.0.0",
+        "mdast-util-definitions": "^1.2.0",
+        "mdurl": "^1.0.1",
+        "trim": "0.0.1",
+        "trim-lines": "^1.0.0",
+        "unist-builder": "^1.0.1",
+        "unist-util-generated": "^1.1.0",
+        "unist-util-position": "^3.0.0",
+        "unist-util-visit": "^1.1.0",
+        "xtend": "^4.0.1"
+      }
     },
     "mdast-util-to-string": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.0.5.tgz",
-      "integrity": "sha512-2qLt/DEOo5F6nc2VFScQiHPzQ0XXcabquRJxKMhKte8nt42o08HUxNDPk7tt0YPxnWjAT11I1SYi0X0iPnfI5A=="
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.0.7.tgz",
+      "integrity": "sha512-P+gdtssCoHOX+eJUrrC30Sixqao86ZPlVjR5NEAoy0U79Pfxb1Y0Gntei0+GrnQD4T04X9xA8tcugp90cSmNow=="
     },
     "mdn-data": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz",
       "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA=="
     },
+    "mdurl": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+      "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
+    },
     "mem": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
     },
     "micromatch": {
       "version": "3.1.10",
-      "resolved": "http://registry.npm.taobao.org/micromatch/download/micromatch-3.1.10.tgz",
-      "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
       "requires": {
         "arr-diff": "^4.0.0",
         "array-unique": "^0.3.2",
       }
     },
     "mime-db": {
-      "version": "1.36.0",
-      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz",
-      "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw=="
+      "version": "1.43.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
+      "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ=="
     },
     "mime-types": {
-      "version": "2.1.20",
-      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz",
-      "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==",
+      "version": "2.1.26",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
+      "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
       "requires": {
-        "mime-db": "~1.36.0"
+        "mime-db": "1.43.0"
       }
     },
     "mimic-fn": {
     },
     "ms": {
       "version": "2.0.0",
-      "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
     },
     "multipipe": {
     },
     "mute-stdout": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/mute-stdout/download/mute-stdout-1.0.1.tgz",
-      "integrity": "sha1-rLAwDrTeI6fd7sAU4+lgRLNHIzE="
+      "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz",
+      "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg=="
     },
     "nan": {
       "version": "2.14.0",
     },
     "nanomatch": {
       "version": "1.2.13",
-      "resolved": "http://registry.npm.taobao.org/nanomatch/download/nanomatch-1.2.13.tgz",
-      "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
       "requires": {
         "arr-diff": "^4.0.0",
         "array-unique": "^0.3.2",
     },
     "next-tick": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/next-tick/download/next-tick-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
       "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
     },
     "nice-try": {
     },
     "normalize-path": {
       "version": "2.1.1",
-      "resolved": "http://registry.npm.taobao.org/normalize-path/download/normalize-path-2.1.1.tgz",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
       "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
       "requires": {
         "remove-trailing-separator": "^1.0.1"
       "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg=="
     },
     "now-and-later": {
-      "version": "2.0.0",
-      "resolved": "http://registry.npm.taobao.org/now-and-later/download/now-and-later-2.0.0.tgz",
-      "integrity": "sha1-vGHLtFbXnLMiB85HygUTb/Ln1u4=",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz",
+      "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==",
       "requires": {
         "once": "^1.3.2"
       }
       "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
     },
     "nwsapi": {
-      "version": "2.0.9",
-      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.9.tgz",
-      "integrity": "sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ=="
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
+      "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ=="
     },
     "oauth-sign": {
       "version": "0.9.0",
     },
     "object-copy": {
       "version": "0.1.0",
-      "resolved": "http://registry.npm.taobao.org/object-copy/download/object-copy-0.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
       "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
       "requires": {
         "copy-descriptor": "^0.1.0",
       "dependencies": {
         "define-property": {
           "version": "0.2.5",
-          "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
           "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
           "requires": {
             "is-descriptor": "^0.1.0"
         },
         "kind-of": {
           "version": "3.2.2",
-          "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
           "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
           "requires": {
             "is-buffer": "^1.1.5"
     },
     "object-visit": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/object-visit/download/object-visit-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
       "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
       "requires": {
         "isobject": "^3.0.0"
     },
     "object.assign": {
       "version": "4.1.0",
-      "resolved": "http://registry.npm.taobao.org/object.assign/download/object.assign-4.1.0.tgz",
-      "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+      "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
       "requires": {
         "define-properties": "^1.1.2",
         "function-bind": "^1.1.1",
     },
     "object.defaults": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/object.defaults/download/object.defaults-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
       "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=",
       "requires": {
         "array-each": "^1.0.1",
     },
     "object.map": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/object.map/download/object.map-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
       "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=",
       "requires": {
         "for-own": "^1.0.0",
     },
     "object.pick": {
       "version": "1.3.0",
-      "resolved": "http://registry.npm.taobao.org/object.pick/download/object.pick-1.3.0.tgz",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
       "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
       "requires": {
         "isobject": "^3.0.1"
     },
     "object.reduce": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/object.reduce/download/object.reduce-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz",
       "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=",
       "requires": {
         "for-own": "^1.0.0",
       }
     },
     "optionator": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
-      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
       "requires": {
         "deep-is": "~0.1.3",
-        "fast-levenshtein": "~2.0.4",
+        "fast-levenshtein": "~2.0.6",
         "levn": "~0.3.0",
         "prelude-ls": "~1.1.2",
         "type-check": "~0.3.2",
-        "wordwrap": "~1.0.0"
+        "word-wrap": "~1.2.3"
       }
     },
     "ordered-read-streams": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/ordered-read-streams/download/ordered-read-streams-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
       "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=",
       "requires": {
         "readable-stream": "^2.0.1"
     },
     "parse-filepath": {
       "version": "1.0.2",
-      "resolved": "http://registry.npm.taobao.org/parse-filepath/download/parse-filepath-1.0.2.tgz",
+      "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
       "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=",
       "requires": {
         "is-absolute": "^1.0.0",
     },
     "parse-passwd": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/parse-passwd/download/parse-passwd-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
       "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY="
     },
     "parse5": {
     },
     "pascalcase": {
       "version": "0.1.1",
-      "resolved": "http://registry.npm.taobao.org/pascalcase/download/pascalcase-0.1.1.tgz",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
       "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
     },
     "path-dirname": {
       "version": "1.0.2",
-      "resolved": "http://registry.npm.taobao.org/path-dirname/download/path-dirname-1.0.2.tgz",
+      "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
       "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA="
     },
     "path-exists": {
     },
     "path-root": {
       "version": "0.1.1",
-      "resolved": "http://registry.npm.taobao.org/path-root/download/path-root-0.1.1.tgz",
+      "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
       "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
       "requires": {
         "path-root-regex": "^0.1.0"
     },
     "path-root-regex": {
       "version": "0.1.2",
-      "resolved": "http://registry.npm.taobao.org/path-root-regex/download/path-root-regex-0.1.2.tgz",
+      "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
       "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0="
     },
     "path-type": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/path-type/download/path-type-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
       "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
       "requires": {
         "graceful-fs": "^4.1.2",
     },
     "pinkie": {
       "version": "2.0.4",
-      "resolved": "http://registry.npm.taobao.org/pinkie/download/pinkie-2.0.4.tgz",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
       "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
     },
     "pinkie-promise": {
       "version": "2.0.1",
-      "resolved": "http://registry.npm.taobao.org/pinkie-promise/download/pinkie-promise-2.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
       "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
       "requires": {
         "pinkie": "^2.0.0"
       }
     },
     "plur": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/plur/-/plur-3.0.1.tgz",
-      "integrity": "sha512-lJl0ojUynAM1BZn58Pas2WT/TXeC1+bS+UqShl0x9+49AtOn7DixRXVzaC8qrDOIxNDmepKnLuMTH7NQmkX0PA==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz",
+      "integrity": "sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==",
       "requires": {
         "irregular-plurals": "^2.0.0"
       }
     },
     "posix-character-classes": {
       "version": "0.1.1",
-      "resolved": "http://registry.npm.taobao.org/posix-character-classes/download/posix-character-classes-0.1.1.tgz",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
       "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
     },
     "postcss": {
     },
     "pretty-hrtime": {
       "version": "1.0.3",
-      "resolved": "http://registry.npm.taobao.org/pretty-hrtime/download/pretty-hrtime-1.0.3.tgz",
+      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
       "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE="
     },
     "process-nextick-args": {
-      "version": "1.0.7",
-      "resolved": "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-1.0.7.tgz",
-      "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+    },
+    "property-information": {
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.4.0.tgz",
+      "integrity": "sha512-nmMWAm/3vKFGmmOWOcdLjgq/Hlxa+hsuR/px1Lp/UGEyc5A22A6l78Shc2C0E71sPmAqglni+HrS7L7VJ7AUCA==",
+      "requires": {
+        "xtend": "^4.0.0"
+      }
     },
     "pseudomap": {
       "version": "1.0.2",
       "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
     },
     "psl": {
-      "version": "1.1.29",
-      "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
-      "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ=="
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
+      "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ=="
     },
     "pump": {
       "version": "2.0.1",
-      "resolved": "http://registry.npm.taobao.org/pump/download/pump-2.0.1.tgz",
-      "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+      "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
       "requires": {
         "end-of-stream": "^1.1.0",
         "once": "^1.3.1"
     },
     "pumpify": {
       "version": "1.5.1",
-      "resolved": "http://registry.npm.taobao.org/pumpify/download/pumpify-1.5.1.tgz",
-      "integrity": "sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4=",
+      "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+      "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
       "requires": {
         "duplexify": "^3.6.0",
         "inherits": "^2.0.3",
     },
     "read-pkg": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/read-pkg/download/read-pkg-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
       "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
       "requires": {
         "load-json-file": "^1.0.0",
     },
     "read-pkg-up": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/read-pkg-up/download/read-pkg-up-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
       "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
       "requires": {
         "find-up": "^1.0.0",
       "dependencies": {
         "find-up": {
           "version": "1.1.2",
-          "resolved": "http://registry.npm.taobao.org/find-up/download/find-up-1.1.2.tgz",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
           "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
           "requires": {
             "path-exists": "^2.0.0",
         },
         "path-exists": {
           "version": "2.1.0",
-          "resolved": "http://registry.npm.taobao.org/path-exists/download/path-exists-2.1.0.tgz",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
           "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
           "requires": {
             "pinkie-promise": "^2.0.0"
     },
     "readdirp": {
       "version": "2.2.1",
-      "resolved": "http://registry.npm.taobao.org/readdirp/download/readdirp-2.2.1.tgz",
-      "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+      "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
       "requires": {
         "graceful-fs": "^4.1.11",
         "micromatch": "^3.1.10",
     },
     "rechoir": {
       "version": "0.6.2",
-      "resolved": "http://registry.npm.taobao.org/rechoir/download/rechoir-0.6.2.tgz",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
       "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
       "requires": {
         "resolve": "^1.1.6"
     },
     "regex-not": {
       "version": "1.0.2",
-      "resolved": "http://registry.npm.taobao.org/regex-not/download/regex-not-1.0.2.tgz",
-      "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
       "requires": {
         "extend-shallow": "^3.0.2",
         "safe-regex": "^1.1.0"
       }
     },
+    "rehype-stringify": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-6.0.1.tgz",
+      "integrity": "sha512-JfEPRDD4DiG7jet4md7sY07v6ACeb2x+9HWQtRPm2iA6/ic31hCv1SNBUtpolJASxQ/D8gicXiviW4TJKEMPKQ==",
+      "requires": {
+        "hast-util-to-html": "^6.0.0",
+        "xtend": "^4.0.0"
+      }
+    },
     "relateurl": {
       "version": "0.2.7",
       "resolved": "http://registry.npm.taobao.org/relateurl/download/relateurl-0.2.7.tgz",
       "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
     },
     "remark-clang-format": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/remark-clang-format/-/remark-clang-format-1.0.1.tgz",
-      "integrity": "sha512-ztyv9OPExH/TDSSaYJPIwsVbL2yGqSASyZtEcXIOg5O7kwAiJH4jSUhZ6OgUCfrGv/R/kzKscP5FP8VBIDwAtQ==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remark-clang-format/-/remark-clang-format-1.1.0.tgz",
+      "integrity": "sha512-c55SOKzUirP6GfAWijNiHLqudvn7rDfrcLH4che5Iejv5cCZMRg323MPOsGGKWiahG1pGW0704CQeaBZcbtYeA==",
       "requires": {
         "clang-format": "^1.2.4",
         "unist-util-visit": "^1.4.0"
       }
     },
     "remark-details": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/remark-details/-/remark-details-1.8.0.tgz",
-      "integrity": "sha512-O8kGnRneRV3Y8zD6UKjhXB1K/X8VkeGg3uQvz3reRgMvv8REJfF15etmqXLo84L8OvmvKFycOLR+ZtmdIpzmWw=="
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/remark-details/-/remark-details-2.0.0.tgz",
+      "integrity": "sha512-sKkRKjQjfeCVNoCLw6qxHdlpTwzBiLM6IvcLS6zBZZizUSDXk9Seu4/mOnGDrhtjBQO99RvKZ2RACfDkCPIJ6A==",
+      "requires": {
+        "rehype-stringify": "^6.0.1",
+        "remark-rehype": "^5.0.0"
+      }
     },
     "remark-lint": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint/-/remark-lint-6.0.2.tgz",
-      "integrity": "sha512-zrIx7InZLLOUYUViT6lSa8T80pDyl3Ywvliog+4hoc7LoiJZRV74ejq+RBZK70bg/p2dU/CV6ycedgypFFePPg==",
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/remark-lint/-/remark-lint-6.0.5.tgz",
+      "integrity": "sha512-o1I3ddm+KNsTxk60wWGI+p2yU1jB1gcm8jo2Sy6VhJ4ab2TrQIp1oQbp5xeLoFXYSh/NAqCpKjHkCM/BYpkFdQ==",
       "requires": {
         "remark-message-control": "^4.0.0"
       }
     },
     "remark-lint-blockquote-indentation": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-blockquote-indentation/-/remark-lint-blockquote-indentation-1.0.2.tgz",
-      "integrity": "sha512-u3ruA+4ZZOpt3YmTCdCOcYiGBMSQ/b/iJvZs/fibF6rwSBmkod48aGGJVoOLMuIuTYYbbXpzigxS+PeJwN0CDQ==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-blockquote-indentation/-/remark-lint-blockquote-indentation-1.0.3.tgz",
+      "integrity": "sha512-qK4C1l2VmeOVWEAkDYP0CaDtSFoaEBEo5l4oyz1kTkY7YB0Jh7llW2KjuhJz5IzMLmloKJzIyGwlu/odcwaHpg==",
       "requires": {
         "mdast-util-to-string": "^1.0.2",
         "plur": "^3.0.0",
       }
     },
     "remark-lint-code-block-style": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-code-block-style/-/remark-lint-code-block-style-1.0.2.tgz",
-      "integrity": "sha512-fTSCga/lJ710zBaD808NwqzAatVoLQFizvXWpetygKwoAfXCyMYQ9DUdDE5jdDhwOu2JPnKbxY+4t6m4SrKKWA==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-code-block-style/-/remark-lint-code-block-style-1.0.3.tgz",
+      "integrity": "sha512-DL+rudnd9ILP5YXm74tLpMzfWZLqziX7NwIwUhqRefaOyWwxgPPy7hbT59FJqcFc6E/zvDz+Oq4nR1BSV5kEdw==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-definition-case": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-definition-case/-/remark-lint-definition-case-1.0.2.tgz",
-      "integrity": "sha512-vzL3IufsgYMdoYzgelryjBbNotMSac2VpIQWPbBrOEaMO8YA0OwFmD4ZxZ/IgqExRJs7CYO1v7Vr1/AhIy6RwA==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-definition-case/-/remark-lint-definition-case-1.0.4.tgz",
+      "integrity": "sha512-ebl8vYOab9iy1Mr29Wo/9CmqcYGRjCfBievIZts08efrxIElWz+jB8/n7C17fh8k0djiiS/Of6W+bfRD+kMXLA==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
         "unist-util-position": "^3.0.0",
-        "unist-util-visit": "^1.1.1"
+        "unist-util-visit": "^1.4.0"
       }
     },
     "remark-lint-definition-spacing": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-definition-spacing/-/remark-lint-definition-spacing-1.0.2.tgz",
-      "integrity": "sha512-Yg1BcI/nydXii1B6kiqKIBsqDW7KlOCBMpJO2jMGmNuEuZe8sv1AWNmaCtiSCdPuDiX0CZRidklrkrZwAthPdw==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-definition-spacing/-/remark-lint-definition-spacing-1.0.4.tgz",
+      "integrity": "sha512-UderghITmru72OXB5ErCFhVsY7up2wK/m1bUD3E2dm/TFn73/7WpykENt5UirCDT/aeyoHYl8QXUVL20rAc3XQ==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
         "unist-util-position": "^3.0.0",
-        "unist-util-visit": "^1.1.1"
+        "unist-util-visit": "^1.4.0"
       }
     },
     "remark-lint-emphasis-marker": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-emphasis-marker/-/remark-lint-emphasis-marker-1.0.2.tgz",
-      "integrity": "sha512-c+uvvnYesMaqy/X0dU62dbI6/rk+4dxMXdnfLC/NKBA8GU+4kljWqluW797S6nBG94QZjKIv8m49zJl38QfImQ==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-emphasis-marker/-/remark-lint-emphasis-marker-1.0.3.tgz",
+      "integrity": "sha512-ea2tEVyhZvYxwj6AHsW2qzgEDLljcnzq5taZ3FJFL0KMZYZHfWaIU90H43jrW4seGEtmaP1bmoqJaTavJ2x5Jw==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-fenced-code-flag": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-fenced-code-flag/-/remark-lint-fenced-code-flag-1.0.2.tgz",
-      "integrity": "sha512-6/412zYtz+qKpFJryEPSMurWr6tO5MTVohJF3byFc3+3SSEZLWY3Dg8gbwFlumZ9T4HgmfUm/LT7Idm96zj0nw==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-fenced-code-flag/-/remark-lint-fenced-code-flag-1.0.3.tgz",
+      "integrity": "sha512-X8Oi6dhfqV9NI3cVg29myvT/NATDHVgRGCpnNz76w7VXwzhBvQtJr1MxZzuPxfWLox+ARCXF2rY9n9hbYFHYTg==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-fenced-code-marker": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-fenced-code-marker/-/remark-lint-fenced-code-marker-1.0.2.tgz",
-      "integrity": "sha512-yAP59Q1JoI1jjOFCn0GoNx4uDji99ROLvdwvmz7+9YR9guDArBcR4i9Wem/wN6apauWPk2DbAZFavHvbZaT8HQ==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-fenced-code-marker/-/remark-lint-fenced-code-marker-1.0.3.tgz",
+      "integrity": "sha512-JKnojSQ8JkwpIpbNm6wtKEfx8iiv8QIwNHFM06iTCHExMhXa4pJ3wb5M5f0wsWNHtoND3lrw6AcVPoZxEPnflg==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-file-extension": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-file-extension/-/remark-lint-file-extension-1.0.2.tgz",
-      "integrity": "sha512-qx0uki74rmALIKE3r5J3neasbXnz6h+l88OngvpwWkELsnJmfk81JdxfEd0tZ++uTj6CN0TZuhMKad9smfNtRw==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-file-extension/-/remark-lint-file-extension-1.0.3.tgz",
+      "integrity": "sha512-P5gzsxKmuAVPN7Kq1W0f8Ss0cFKfu+OlezYJWXf+5qOa+9Y5GqHEUOobPnsmNFZrVMiM7JoqJN2C9ZjrUx3N6Q==",
       "requires": {
         "unified-lint-rule": "^1.0.0"
       }
     },
     "remark-lint-final-definition": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-final-definition/-/remark-lint-final-definition-1.0.2.tgz",
-      "integrity": "sha512-F+n8eauYOJGdcSrnD7w2YgQSERx1rAwXTxStaJ2tLmoXlT7eQgpVGHz1U4Y76cg8OANbq8pT0KTNJ85JNqkq4g==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-final-definition/-/remark-lint-final-definition-1.0.3.tgz",
+      "integrity": "sha512-QhbBYy99enfQDeUTElioCHrhgg+SgjMNRlru7/JlOguOufP6wn7AXgn2EVTrLZRoByY0VsNS2jCayXxUTzQ8KA==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-final-newline": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-final-newline/-/remark-lint-final-newline-1.0.2.tgz",
-      "integrity": "sha512-hW/lbDwVKtME3jIcJWJ16wBtoJdFPWIiu0fEI93yzNTjeB1g3VSWJp66dHbtCLYwquRS5fr8UlGx7JxIu1kiuA==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-final-newline/-/remark-lint-final-newline-1.0.3.tgz",
+      "integrity": "sha512-ETAadktv75EwUS3XDhyZUVstXKxfPAEn7SmfN9kZ4+Jb4qo4hHE9gtTOzhE6HxLUxxl9BBhpC5mMO3JcL8UZ5A==",
       "requires": {
         "unified-lint-rule": "^1.0.0"
       }
     },
     "remark-lint-hard-break-spaces": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/remark-lint-hard-break-spaces/-/remark-lint-hard-break-spaces-1.0.3.tgz",
-      "integrity": "sha512-GiC0uXeFwef6/Pfo+EYBN0WIVlEFffh+9TdeJ4uLt89ZweaRVDPCTJQqkkuXoiXSPnZGD7cGHdkWCfXU1PaU7Q==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-hard-break-spaces/-/remark-lint-hard-break-spaces-1.0.4.tgz",
+      "integrity": "sha512-YM82UpgliZCZhGNmFxEe7ArfhqR5CplFf2bc0k0+8w3rKWKx7EJcGMar2NK410tIi40gGeWtH/pIEypPJFCCiA==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-heading-increment": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-heading-increment/-/remark-lint-heading-increment-1.0.2.tgz",
-      "integrity": "sha512-CE3MmARKFk6LK+nBuOUubhr64LnbJfLNx1gA8XgxWJ4s/gf8yZO23KsaWk3ftVmmwk0d8Eqh4qKg8vvvaMyrWQ==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-heading-increment/-/remark-lint-heading-increment-1.0.3.tgz",
+      "integrity": "sha512-/KL4/7D2pNxP07KKgktjcIUS+ga8pYI2k9Q/V91pMfyfSC+RYuCGOLFVJSKV0Affr/4Eqnfhw+gJ9X2HAanNuw==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-heading-style": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-heading-style/-/remark-lint-heading-style-1.0.2.tgz",
-      "integrity": "sha512-d0aIbL8PU5LWfZVI8p49vEV5wWIfD/DdUjc+O8j5E0UWUgcRgPGB66xznkOb8AiniXpcaYggRW8hGZsxoYNt1g==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-heading-style/-/remark-lint-heading-style-1.0.3.tgz",
+      "integrity": "sha512-ZUhMav0HHUxo5gzLqxQsOf2ZpP/I3m6EEK8q25/kqpCYnwm1uRJ5CQ40PDQx46pmKtVibIMzDmraYovxNG3ovw==",
       "requires": {
         "mdast-util-heading-style": "^1.0.2",
         "unified-lint-rule": "^1.0.0",
       }
     },
     "remark-lint-link-title-style": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-link-title-style/-/remark-lint-link-title-style-1.0.2.tgz",
-      "integrity": "sha512-0yoaSeLek5hWAQM8WETpi7/pY8kAVOOC/G1ZZFKmIQ0LPeWIzbIlPKJVV0vCiW97J3Bpv8PL0TMTwhXeP0KH2w==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-link-title-style/-/remark-lint-link-title-style-1.0.4.tgz",
+      "integrity": "sha512-61/uH3zDTiozLJqgxp6rHGnVKTChC3UjL3Q0KQDBpprEOL4qLYjTn4fFKscVz776d0uUX6jczrW+GT4AFVOUgg==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-list-item-content-indent": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-list-item-content-indent/-/remark-lint-list-item-content-indent-1.0.2.tgz",
-      "integrity": "sha512-I7VkspA/jeMmIWZ4cGmW/4oWnT6fP8pn5n11MR7azRMKgooj3N2qGF084UqrWHh/dLJcakJUNl3NTXv1XCS1Mw==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-list-item-content-indent/-/remark-lint-list-item-content-indent-1.0.3.tgz",
+      "integrity": "sha512-ZSIGJG2/6jd1xj/xEoDlkcJBf2Ksw8U6vIGJO0IFIA3BLCbJm2EMWJxto2cfzRvXoACmAaxTJMqW8qatPExa4w==",
       "requires": {
         "plur": "^3.0.0",
         "unified-lint-rule": "^1.0.0",
       }
     },
     "remark-lint-list-item-indent": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-list-item-indent/-/remark-lint-list-item-indent-1.0.2.tgz",
-      "integrity": "sha512-ogCCrO8nyuM/0k1bo+O7Ww0S08XxHA9sHh5VdhLwffCTCyOPDoxL1zWCIrAgzPBFZkgjXDQHsOxeUBi5I1ZFcA==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-list-item-indent/-/remark-lint-list-item-indent-1.0.4.tgz",
+      "integrity": "sha512-Sv0gVH6qP1/nFpbJuyyguB9sAD2o42StD2WbEZeUcEexXwRO4u/YaX0Pm5pMtCiEHyN+qyL6ShKBQMtgol9BeA==",
       "requires": {
         "plur": "^3.0.0",
         "unified-lint-rule": "^1.0.0",
       }
     },
     "remark-lint-list-item-spacing": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-list-item-spacing/-/remark-lint-list-item-spacing-1.1.2.tgz",
-      "integrity": "sha512-IhG28ofW85o/2+eVH1ft1zgQmjxqDhNp3+217EQLQviPt/+jVcMsua4W4ZQECPg0E9473yiY9TKbBodp2kOMkg==",
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-list-item-spacing/-/remark-lint-list-item-spacing-1.1.3.tgz",
+      "integrity": "sha512-QzDY0Qfk6m+Az0kmxP57OfswIH1WRdd6SIpQLaUEgsTlsbrJOiO0sJYkkOlFPsyJIfp7SV/FCbr+aYCbHF+kRQ==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-maximum-heading-length": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-maximum-heading-length/-/remark-lint-maximum-heading-length-1.0.2.tgz",
-      "integrity": "sha512-kDdwgRItpVGhxdUC+kbWn5YisCrtF4KggP8z36z26tBmDuPj1ohjQvfMWY0oKL8I0Y6UuXyE0vQx3m4R8Qrj+A==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-maximum-heading-length/-/remark-lint-maximum-heading-length-1.0.3.tgz",
+      "integrity": "sha512-ybcDpR5VHBjtjzdry7AdSjLFwslPo6rdhIJK2+WfHgfeEjIYnlz1uMvp1Z98QMmjpB5JSN83Kzg5fH8/B7poUw==",
       "requires": {
         "mdast-util-to-string": "^1.0.2",
         "unified-lint-rule": "^1.0.0",
       }
     },
     "remark-lint-maximum-line-length": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/remark-lint-maximum-line-length/-/remark-lint-maximum-line-length-1.1.0.tgz",
-      "integrity": "sha512-L+jI6+DReoxHyAWRIxABjX8hPDgxB8B5Lzp0/nDYjWbjl7I4vTsdEvejpmP1K8LVvZ7Ew0XcVHd1zt+p2O8tDg==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/remark-lint-maximum-line-length/-/remark-lint-maximum-line-length-1.2.1.tgz",
+      "integrity": "sha512-CSxX1qc+rAqixk8eBrI+yBsUmD8YGfOezFeJWjJRuUaoOvs67oqCIU+I2HbwcUYY8/KnDxF1MCp+uCM0RkjKKw==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
         "unist-util-position": "^3.0.0",
-        "unist-util-visit": "^1.1.1"
+        "unist-util-visit": "^1.4.0"
       }
     },
     "remark-lint-no-auto-link-without-protocol": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-auto-link-without-protocol/-/remark-lint-no-auto-link-without-protocol-1.0.2.tgz",
-      "integrity": "sha512-3GtkSxOyd6we4b8JdtJsNgt8+3UN+hpw1UiMoE9X96ahc1rqsCFm6miorNUnF/gfPQ1liHBvZUed2SIenDmpkg==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-auto-link-without-protocol/-/remark-lint-no-auto-link-without-protocol-1.0.3.tgz",
+      "integrity": "sha512-k+hg2mXnO4Q9WV+UShPLen5oThvFxcRVWkx2hviVd/nu3eiszBKH3o38csBwjeJoMG3l2ZhdUW8dlOBhq8670Q==",
       "requires": {
         "mdast-util-to-string": "^1.0.2",
         "unified-lint-rule": "^1.0.0",
       }
     },
     "remark-lint-no-blockquote-without-marker": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-blockquote-without-marker/-/remark-lint-no-blockquote-without-marker-2.0.2.tgz",
-      "integrity": "sha512-jkfZ4hFiviZttEo7Ac7GZWFgMQ/bdVPfSluLeuf+qwL8sQvR4ClklKJ0Xbkk3cLRjvlGsc8U8uZR8qqH5MSLoA==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-blockquote-without-marker/-/remark-lint-no-blockquote-without-marker-2.0.3.tgz",
+      "integrity": "sha512-faDzKrA6aKidsRXG6gcIlCO8TexLxIxe+n9B3mdnl8mhZGgE0FfWTkIWVMj0IYps/xVsVMf45KxhXgc1wU9kwg==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-no-consecutive-blank-lines": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-consecutive-blank-lines/-/remark-lint-no-consecutive-blank-lines-1.0.2.tgz",
-      "integrity": "sha512-KbOm6EX5Yl9uzRC93soTB+HlqtCzu9XJWsV9CVcoDKtNnpKfyTwQOy6dmUbQrLp4xBdNk4s9S9CsemRaHEkFGA==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-consecutive-blank-lines/-/remark-lint-no-consecutive-blank-lines-1.0.3.tgz",
+      "integrity": "sha512-2Ef7fPxrfLditA7sTo2Qfqd+xwh/luWl8GzILE5vcWIxLDqKk3dTLJkB5nP+7Cr4kqWJAwXnRkEDd77ehrRV3A==",
       "requires": {
         "plur": "^3.0.0",
         "unified-lint-rule": "^1.0.0",
       }
     },
     "remark-lint-no-duplicate-headings": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-duplicate-headings/-/remark-lint-no-duplicate-headings-1.0.2.tgz",
-      "integrity": "sha512-RO3/eQxLjUoHirHIVC+bE5Abzl+gWiJcdPr48gGSP34xfwCeaBAaeorOAxY/hOqOQ/EVNTTA/JHCBVSNPZWIeg==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-duplicate-headings/-/remark-lint-no-duplicate-headings-1.0.4.tgz",
+      "integrity": "sha512-QuPw+VG502Ctpd/jBjnBYuRXTg0ToP3D+dd3TYds4TRcdgaEFYTZfQ5zjK6XrxLMg0Hn9/WpXr4UqTlV4YZupA==",
       "requires": {
         "mdast-util-to-string": "^1.0.2",
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
         "unist-util-position": "^3.0.0",
-        "unist-util-stringify-position": "^1.1.2",
+        "unist-util-stringify-position": "^2.0.0",
         "unist-util-visit": "^1.1.1"
       }
     },
     "remark-lint-no-emphasis-as-heading": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-emphasis-as-heading/-/remark-lint-no-emphasis-as-heading-1.0.2.tgz",
-      "integrity": "sha512-lKlwiRQOFOoPSwjbZf065RaUr6RZmO82zZYjXhVT9xwMkWXIAQyG0GJuLB2/+rlMEtlgoUD3ePch+Pzf+KrSJQ==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-emphasis-as-heading/-/remark-lint-no-emphasis-as-heading-1.0.3.tgz",
+      "integrity": "sha512-HEmyeyKciUz95+CgpAH98RPR73jq5u5CZb2FOMSqgNl9B6FZXqVpq9F3txPqUw3nAqFYOAEnfiaoRgcqtioh0Q==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-no-file-name-articles": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-file-name-articles/-/remark-lint-no-file-name-articles-1.0.2.tgz",
-      "integrity": "sha512-5FuxJ0Hd2AgVSP1javG51qPbMBWxma1LrCKI6JmBsu/GM7ZYOgemMyH5v4I1ejTPGj7P30xmIjMNSnV8IBMq3g==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-file-name-articles/-/remark-lint-no-file-name-articles-1.0.3.tgz",
+      "integrity": "sha512-YZDJDKUWZEmhrO6tHB0u0K0K2qJKxyg/kryr14OaRMvWLS62RgMn97sXPZ38XOSN7mOcCnl0k7/bClghJXx0sg==",
       "requires": {
         "unified-lint-rule": "^1.0.0"
       }
     },
     "remark-lint-no-file-name-consecutive-dashes": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-file-name-consecutive-dashes/-/remark-lint-no-file-name-consecutive-dashes-1.0.2.tgz",
-      "integrity": "sha512-VvCxG3AfRm6ROFNJ8+tdOOkk61mEKj+PytB8xg5WNQypKWhhJ734mJ3GzXD4XEov7Bdd1GVXJFXlLFtfoAewHw==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-file-name-consecutive-dashes/-/remark-lint-no-file-name-consecutive-dashes-1.0.3.tgz",
+      "integrity": "sha512-7f4vyXn/ca5lAguWWC3eu5hi8oZ7etX7aQlnTSgQZeslnJCbVJm6V6prFJKAzrqbBzMicUXr5pZLBDoXyTvHHw==",
       "requires": {
         "unified-lint-rule": "^1.0.0"
       }
     },
     "remark-lint-no-file-name-irregular-characters": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-file-name-irregular-characters/-/remark-lint-no-file-name-irregular-characters-1.0.2.tgz",
-      "integrity": "sha512-8A+DYXsiPBu0q4cvqtYwzRj6SWrKnPh+oI1H1t64pCQiSnLmG9e3mAUXMxH9PiM6y5OW7Vw8Xh4KYsnRwGEuMQ==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-file-name-irregular-characters/-/remark-lint-no-file-name-irregular-characters-1.0.3.tgz",
+      "integrity": "sha512-b4xIy1Yi8qZpM2vnMN+6gEujagPGxUBAs1judv6xJQngkl5d5zT8VQZsYsTGHku4NWHjjh3b7vK5mr0/yp4JSg==",
       "requires": {
         "unified-lint-rule": "^1.0.0"
       }
     },
     "remark-lint-no-file-name-mixed-case": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-file-name-mixed-case/-/remark-lint-no-file-name-mixed-case-1.0.2.tgz",
-      "integrity": "sha512-OMH2kpjvDAsyyw8ar9h6WI1kUXSpQ2r2c5JZv3NBNYxwzTBfhCR2MSQq+eEI7yUmD2ehqNUY5LwZTQZG6cK4vw==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-file-name-mixed-case/-/remark-lint-no-file-name-mixed-case-1.0.3.tgz",
+      "integrity": "sha512-d7rJ4c8CzDbEbGafw2lllOY8k7pvnsO77t8cV4PHFylwQ3hmCdTHLuDvK87G3DaWCeKclp0PMyamfOgJWKMkPA==",
       "requires": {
         "unified-lint-rule": "^1.0.0"
       }
     },
     "remark-lint-no-file-name-outer-dashes": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-file-name-outer-dashes/-/remark-lint-no-file-name-outer-dashes-1.0.3.tgz",
-      "integrity": "sha512-imUWm8Bi9PxV+IQtQC2/BV1Yj0VboC9hPMZh3sae8pZvCjXquTyYiSFa7hQxX6KWCNUiRPHMSlaSVvfvM2e4pQ==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-file-name-outer-dashes/-/remark-lint-no-file-name-outer-dashes-1.0.4.tgz",
+      "integrity": "sha512-+bZvvme2Bm3Vp5L2iKuvGHYVmHKrTkkRt8JqJPGepuhvBvT4Q7+CgfKyMtC/hIjyl+IcuJQ2H0qPRzdicjy1wQ==",
       "requires": {
         "unified-lint-rule": "^1.0.0"
       }
     },
     "remark-lint-no-heading-punctuation": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-heading-punctuation/-/remark-lint-no-heading-punctuation-1.0.2.tgz",
-      "integrity": "sha512-nYc2a0ihQ5cPy7elaM0lRPYKEMpEK6EjyJH6pHYlgG8NQwjKXhsVaek0fmAm12PaYoYOGW1pDxfzxnFUocU20g==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-heading-punctuation/-/remark-lint-no-heading-punctuation-1.0.3.tgz",
+      "integrity": "sha512-JQD05RjLS99ePBQ4Bed1uWsQTlIMBTcGgIgF6jFXSCEqhwnrIUDwk6S3MG1RZsKd3TLw2xuT/i+POpfBc2+1kQ==",
       "requires": {
         "mdast-util-to-string": "^1.0.2",
         "unified-lint-rule": "^1.0.0",
       }
     },
     "remark-lint-no-inline-padding": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-inline-padding/-/remark-lint-no-inline-padding-1.0.2.tgz",
-      "integrity": "sha512-SHYqEH27yxzgcXSyaIzvqImvktDhXGltRSOEhAHiL2nJktuPt3nosFfGy4/oKAJMWJ2N3aMudXq/zuw1dAkQSg==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-inline-padding/-/remark-lint-no-inline-padding-1.0.4.tgz",
+      "integrity": "sha512-u5rgbDkcfVv645YxxOwoGBBJbsHEwWm/XqnO8EhfKTxkfKOF4ZItG7Ajhj89EDaeXMkvCcB/avBl4bj50eJH3g==",
       "requires": {
         "mdast-util-to-string": "^1.0.2",
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
-        "unist-util-visit": "^1.1.1"
+        "unist-util-visit": "^1.4.0"
       }
     },
     "remark-lint-no-literal-urls": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-literal-urls/-/remark-lint-no-literal-urls-1.0.2.tgz",
-      "integrity": "sha512-+mWZIJA4yAqpKIclcFP5wRy/6hxcPnfU9Xmgp4fR7OD4JQ4JHkKq9O7MUbda14PLez1aMX+Is0O0hWI7OuqsSw==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-literal-urls/-/remark-lint-no-literal-urls-1.0.3.tgz",
+      "integrity": "sha512-H5quyMzl2kaewK+jYD1FI0G1SIinIsIp4DEyOUwIR+vYUoKwo0B4vvW0cmPpD1dgqqxHYx0B2B0JQQKFVWzGiw==",
       "requires": {
         "mdast-util-to-string": "^1.0.2",
         "unified-lint-rule": "^1.0.0",
       }
     },
     "remark-lint-no-multiple-toplevel-headings": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-multiple-toplevel-headings/-/remark-lint-no-multiple-toplevel-headings-1.0.2.tgz",
-      "integrity": "sha512-Zxkw7wIyMOyYQb5C5NTswSttZPCLqm/60Wnt0TEWzXVDkVk5DrxrCCxbMKgpXve1Co5CXPmMixNr/xYBqzxzWg==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-multiple-toplevel-headings/-/remark-lint-no-multiple-toplevel-headings-1.0.4.tgz",
+      "integrity": "sha512-0wDddx6htN5sL9/rofesiQF0oEgwN5224UmueiDx0ZUlYrn6VS0/SS0X3WWxtXmyeqlExfWF3D/g89tNs7dcjw==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
         "unist-util-position": "^3.0.0",
-        "unist-util-stringify-position": "^1.1.2",
+        "unist-util-stringify-position": "^2.0.0",
         "unist-util-visit": "^1.1.1"
       }
     },
     "remark-lint-no-shell-dollars": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-shell-dollars/-/remark-lint-no-shell-dollars-1.0.2.tgz",
-      "integrity": "sha512-eIjBebX9iOFWbMdjol5JJBXI7ku+7UyJpNrd++rl8QenLLZ76beh+xONCzJw/k5dhEw5voBmQLh7VK9HPU/ang==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-shell-dollars/-/remark-lint-no-shell-dollars-1.0.3.tgz",
+      "integrity": "sha512-fT3lQMTjEkPryL+63qDP1NfrohP3tG5i3SkNWSSR4VLU6OSsSSXlHGQGjo0ag//+EPKHB5/9frB/YQ0gDEPRGQ==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-no-shortcut-reference-image": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-shortcut-reference-image/-/remark-lint-no-shortcut-reference-image-1.0.2.tgz",
-      "integrity": "sha512-IVYv5pgyf70jYcrn+BNHVO37BuQJg26rFOLzi2mj+/8EdFpolJiJcTvkChJgz5yip7317DmQQSNLX6gCExuDrQ==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-shortcut-reference-image/-/remark-lint-no-shortcut-reference-image-1.0.3.tgz",
+      "integrity": "sha512-CGm27X54kXp/5ehXejDTsZjqzK4uIhLGcrFzN3k/KjdwunQouEY92AARGrLSEuJ1hQx0bJsmnvr/hvQyWAfNJg==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-no-shortcut-reference-link": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-shortcut-reference-link/-/remark-lint-no-shortcut-reference-link-1.0.3.tgz",
-      "integrity": "sha512-v5mk4wYQL+YRmlOTqi8avpzhoGZg+P42dDRda2jedysDIx7TJBEXUH6oMFEbo/qV6PMmtr7fr066M3RrOrLpiQ==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-shortcut-reference-link/-/remark-lint-no-shortcut-reference-link-1.0.4.tgz",
+      "integrity": "sha512-FXdMJYqspZBhPlxYqfVgVluVXjxStg0RHJzqrk8G9wS8fCS62AE3reoaoiCahwoH1tfKcA+poktbKqDAmZo7Jg==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-no-table-indentation": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-table-indentation/-/remark-lint-no-table-indentation-1.0.2.tgz",
-      "integrity": "sha512-wH0lMGV3DGf7WeDLYGle7SODkXNKqmFtGuh6sG5oa0XgA17rI/L35Vq5tal4DE/5gQG+l4+/0Iy9FPKdBODSDA==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-table-indentation/-/remark-lint-no-table-indentation-1.0.4.tgz",
+      "integrity": "sha512-H4VGHcg1k8sTIbwazFYLNbDqpPR+M0aHHKDf+93b/xyd27Dp0ODQrMnQbls1Cls5qOAQnwAQbx+75wcpFxP3OQ==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
         "unist-util-position": "^3.0.0",
-        "unist-util-visit": "^1.1.1"
+        "unist-util-visit": "^1.4.0"
       }
     },
     "remark-lint-no-tabs": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-no-tabs/-/remark-lint-no-tabs-1.0.2.tgz",
-      "integrity": "sha512-jPjRLHyzO4lO6orhOmHd6AN6mVc/uMWvYZ3qD41dniktnLyHEbIG6DpPxixjfpmEe0wi73RXMywKHrWshLJwAg==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-no-tabs/-/remark-lint-no-tabs-1.0.3.tgz",
+      "integrity": "sha512-GxmG1LLxYoVjKnQ39On4mFEiVwpLfR3BPTXyaC9UCBUj9fnDQ7ANXceeCsPAyxamr0UM4r2tk/hB9mNT4rLskQ==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "vfile-location": "^2.0.1"
       }
     },
     "remark-lint-ordered-list-marker-style": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-ordered-list-marker-style/-/remark-lint-ordered-list-marker-style-1.0.2.tgz",
-      "integrity": "sha512-4EHuHxZqy8IT4k+4Vc8P38I34AiZfgl07fS5/iqGhCdoSMCvvxdOuzTWTgpDFbx/W2QpHelBfJ+FtOp+E0J4Lg==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-ordered-list-marker-style/-/remark-lint-ordered-list-marker-style-1.0.3.tgz",
+      "integrity": "sha512-24TmW1eUa/2JlwprZg9jJ8LKLxNGKnlKiI5YOhN4taUp2yv8daqlV9vR54yfn/ZZQh6EQvbIX0jeVY9NYgQUtw==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-ordered-list-marker-value": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-ordered-list-marker-value/-/remark-lint-ordered-list-marker-value-1.0.2.tgz",
-      "integrity": "sha512-vIPD07u+FBjTjEETZ+UWUp2nydzvOe5AHIX812JlNXWuHYuCybq8DGnkYUcoiK3HbIE+KdG+e7C5xHkim0PSjw==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-ordered-list-marker-value/-/remark-lint-ordered-list-marker-value-1.0.4.tgz",
+      "integrity": "sha512-ojRXhvysomFFf6C747Fo7s5CyhU56e+IKE7cV1couAu+COrajQEbL13If3P3fL9Ucw1yXw9srg0AQWjsEGHYCg==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-rule-style": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-rule-style/-/remark-lint-rule-style-1.0.2.tgz",
-      "integrity": "sha512-D9mMPKA7rtCe4Yx+ryip6FyfNG9uGOaHxRgJClfte7D66QzxiiWtHYyNCXI4rkv8Ax9PrEdpWCPcIl3D2LrXhw==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-rule-style/-/remark-lint-rule-style-1.0.3.tgz",
+      "integrity": "sha512-SJe7IFORYRdo8JUhMSdcTktVAUVNVp36YYl1ZD9CfHqQHWlFD+3vWYzJXOZfog/i+CyWf7Yi0WVYmQes+167dA==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-strong-marker": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-strong-marker/-/remark-lint-strong-marker-1.0.2.tgz",
-      "integrity": "sha512-oUSKqYJVLgbXe25NmcTOfQ8wsFasc+qhEoGjPEGPuJMV2aZIGuOEbGVqD5B1ckYGBEwbTuet3btvMohz8HaBDQ==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-strong-marker/-/remark-lint-strong-marker-1.0.3.tgz",
+      "integrity": "sha512-PFkH282dCwfRsVEw9IxbYbaZBY4UcTuT2SN+lA3R0cBeocWnOySVw8YEm4sv9JfV8BLcQA5gc4tj66/U3KCScw==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-table-cell-padding": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-table-cell-padding/-/remark-lint-table-cell-padding-1.0.2.tgz",
-      "integrity": "sha512-uYm8ia0joAFeK0XLpxVtGW37Ry1XRBDmWH1gDiO2MXWcUip1w1Brvyue4H8JfXB4IM+S5eI/zPR5zN5Wpj9kfA==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/remark-lint-table-cell-padding/-/remark-lint-table-cell-padding-1.0.4.tgz",
+      "integrity": "sha512-AQWWtV1yca1PN27QaFRJbBK6Ro/bopv1XnVKxj/iMebhOU2D2FBJ8rXmMZXVMC3G9OB2WSzGgqH3nP6QY12LoA==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
         "unist-util-position": "^3.0.0",
-        "unist-util-visit": "^1.1.1"
+        "unist-util-visit": "^1.4.0"
       }
     },
     "remark-lint-table-pipe-alignment": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-table-pipe-alignment/-/remark-lint-table-pipe-alignment-1.0.2.tgz",
-      "integrity": "sha512-gLJwduvBI2soR7Dyf39KGUl3M9ZCK/7pFfWBeOv8J27D7px/1lXooqlX4Y9NQ/+9jc7DyLF9upPxh7UWm7UXGg==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-table-pipe-alignment/-/remark-lint-table-pipe-alignment-1.0.3.tgz",
+      "integrity": "sha512-5fhEMcKqNjK6S/y7cVG0+iVqhmhXFW+awIuN7vOBhmDbZ3HF9rCCy20XiHoaG6FzrPJ+zfkjK/QZAbq2Vf58HA==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-table-pipes": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-table-pipes/-/remark-lint-table-pipes-1.0.2.tgz",
-      "integrity": "sha512-BGKcOviuUC6fILIOPYFe6awqk57ApzNJpK3OYBrweGoFF55nZ/qf3q6JpzA0chd6wKj7VrcfQEd3QSQQ+8Wcrw==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-table-pipes/-/remark-lint-table-pipes-1.0.3.tgz",
+      "integrity": "sha512-K9NnGZp6i0m/CaOH7ZT4Ymt2seyiRPcBIlNMMGXBm6gpy34KJDDxYqsNUrh+j7dR+Zg4rYAQLnr3BiSHvj+rbQ==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       }
     },
     "remark-lint-unordered-list-marker-style": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/remark-lint-unordered-list-marker-style/-/remark-lint-unordered-list-marker-style-1.0.2.tgz",
-      "integrity": "sha512-qdnF9JuMWzFJzGIfdAWfOHyjad8dqIQSs+cTzqMlNZHOGrrCJdTUWzybzcZMGn1yuwreklZdHKhOglXQFwSD3A==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/remark-lint-unordered-list-marker-style/-/remark-lint-unordered-list-marker-style-1.0.3.tgz",
+      "integrity": "sha512-0nn/Yscy5ImO4fqByrk/Ua02UwGx8LRu+0kdCbkVz4IxPO5qxTEfyccUQZR71zTdMJp1d2OeqyD9XtMaO4X7Ww==",
       "requires": {
         "unified-lint-rule": "^1.0.0",
         "unist-util-generated": "^1.1.0",
       "integrity": "sha512-ON8gRJHGwcabSpl/k0834039weeOu6iW4RjOomPyqP7irIdyv40bh6/gkQhqlAqB9txSaRHr8o2Xty5f3sTmuQ=="
     },
     "remark-message-control": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/remark-message-control/-/remark-message-control-4.1.0.tgz",
-      "integrity": "sha512-e1dszks4YKY7hLAkhS2367jBjBpAfvi+kVgSN/tOFrdp3qxITjiNR5fOFnyYF8vvorkQ9uxlKJoZUOW8T7rKDg==",
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/remark-message-control/-/remark-message-control-4.2.0.tgz",
+      "integrity": "sha512-WXH2t5ljTyhsXlK1zPBLF3iPHbXl58R94phPMreS1xcHWBZJt6Oiu8RtNjy1poZFb3PqKnbYLJeR/CWcZ1bTFw==",
       "requires": {
         "mdast-comment-marker": "^1.0.0",
         "unified-message-control": "^1.0.0",
       }
     },
     "remark-preset-lint-markdown-style-guide": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/remark-preset-lint-markdown-style-guide/-/remark-preset-lint-markdown-style-guide-2.1.2.tgz",
-      "integrity": "sha512-0mYeeO084o3ZuDSQCvj5vpMZEGQ/HxPcO5vdNpicu+wKpuGNKV2hYZeHbXa/uZV0gjiQeuRmCHIDgNaDsMj5fg==",
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/remark-preset-lint-markdown-style-guide/-/remark-preset-lint-markdown-style-guide-2.1.3.tgz",
+      "integrity": "sha512-H/jSoLvTY8abUcB+7/062I2oHevlHcHdrfRMP2RMh19QA1wmARgNEn3tZfdBXFq1TpzhevGgb6VwSdOjdU8NOQ==",
       "requires": {
         "remark-lint": "^6.0.0",
         "remark-lint-blockquote-indentation": "^1.0.0",
         "remark-lint-unordered-list-marker-style": "^1.0.0"
       }
     },
+    "remark-rehype": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-5.0.0.tgz",
+      "integrity": "sha512-tgo+AeOotuh9FnGMkEPbE6C3OfdARqqSxT0H/KNGAiTwJLiDoRSm6x/ytqPZTyYSiQ/exbi/kx7k6uUvqYL1wQ==",
+      "requires": {
+        "mdast-util-to-hast": "^6.0.0"
+      }
+    },
     "remove-bom-buffer": {
       "version": "3.0.0",
-      "resolved": "http://registry.npm.taobao.org/remove-bom-buffer/download/remove-bom-buffer-3.0.0.tgz",
-      "integrity": "sha1-wr8eN3Ug0yT2I4kuM8EMrCwlK1M=",
+      "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",
+      "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==",
       "requires": {
         "is-buffer": "^1.1.5",
         "is-utf8": "^0.2.1"
     },
     "remove-bom-stream": {
       "version": "1.2.0",
-      "resolved": "http://registry.npm.taobao.org/remove-bom-stream/download/remove-bom-stream-1.2.0.tgz",
+      "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz",
       "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=",
       "requires": {
         "remove-bom-buffer": "^3.0.0",
     },
     "remove-trailing-separator": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
       "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
     },
     "repeat-element": {
       "version": "1.1.3",
-      "resolved": "http://registry.npm.taobao.org/repeat-element/download/repeat-element-1.1.3.tgz",
-      "integrity": "sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4="
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+      "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g=="
     },
     "repeat-string": {
       "version": "1.6.1",
-      "resolved": "http://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
       "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
     },
     "replace-ext": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/replace-ext/download/replace-ext-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
       "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs="
     },
     "replace-homedir": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/replace-homedir/download/replace-homedir-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz",
       "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=",
       "requires": {
         "homedir-polyfill": "^1.0.1",
         "tough-cookie": "~2.4.3",
         "tunnel-agent": "^0.6.0",
         "uuid": "^3.3.2"
+      },
+      "dependencies": {
+        "punycode": {
+          "version": "1.4.1",
+          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+        },
+        "tough-cookie": {
+          "version": "2.4.3",
+          "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+          "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+          "requires": {
+            "psl": "^1.1.24",
+            "punycode": "^1.4.1"
+          }
+        }
       }
     },
     "request-promise-core": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
-      "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz",
+      "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==",
       "requires": {
-        "lodash": "^4.13.1"
+        "lodash": "^4.17.15"
       }
     },
     "request-promise-native": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz",
-      "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=",
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz",
+      "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==",
       "requires": {
-        "request-promise-core": "1.1.1",
-        "stealthy-require": "^1.1.0",
-        "tough-cookie": ">=2.3.3"
+        "request-promise-core": "1.1.3",
+        "stealthy-require": "^1.1.1",
+        "tough-cookie": "^2.3.3"
       }
     },
     "require-directory": {
     },
     "resolve-dir": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/resolve-dir/download/resolve-dir-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
       "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
       "requires": {
         "expand-tilde": "^2.0.0",
     },
     "resolve-options": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/resolve-options/download/resolve-options-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz",
       "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=",
       "requires": {
         "value-or-function": "^3.0.0"
     },
     "ret": {
       "version": "0.1.15",
-      "resolved": "http://registry.npm.taobao.org/ret/download/ret-0.1.15.tgz",
-      "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w="
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
     },
     "rework": {
       "version": "1.0.1",
     },
     "safe-regex": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/safe-regex/download/safe-regex-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
       "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
       "requires": {
         "ret": "~0.1.10"
     },
     "semver-greatest-satisfied-range": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/semver-greatest-satisfied-range/download/semver-greatest-satisfied-range-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz",
       "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=",
       "requires": {
         "sver-compat": "^1.5.0"
     },
     "snapdragon": {
       "version": "0.8.2",
-      "resolved": "http://registry.npm.taobao.org/snapdragon/download/snapdragon-0.8.2.tgz",
-      "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
       "requires": {
         "base": "^0.11.1",
         "debug": "^2.2.0",
       "dependencies": {
         "define-property": {
           "version": "0.2.5",
-          "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
           "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
           "requires": {
             "is-descriptor": "^0.1.0"
         },
         "extend-shallow": {
           "version": "2.0.1",
-          "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
           "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
           "requires": {
             "is-extendable": "^0.1.0"
         },
         "source-map": {
           "version": "0.5.7",
-          "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
           "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
         }
       }
     },
     "snapdragon-node": {
       "version": "2.1.1",
-      "resolved": "http://registry.npm.taobao.org/snapdragon-node/download/snapdragon-node-2.1.1.tgz",
-      "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
       "requires": {
         "define-property": "^1.0.0",
         "isobject": "^3.0.0",
       "dependencies": {
         "define-property": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
           "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
           "requires": {
             "is-descriptor": "^1.0.0"
         },
         "is-accessor-descriptor": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
           "requires": {
             "kind-of": "^6.0.0"
           }
         },
         "is-data-descriptor": {
           "version": "1.0.0",
-          "resolved": "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
           "requires": {
             "kind-of": "^6.0.0"
           }
         },
         "is-descriptor": {
           "version": "1.0.2",
-          "resolved": "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz",
-          "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
           "requires": {
             "is-accessor-descriptor": "^1.0.0",
             "is-data-descriptor": "^1.0.0",
     },
     "snapdragon-util": {
       "version": "3.0.1",
-      "resolved": "http://registry.npm.taobao.org/snapdragon-util/download/snapdragon-util-3.0.1.tgz",
-      "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
       "requires": {
         "kind-of": "^3.2.0"
       },
       "dependencies": {
         "kind-of": {
           "version": "3.2.2",
-          "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
           "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
           "requires": {
             "is-buffer": "^1.1.5"
       "resolved": "http://registry.npm.taobao.org/source-map-url/download/source-map-url-0.4.0.tgz",
       "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
     },
+    "space-separated-tokens": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz",
+      "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA=="
+    },
     "sparkles": {
       "version": "1.0.1",
       "resolved": "http://registry.npm.taobao.org/sparkles/download/sparkles-1.0.1.tgz",
     },
     "split-string": {
       "version": "3.1.0",
-      "resolved": "http://registry.npm.taobao.org/split-string/download/split-string-3.1.0.tgz",
-      "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
       "requires": {
         "extend-shallow": "^3.0.0"
       }
       "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
     },
     "sshpk": {
-      "version": "1.14.2",
-      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
-      "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
+      "version": "1.16.1",
+      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+      "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
       "requires": {
         "asn1": "~0.2.3",
         "assert-plus": "^1.0.0",
     },
     "stack-trace": {
       "version": "0.0.10",
-      "resolved": "http://registry.npm.taobao.org/stack-trace/download/stack-trace-0.0.10.tgz",
+      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
       "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
     },
     "static-extend": {
       "version": "0.1.2",
-      "resolved": "http://registry.npm.taobao.org/static-extend/download/static-extend-0.1.2.tgz",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
       "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
       "requires": {
         "define-property": "^0.2.5",
       "dependencies": {
         "define-property": {
           "version": "0.2.5",
-          "resolved": "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
           "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
           "requires": {
             "is-descriptor": "^0.1.0"
     },
     "stream-exhaust": {
       "version": "1.0.2",
-      "resolved": "http://registry.npm.taobao.org/stream-exhaust/download/stream-exhaust-1.0.2.tgz",
-      "integrity": "sha1-rNrI2lnvK8HheiwMz2wyDRIOVV0="
+      "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz",
+      "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw=="
     },
     "stream-shift": {
-      "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/stream-shift/download/stream-shift-1.0.0.tgz",
-      "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI="
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
+      "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
     },
     "string-width": {
       "version": "2.1.1",
         "safe-buffer": "~5.1.0"
       }
     },
+    "stringify-entities": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-2.0.0.tgz",
+      "integrity": "sha512-fqqhZzXyAM6pGD9lky/GOPq6V4X0SeTAFBl0iXb/BzOegl40gpf/bV3QQP7zULNYvjr6+Dx8SCaDULjVoOru0A==",
+      "requires": {
+        "character-entities-html4": "^1.0.0",
+        "character-entities-legacy": "^1.0.0",
+        "is-alphanumerical": "^1.0.0",
+        "is-decimal": "^1.0.2",
+        "is-hexadecimal": "^1.0.0"
+      }
+    },
     "strip-ansi": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
     },
     "strip-bom": {
       "version": "2.0.0",
-      "resolved": "http://registry.npm.taobao.org/strip-bom/download/strip-bom-2.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
       "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
       "requires": {
         "is-utf8": "^0.2.0"
     },
     "sver-compat": {
       "version": "1.5.0",
-      "resolved": "http://registry.npm.taobao.org/sver-compat/download/sver-compat-1.5.0.tgz",
+      "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz",
       "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=",
       "requires": {
         "es6-iterator": "^2.0.1",
       }
     },
     "symbol-tree": {
-      "version": "3.2.2",
-      "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
-      "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY="
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+      "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
     },
     "through2": {
       "version": "2.0.5",
     },
     "through2-filter": {
       "version": "3.0.0",
-      "resolved": "http://registry.npm.taobao.org/through2-filter/download/through2-filter-3.0.0.tgz",
-      "integrity": "sha1-cA54bfI2fCyIzYqlvkz5weeDElQ=",
+      "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
+      "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
       "requires": {
         "through2": "~2.0.0",
         "xtend": "~4.0.0"
     },
     "to-absolute-glob": {
       "version": "2.0.2",
-      "resolved": "http://registry.npm.taobao.org/to-absolute-glob/download/to-absolute-glob-2.0.2.tgz",
+      "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
       "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=",
       "requires": {
         "is-absolute": "^1.0.0",
     },
     "to-object-path": {
       "version": "0.3.0",
-      "resolved": "http://registry.npm.taobao.org/to-object-path/download/to-object-path-0.3.0.tgz",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
       "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
       "requires": {
         "kind-of": "^3.0.2"
       "dependencies": {
         "kind-of": {
           "version": "3.2.2",
-          "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
           "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
           "requires": {
             "is-buffer": "^1.1.5"
     },
     "to-regex": {
       "version": "3.0.2",
-      "resolved": "http://registry.npm.taobao.org/to-regex/download/to-regex-3.0.2.tgz",
-      "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
       "requires": {
         "define-property": "^2.0.2",
         "extend-shallow": "^3.0.2",
     },
     "to-regex-range": {
       "version": "2.1.1",
-      "resolved": "http://registry.npm.taobao.org/to-regex-range/download/to-regex-range-2.1.1.tgz",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
       "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
       "requires": {
         "is-number": "^3.0.0",
     },
     "to-through": {
       "version": "2.0.0",
-      "resolved": "http://registry.npm.taobao.org/to-through/download/to-through-2.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
       "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=",
       "requires": {
         "through2": "^2.0.3"
       }
     },
     "tough-cookie": {
-      "version": "2.4.3",
-      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
-      "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+      "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
       "requires": {
-        "psl": "^1.1.24",
-        "punycode": "^1.4.1"
-      },
-      "dependencies": {
-        "punycode": {
-          "version": "1.4.1",
-          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
-        }
+        "psl": "^1.1.28",
+        "punycode": "^2.1.1"
       }
     },
     "tr46": {
       "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
       "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0="
     },
+    "trim-lines": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-1.1.3.tgz",
+      "integrity": "sha512-E0ZosSWYK2mkSu+KEtQ9/KqarVjA9HztOSX+9FDdNacRAq29RRV6ZQNgob3iuW8Htar9vAfEa6yyt5qBAHZDBA=="
+    },
     "trim-trailing-lines": {
       "version": "1.1.1",
       "resolved": "http://registry.npm.taobao.org/trim-trailing-lines/download/trim-trailing-lines-1.1.1.tgz",
     "tweetnacl": {
       "version": "0.14.5",
       "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
-      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
-      "optional": true
+      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+    },
+    "type": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+      "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
     },
     "type-check": {
       "version": "0.3.2",
     },
     "typedarray": {
       "version": "0.0.6",
-      "resolved": "http://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
       "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
     },
     "uglify-js": {
     },
     "unc-path-regex": {
       "version": "0.1.2",
-      "resolved": "http://registry.npm.taobao.org/unc-path-regex/download/unc-path-regex-0.1.2.tgz",
+      "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
       "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo="
     },
     "undertaker": {
-      "version": "1.2.0",
-      "resolved": "http://registry.npm.taobao.org/undertaker/download/undertaker-1.2.0.tgz",
-      "integrity": "sha1-M52kZGJS0ILcN45wgGcpl1DhG0k=",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz",
+      "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==",
       "requires": {
         "arr-flatten": "^1.0.1",
         "arr-map": "^2.0.0",
     },
     "undertaker-registry": {
       "version": "1.0.1",
-      "resolved": "http://registry.npm.taobao.org/undertaker-registry/download/undertaker-registry-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz",
       "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA="
     },
     "unified-lint-rule": {
     },
     "unique-stream": {
       "version": "2.3.1",
-      "resolved": "http://registry.npm.taobao.org/unique-stream/download/unique-stream-2.3.1.tgz",
-      "integrity": "sha1-xl0RDppK35psWUiygFPZqNBMvqw=",
+      "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
+      "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
       "requires": {
         "json-stable-stringify-without-jsonify": "^1.0.1",
         "through2-filter": "^3.0.0"
       }
     },
+    "unist-builder": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-1.0.4.tgz",
+      "integrity": "sha512-v6xbUPP7ILrT15fHGrNyHc1Xda8H3xVhP7/HAIotHOhVPjH5dCXA097C3Rry1Q2O+HbOLCao4hfPB+EYEjHgVg==",
+      "requires": {
+        "object-assign": "^4.1.0"
+      },
+      "dependencies": {
+        "object-assign": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+          "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+        }
+      }
+    },
     "unist-util-generated": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.2.tgz",
-      "integrity": "sha512-1HcwiEO62dr0XWGT+abVK4f0aAm8Ik8N08c5nAYVmuSxfvpA9rCcNyX/le8xXj1pJK5nBrGlZefeWB6bN8Pstw=="
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.5.tgz",
+      "integrity": "sha512-1TC+NxQa4N9pNdayCYA1EGUOCAO0Le3fVp7Jzns6lnua/mYgwHo0tz5WUAfrdpNch1RZLHc61VZ1SDgrtNXLSw=="
     },
     "unist-util-is": {
       "version": "2.1.2",
       "integrity": "sha512-YkXBK/H9raAmG7KXck+UUpnKiNmUdB+aBGrknfQ4EreE1banuzrKABx3jP6Z5Z3fMSPMQQmeXBlKpCbMwBkxVw=="
     },
     "unist-util-position": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.0.1.tgz",
-      "integrity": "sha512-05QfJDPI7PE1BIUtAxeSV+cDx21xP7+tUZgSval5CA7tr0pHBwybF7OnEa1dOFqg6BfYH/qiMUnWwWj+Frhlww=="
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.0.4.tgz",
+      "integrity": "sha512-tWvIbV8goayTjobxDIr4zVTyG+Q7ragMSMeKC3xnPl9xzIc0+she8mxXLM3JVNDDsfARPbCd3XdzkyLdo7fF3g=="
     },
     "unist-util-stringify-position": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz",
-      "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ=="
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.2.tgz",
+      "integrity": "sha512-nK5n8OGhZ7ZgUwoUbL8uiVRwAbZyzBsB/Ddrlbu6jwwubFza4oe15KlyEaLNMXQW1svOQq4xesUeqA85YrIUQA==",
+      "requires": {
+        "@types/unist": "^2.0.2"
+      }
     },
     "unist-util-visit": {
       "version": "1.4.0",
     },
     "unset-value": {
       "version": "1.0.0",
-      "resolved": "http://registry.npm.taobao.org/unset-value/download/unset-value-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
       "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
       "requires": {
         "has-value": "^0.3.1",
       "dependencies": {
         "has-value": {
           "version": "0.3.1",
-          "resolved": "http://registry.npm.taobao.org/has-value/download/has-value-0.3.1.tgz",
+          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
           "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
           "requires": {
             "get-value": "^2.0.3",
           "dependencies": {
             "isobject": {
               "version": "2.1.0",
-              "resolved": "http://registry.npm.taobao.org/isobject/download/isobject-2.1.0.tgz",
+              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
               "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
               "requires": {
                 "isarray": "1.0.0"
         },
         "has-values": {
           "version": "0.1.4",
-          "resolved": "http://registry.npm.taobao.org/has-values/download/has-values-0.1.4.tgz",
+          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
           "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
         }
       }
     },
     "upath": {
-      "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/upath/download/upath-1.1.0.tgz",
-      "integrity": "sha1-NSVll+RqWB20eT0M5H+prr/J+r0="
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+      "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="
     },
     "upper-case": {
       "version": "1.1.3",
       "resolved": "http://registry.npm.taobao.org/upper-case/download/upper-case-1.1.3.tgz",
       "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg="
     },
+    "uri-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+      "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "requires": {
+        "punycode": "^2.1.0"
+      }
+    },
     "urix": {
       "version": "0.1.0",
       "resolved": "http://registry.npm.taobao.org/urix/download/urix-0.1.0.tgz",
     },
     "use": {
       "version": "3.1.1",
-      "resolved": "http://registry.npm.taobao.org/use/download/use-3.1.1.tgz",
-      "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8="
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
     },
     "util-deprecate": {
       "version": "1.0.2",
       }
     },
     "uuid": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
-      "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+      "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
     },
     "v8flags": {
-      "version": "3.1.2",
-      "resolved": "http://registry.npm.taobao.org/v8flags/download/v8flags-3.1.2.tgz",
-      "integrity": "sha1-/FzQwidCgYHmwpspkuT48dpeDJ8=",
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz",
+      "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==",
       "requires": {
         "homedir-polyfill": "^1.0.1"
       }
     },
     "value-or-function": {
       "version": "3.0.0",
-      "resolved": "http://registry.npm.taobao.org/value-or-function/download/value-or-function-3.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
       "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM="
     },
     "vendors": {
     },
     "vinyl": {
       "version": "2.2.0",
-      "resolved": "http://registry.npm.taobao.org/vinyl/download/vinyl-2.2.0.tgz",
-      "integrity": "sha1-2FsH2pbkWNJbL/4Z/s6fLKoT7YY=",
+      "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
+      "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
       "requires": {
         "clone": "^2.1.1",
         "clone-buffer": "^1.0.0",
     },
     "vinyl-fs": {
       "version": "3.0.3",
-      "resolved": "http://registry.npm.taobao.org/vinyl-fs/download/vinyl-fs-3.0.3.tgz",
-      "integrity": "sha1-yFhJQF9nQo/qu71cXb3WT0fTG8c=",
+      "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
+      "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==",
       "requires": {
         "fs-mkdirp-stream": "^1.0.0",
         "glob-stream": "^6.1.0",
     },
     "vinyl-sourcemap": {
       "version": "1.1.0",
-      "resolved": "http://registry.npm.taobao.org/vinyl-sourcemap/download/vinyl-sourcemap-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz",
       "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=",
       "requires": {
         "append-buffer": "^1.0.2",
       "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
     },
     "whatwg-encoding": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.4.tgz",
-      "integrity": "sha512-vM9KWN6MP2mIHZ86ytcyIv7e8Cj3KTfO2nd2c8PFDqcI4bxFmQp83ibq4wadq7rL9l9sZV6o9B0LTt8ygGAAXg==",
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
+      "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
       "requires": {
-        "iconv-lite": "0.4.23"
+        "iconv-lite": "0.4.24"
       }
     },
     "whatwg-mimetype": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz",
-      "integrity": "sha512-FKxhYLytBQiUKjkYteN71fAUA3g6KpNXoho1isLiLSB3N1G4F35Q5vUxWfKFhBwi5IWF27VE6WxhrnnC+m0Mew=="
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
+      "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
     },
     "whatwg-url": {
       "version": "6.5.0",
       "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
       "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
     },
-    "wordwrap": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
-      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
+    "word-wrap": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
     },
     "wrap-ansi": {
       "version": "2.1.0",
index 827f042..4b7fb2e 100644 (file)
@@ -33,7 +33,7 @@
     "mathjax-node-page": "^3.0.1",
     "remark-clang-format": "^1.0.1",
     "remark-copywriting-correct": "^0.5.0",
-    "remark-details": "^1.8.0",
+    "remark-details": "^2.0.0",
     "remark-lint-final-newline": "^1.0.2",
     "remark-lint-no-tabs": "^1.0.2",
     "remark-math": "^1.0.5",