<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Maerlyn's Rainbow</title><link href="https://wizmann.top/" rel="alternate"/><link href="https://wizmann.top/feeds/all.atom.xml" rel="self"/><id>https://wizmann.top/</id><updated>2026-05-02T12:00:00+08:00</updated><entry><title>《数学觉醒：学会更清晰地思考》读书笔记</title><link href="https://wizmann.top/math-awakening-notes.html" rel="alternate"/><published>2026-05-02T12:00:00+08:00</published><updated>2026-05-02T12:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2026-05-02:/math-awakening-notes.html</id><summary type="html">&lt;p&gt;这本书表面在谈数学理解，实际处理的是更一般的认知问题：人如何形成直觉，语言与理解之间是什么关系，以及为什么形式化表达常常无法自动带来理解。&lt;/p&gt;</summary><content type="html">&lt;p&gt;这本书表面在谈数学理解，实际处理的是更一般的认知问题：人如何形成直觉，语言与理解之间是什么关系，以及为什么形式化表达常常无法自动带来理解。&lt;/p&gt;
&lt;h2 id="1"&gt;1. 理解的核心是心理图像，而不是符号操作&lt;/h2&gt;
&lt;p&gt;数学对象的真正理解，依赖于头脑中是否形成了相应的心理图像。定义、陈述、证明本身不是终点，而是引导理解的媒介。&lt;/p&gt;
&lt;p&gt;一个关键判断：&lt;strong&gt;定义不是注释，也不是解释，而是构建新心理图像的指南&lt;/strong&gt;。它的作用不只是给词划定边界，而是要在脑中生成一个可操作、可感知、可联结的对象。缺了这一层，学习者只是记住了语言形式。&lt;/p&gt;
&lt;p&gt;这解释了一个常见现象：题目能模仿，换个说法就不会；证明能背下来，脱离原题就失去方向。问题往往不在记忆，而在对象还没有真正&amp;rdquo;成形&amp;rdquo;。一个相关的判断也指向同一点——当一个对象无法被想象、无法激发直觉时，学习者觉得&amp;rdquo;自己其实没理解它&amp;rdquo;，这种感觉通常是可靠的。&lt;/p&gt;
&lt;h2 id="2"&gt;2. 形式语言保证精确性，但不保证理解&lt;/h2&gt;
&lt;p&gt;数学语言之所以高度形式化，是因为人在讨论&amp;rdquo;无法直接展示的对象&amp;rdquo;时，需要稳定、可检验、低歧义的表达方式。形式化是必要的。&lt;/p&gt;
&lt;p&gt;但它有代价：词义被压缩进定义，语言与自然理解之间产生距离。书里举过一个极端例子：如果&amp;rdquo;长鼻子&amp;rdquo;被写进大象的定义，那么鼻子被砍掉它就不再是大象。这不是抬杠，而是说明形式系统只服从定义，不服从常识语感。&lt;/p&gt;
&lt;p&gt;由此引出一个有用的区分：&lt;strong&gt;官方数学&lt;/strong&gt; vs &lt;strong&gt;秘密数学&lt;/strong&gt;。前者是对外发表的规范系统，后者是个人头脑里实际进行的直觉、图像和意义活动。很多学习困难的本质，不是官方数学不存在，而是它没有被翻译成秘密数学。&lt;/p&gt;
&lt;h2 id="3"&gt;3. 数学活动是想象、语言和推理之间的反复转换&lt;/h2&gt;
&lt;p&gt;数学并非单纯的逻辑演算，而是一种多层次的认知活动，涉及几组互补的张力：想象力与语言、直觉与逻辑、细节与全局、遐想与计算。真正的理解来自它们的协同。&lt;/p&gt;
&lt;p&gt;书中有一句值得记下：&lt;strong&gt;从人类语言出发，通过数学语言推理，再回到人类语言中来&lt;/strong&gt;。这个流程不只适用于数学——自然语言负责提出问题和承载意义，形式语言负责约束推理，最后还要翻译回来，检查结论是否真正可被理解。&lt;/p&gt;
&lt;h2 id="4"&gt;4. &amp;ldquo;反直觉&amp;rdquo;是认知状态，不是对象属性&lt;/h2&gt;
&lt;p&gt;书中反对把某些问题描述为&amp;rdquo;本质上反直觉&amp;rdquo;或&amp;rdquo;本质上悖论&amp;rdquo;。所谓反直觉通常只是暂时的；所谓悖论，往往意味着当前理解尚未完成。&lt;/p&gt;
&lt;p&gt;这与流行表达不同。人们经常把&amp;rdquo;不懂&amp;rdquo;包装成&amp;rdquo;深刻&amp;rdquo;，把&amp;rdquo;尚未解释清楚&amp;rdquo;包装成&amp;rdquo;天然矛盾&amp;rdquo;。作者对此比较警惕——直觉和推理结果冲突时，这不是理解的终点，而是&lt;strong&gt;重建直觉的起点&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;为此，书中引入三个系统：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;系统1&lt;/strong&gt;：快速、低成本、直觉式反应&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;系统2&lt;/strong&gt;：慢速、费力、逻辑化推理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;系统3&lt;/strong&gt;：让二者对话，使推理结果逐步重塑直觉&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个框架把&amp;rdquo;会算但不直观&amp;rdquo;视为&lt;strong&gt;中间状态&lt;/strong&gt;，而非终点。稳定的理解不是系统2能推出结果，而是系统1也被训练到能自然接受这个结果。练习的目的，不只是得出正确答案，而是让某类对象在头脑中越来越&amp;rdquo;看得见&amp;rdquo;。&lt;/p&gt;
&lt;h2 id="5"&gt;5. 主要的学习阻碍之一，是对&amp;rdquo;不懂&amp;rdquo;的羞耻感&lt;/h2&gt;
&lt;p&gt;许多数学交流之所以失败，不是因为问题太难，而是因为参与者不愿暴露自己的无知状态。一旦开始羞于承认&amp;rdquo;没听懂&amp;rdquo;，注意力就会被自我评价吞掉，无法继续真正思考。结果是既没学会、也没问清，还带着挫败感结束对话。&lt;/p&gt;
&lt;p&gt;由此引出一个实用动作：&lt;strong&gt;主动把自己放在&amp;rdquo;什么都不懂&amp;rdquo;的位置&lt;/strong&gt;，甚至在交流一开始就公开这一点。它的功能不是表演谦虚，而是降低认知负担，让提问和澄清合法化。&lt;/p&gt;
&lt;p&gt;两个相关表述：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;游客菜单与私房菜单。&lt;/strong&gt; 很多人对外讲的是一套正式说明，对内依赖的是另一套更直观、更朴素的理解方式。前者用于公共交流，后者才是自己真正能工作的认知工具。如果只接触游客菜单，理解往往是悬空的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;向初学者解释，是检验理解的有效方法。&lt;/strong&gt; 重点不在&amp;rdquo;教学促进复习&amp;rdquo;，而在于：一旦要解释，你会立刻发现哪些地方其实只是&amp;rdquo;奇迹&amp;rdquo;——会用，但不知为什么。&lt;/p&gt;
&lt;h2 id="6"&gt;6. 数学训练的产物是&amp;rdquo;清晰&amp;rdquo;，而不是定理本身&lt;/h2&gt;
&lt;p&gt;书中有一句可以视为总结：&lt;strong&gt;数学的产物是清晰和理解，而不是定理本身&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这不是轻视定理，而是强调数学活动的价值不只在外部结果，更在于认知结构被训练后的状态。理想情况下，一个人经过数学训练获得的不是更多结论，而是&lt;strong&gt;更好的分辨力&lt;/strong&gt;：更快看出哪里含混、哪里跳步、哪里只是语言在假装理解、哪里是真的把对象看清了。&lt;/p&gt;
&lt;p&gt;从这个角度，&amp;rdquo;数学觉醒&amp;rdquo;并不限于数学，它对应的是一种更一般的能力——把语言、直觉、形式化、怀疑和修正组织成一个持续运转的理解机制。&lt;/p&gt;
&lt;h2 id="_1"&gt;简要归纳&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;理解先于表达，但表达又是校正理解的工具。&lt;/li&gt;
&lt;li&gt;数学对象必须在头脑里形成图像，否则学习容易停留在模仿层。&lt;/li&gt;
&lt;li&gt;定义和形式系统解决的是精确性，不自动解决意义问题。&lt;/li&gt;
&lt;li&gt;直觉并非固定不变，它可以被训练、修正和重塑。&lt;/li&gt;
&lt;li&gt;&amp;ldquo;反直觉&amp;rdquo;通常表示理解尚未完成，而不是对象天然不可理解。&lt;/li&gt;
&lt;li&gt;承认不懂、反复发问、向初学者解释，是提升理解密度的有效方法。&lt;/li&gt;
&lt;li&gt;数学训练的深层产物，是更清晰的认知，而不只是更多结论。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="7-competitive-programming"&gt;7. 实践应用：把这套方法搬到 competitive programming 上&lt;/h2&gt;
&lt;p&gt;把前面六节压成一句话：&lt;strong&gt;理解 = 心理图像 + 直觉被推理重塑后的状态，而不是会复述定义或会跑通代码。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Competitive programming（LeetCode、Codeforces 等）是这套方法的天然试验场。它的常见失败模式正好对应书里批评的几种状态：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;看题解 → 抄实现 → AC&lt;/strong&gt;：相当于只接触了&amp;rdquo;官方数学&amp;rdquo;，没有形成秘密数学。下次换个皮就不会。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;这题反直觉&amp;rdquo;&lt;/strong&gt;：通常不是题反直觉，而是当前直觉还没有被这一类结构训练过。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;会写但说不清为什么对&lt;/strong&gt;：系统2勉强通过，系统1完全没跟上，属于中间状态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不敢承认哪里没懂&lt;/strong&gt;：跳过&amp;rdquo;装傻&amp;rdquo;步骤，理解出现空洞而不自知。&lt;/li&gt;
&lt;li&gt;&lt;del&gt;&lt;strong&gt;题面没看懂&lt;/strong&gt;: 出题人语文没学好。哪怕花点钱买个AI改改呢？&lt;/del&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，使用 coding agent 的目标不是&amp;rdquo;让它给我答案&amp;rdquo;，而是&lt;strong&gt;让它充当一个迫使我形成心理图像、暴露认知空洞、并把推理结果反向训练直觉的对话者&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;下面是为此设计的 prompt。&lt;/p&gt;
&lt;h3 id="promptcompetitive-programming"&gt;Prompt：Competitive Programming 学习助手&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;# Role&lt;/span&gt;
你是我的 competitive programming 学习教练，不是题解生成器。你的目标不是让我 AC，而是让我对这道题及其所属的问题类，建立可以迁移的理解。

&lt;span class="gh"&gt;# 核心原则&lt;/span&gt;
&lt;span class="k"&gt;1.&lt;/span&gt; &lt;span class="gs"&gt;**理解优先于代码**&lt;/span&gt;。在我没有形成对问题的心理图像前，不要给出完整实现。
&lt;span class="k"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**区分&amp;quot;官方解法&amp;quot;与&amp;quot;私房理解&amp;quot;**&lt;/span&gt;。标准解法要讲，但更重要的是讲清楚：发明这个解法的人，脑子里实际看到了什么结构？
&lt;span class="k"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**把&amp;quot;反直觉&amp;quot;视为待修复的直觉**&lt;/span&gt;。如果某一步看起来需要&amp;quot;灵感&amp;quot;或&amp;quot;技巧&amp;quot;，必须显式拆解：是什么观察让这一步从灵感降格为自然推论。
&lt;span class="k"&gt;4.&lt;/span&gt; &lt;span class="gs"&gt;**允许并鼓励我装傻**&lt;/span&gt;。如果我说&amp;quot;我不懂 X&amp;quot;，不要假设 X 对我是显然的，哪怕 X 是基础概念。
&lt;span class="k"&gt;5.&lt;/span&gt; &lt;span class="gs"&gt;**不要用&amp;quot;显然&amp;quot;&amp;quot;容易看出&amp;quot;&amp;quot;注意到&amp;quot;这类词跳步**&lt;/span&gt;。每个跳步处都可能藏着我尚未形成的心理图像。

&lt;span class="gh"&gt;# 工作流程&lt;/span&gt;

&lt;span class="gu"&gt;## 阶段 0：在我贴出题目后，先不要解题&lt;/span&gt;
先问我：
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;我现在对这题的第一直觉是什么？（哪怕是错的）
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;我能用自然语言把这题重述一遍吗？
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;我能想到的最朴素（哪怕指数级）的做法是什么？

让我先暴露我的初始状态。

&lt;span class="gu"&gt;## 阶段 1：建立心理图像&lt;/span&gt;
在写任何代码、给任何算法名词之前，帮我回答：
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;这题的输入在头脑中应该被想象成什么？（数组？图？状态空间？决策树？）
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;解的结构长什么样？（一个分割点？一条路径？一个不变量？）
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;哪些量在过程中保持不变，哪些在变化？

如果我给不出，引导我给出，而不是替我给出。

&lt;span class="gu"&gt;## 阶段 2：从朴素解到目标解的推导链&lt;/span&gt;
不要直接抛出最优解。按下面的链条走：
&lt;span class="k"&gt;1.&lt;/span&gt; 朴素解是什么？为什么慢？慢在哪个具体的重复或浪费上？
&lt;span class="k"&gt;2.&lt;/span&gt; 这个浪费对应什么结构性观察？（重叠子问题？单调性？对称性？）
&lt;span class="k"&gt;3.&lt;/span&gt; 这个观察如何自然地推出目标算法？

目标是：让最优解看起来像&amp;quot;被逼出来的&amp;quot;，而不是&amp;quot;碰巧想到的&amp;quot;。

&lt;span class="gu"&gt;## 阶段 3：检验理解（强制环节）&lt;/span&gt;
在我说&amp;quot;我懂了&amp;quot;之后，不要相信我。用以下方式检验：
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;让我用一句话向一个不懂这题的人解释核心思路（游客菜单 vs 私房菜单测试）。
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;提一个微小的变体（改个约束、换个目标），看我能否迁移。
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;指出我的解释里哪些地方仍然是&amp;quot;奇迹&amp;quot;——即我会用但说不清为什么对的步骤。

&lt;span class="gu"&gt;## 阶段 4：归档&lt;/span&gt;
最后，用结构化格式输出供我日后复习：
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="gs"&gt;**问题类**&lt;/span&gt;：这题属于哪一类？识别信号是什么？
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="gs"&gt;**核心心理图像**&lt;/span&gt;：一句话 + 一个可以画出来的图。
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="gs"&gt;**关键观察**&lt;/span&gt;：把&amp;quot;灵感步骤&amp;quot;降格为&amp;quot;自然推论&amp;quot;的那一步。
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="gs"&gt;**可迁移点**&lt;/span&gt;：这套思路还能解什么类型的题。
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="gs"&gt;**我的盲点**&lt;/span&gt;：本次对话中暴露出来的、我之前没意识到的认知空洞。

&lt;span class="gh"&gt;# 交互风格&lt;/span&gt;
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;平实、克制、不煽情、不鼓励性废话。
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;我问简单问题时，认真回答简单问题，不要借机讲一大套。
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;我说&amp;quot;跳过这步&amp;quot;时尊重，但如果该步骤是关键直觉，提醒我一次。
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;代码用最小可读形式，注释只标注&amp;quot;为什么&amp;quot;，不标注&amp;quot;做了什么&amp;quot;。

&lt;span class="gh"&gt;# 我现在贴出的题目是：&lt;/span&gt;
[在此处粘贴题目]

&lt;span class="gh"&gt;# 我现在的状态是：&lt;/span&gt;
[完全没思路 / 有方向但写不出 / 写出来了但不懂为什么对 / 想对比我的解法和标准解]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_2"&gt;使用建议&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;这个 prompt 的关键不在某一条规则，而在&lt;strong&gt;阶段 0 和阶段 3&lt;/strong&gt; —— 它们对应&amp;rdquo;先暴露初始直觉&amp;rdquo;和&amp;rdquo;事后检验理解&amp;rdquo;。如果偷懒省掉这两步，对话会迅速退化成普通题解机器人。&lt;/li&gt;
&lt;li&gt;&amp;ldquo;我现在的状态是&amp;rdquo;那一栏不要省。它决定了 agent 应该从哪一阶段切入。&lt;/li&gt;
&lt;li&gt;如果某一类题反复出现&amp;rdquo;盲点&amp;rdquo;字段相似的内容，那是直觉尚未被重塑的信号，需要专门刷一组同类题，而不是继续往前推进度。&lt;/li&gt;
&lt;li&gt;这个 prompt 也可以反过来用于非编程场景：把&amp;rdquo;题目&amp;rdquo;换成&amp;rdquo;论文里看不懂的一段推导&amp;rdquo;或&amp;rdquo;一个工程问题&amp;rdquo;，框架仍然成立——因为它本质上是这本书方法论的一个具体化。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文使用 GPT 和 Claude 大模型生成。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content><category term="读书笔记"/><category term="数学"/><category term="认知"/><category term="学习方法"/><category term="competitive programming"/></entry><entry><title>一个“一读多写”无锁队列的实现</title><link href="https://wizmann.top/implementation-of-mpsc-lock-free-queue-cpp.html" rel="alternate"/><published>2026-01-17T20:00:00+08:00</published><updated>2026-01-17T20:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2026-01-17:/implementation-of-mpsc-lock-free-queue-cpp.html</id><summary type="html">&lt;p&gt;本文详细介绍了一个基于 C++11 std::atomic 实现的高性能 MPSC (多生产单消费) 无锁队列。文章深入剖析了如何利用 Relaxed/Acquire/Release 内存序构建 Happens-Before 关系，通过位运算优化取模开销，并最终实现线程安全的无锁同步机制。&lt;/p&gt;</summary><content type="html">&lt;h1 id="_1"&gt;一个“一读多写”无锁队列的实现&lt;/h1&gt;
&lt;p&gt;标签（空格分隔）： C++  并发编程 Lock-Free 性能优化&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1"&gt;1. 背景与设计目标&lt;/h2&gt;
&lt;p&gt;在高性能网络编程中，我们经常面临&lt;strong&gt;“一读多写”（MPSC, Multi-Producer Single-Consumer）&lt;/strong&gt;的场景，例如多个工作线程需要向同一个 Socket 串行写入数据。&lt;/p&gt;
&lt;p&gt;为了避免互斥锁（Mutex）带来的上下文切换开销，我们设计了一个基于 C++11 &lt;code&gt;std::atomic&lt;/code&gt; 的定长 Ring Buffer。其核心目标包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;零内存动态分配&lt;/strong&gt;：使用定长数组，避免频繁 &lt;code&gt;new/delete&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高效位运算&lt;/strong&gt;：将队列长度限制为 2 的 N 次幂，利用位与运算（&lt;code&gt;&amp;amp;&lt;/code&gt;）替代昂贵的取模操作（&lt;code&gt;%&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;细粒度内存序&lt;/strong&gt;：摒弃粗暴的 &lt;code&gt;seq_cst&lt;/code&gt;，通过 &lt;code&gt;relaxed&lt;/code&gt;、&lt;code&gt;acquire&lt;/code&gt; 和 &lt;code&gt;release&lt;/code&gt; 的精细组合，构建最小开销的同步机制。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="2-try_enqueue"&gt;2. 生产者逻辑：try_enqueue&lt;/h2&gt;
&lt;p&gt;生产者的核心挑战在于：如何在多个线程同时竞争写入时，安全地分配 Slot 并发布数据。&lt;/p&gt;
&lt;h3 id="_2"&gt;代码实现&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;try_enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noexcept&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 1. 获取当前尾部索引的快照（无需同步）&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur_tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m_tail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(;;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next_tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur_tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m_mask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// 2. 获取头部索引（需要同步，以感知消费者的进度）&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m_head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acquire&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// 队列满&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// 3. 尝试抢占 Slot (CAS)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_tail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compare_exchange_weak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;cur_tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;next_tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acq_rel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 成功：建立同步点&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 失败：仅重试&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// 4. 抢占成功，物理写入数据并发布&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;m_slots&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur_tail&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_release&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// CAS 失败：cur_tail 已被自动更新为最新值，进入下一次循环重试&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="try_enqueue"&gt;深度拆解：生产者入队 (try_enqueue) 的三部曲&lt;/h3&gt;
&lt;p&gt;一个标准的无锁入队操作，在逻辑上并非单一步骤，而是一个严密的&lt;strong&gt;“观察 — 抢占 — 发布”&lt;/strong&gt;协议。&lt;/p&gt;
&lt;h4 id="1-observation"&gt;1. 第一阶段：观察 (Observation)&lt;/h4&gt;
&lt;p&gt;在动手修改任何状态前，生产者必须先看清楚局势。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur_tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m_tail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m_head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acquire&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;tail&lt;/code&gt; (Relaxed)&lt;/strong&gt;：这里读取的 &lt;code&gt;tail&lt;/code&gt; 仅仅是一个“猜测值”，用于后续 CAS 的基准。即使读到了旧值，CAS 也会失败并自动重试，因此不需要同步代价高昂的内存序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;head&lt;/code&gt; (Acquire)&lt;/strong&gt;：这是一个关键的同步点。必须使用 &lt;code&gt;acquire&lt;/code&gt; 语义，确保生产者能&lt;strong&gt;“看到”&lt;/strong&gt;消费者之前释放 Slot 的操作（即 &lt;code&gt;consumer-release&lt;/code&gt;  &lt;code&gt;producer-acquire&lt;/code&gt;）。如果不加同步，生产者可能错误地认为队列未满，覆盖了尚未被消费的数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-logical-claim"&gt;2. 第二阶段：抢占 (Logical Claim) —— 核心中的核心&lt;/h4&gt;
&lt;p&gt;这是整个无锁队列最复杂、技术含量最高的一行代码。生产者试图将 &lt;code&gt;tail&lt;/code&gt; 指针向后移动一位，从而宣告对当前 Slot 的所有权。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_tail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compare_exchange_weak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur_tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next_tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acq_rel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这里包含了三个深度的技术决策，我们需要逐一拆解：&lt;/p&gt;
&lt;p&gt;** 为什么选 &lt;code&gt;compare_exchange_weak&lt;/code&gt; 而不是 &lt;code&gt;strong&lt;/code&gt;？**&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;m_tail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compare_exchange_weak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur_tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next_tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在底层硬件（尤其是 ARM/PowerPC 架构）上，CAS 指令可能出现&lt;strong&gt;“伪失败” (Spurious Failure)&lt;/strong&gt;——即原子变量的值虽未被修改，但由于总线微观竞争或缓存行失效，指令依然返回 &lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;针对这种情况，C++ 提供了两个版本：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Strong 版本（双重循环）&lt;/strong&gt;：&lt;br&gt;
它承诺“只要值没变，我就帮你试到成功为止”。为此，编译器会在底层生成一个&lt;strong&gt;隐式的内层循环&lt;/strong&gt;来屏蔽伪失败。这意味着你的代码变成了嵌套结构：外层是业务重试循环，内层是 CAS 的“原地死磕”循环。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Weak 版本（扁平循环）&lt;/strong&gt;：&lt;br&gt;
它允许伪失败，直接返回 &lt;code&gt;false&lt;/code&gt;。这使得代码维持高效的&lt;strong&gt;单层循环&lt;/strong&gt;结构。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;决策理由：计算成本决定了一切&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;既然无论用哪种版本，遇到真正的并发冲突（值被改了）都必须重试，那么选择的关键在于：&lt;strong&gt;当发生伪失败时，“重头再来”的代价有多大？&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;在本队列场景下（选 Weak）：&lt;/strong&gt;&lt;br&gt;
CAS 之前的准备工作（计算 &lt;code&gt;next_tail&lt;/code&gt;）仅涉及极低成本的位运算。如果使用 &lt;code&gt;Strong&lt;/code&gt;，是为了省去一次极快的位运算而引入复杂的内层循环和分支跳转，属于“杀鸡用牛刀”。使用 &lt;code&gt;Weak&lt;/code&gt;，一旦伪失败直接回到外层循环重试，这种&lt;strong&gt;扁平模式&lt;/strong&gt;对 CPU 分支预测器更友好，性能更高。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;反之，什么时候该用 Strong？&lt;/strong&gt;&lt;br&gt;
如果 CAS 之前的&lt;strong&gt;计算逻辑非常昂贵&lt;/strong&gt;（例如耗时 5ms 的复杂数学运算），一旦发生伪失败，我们绝对不想回到外层去重新计算一遍数据。此时必须用 &lt;code&gt;Strong&lt;/code&gt;，在指令层面上死磕，直到成功或检测到值真的发生了变化，从而避免昂贵的&lt;strong&gt;“业务逻辑级重试”&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;** 为什么内存序是 &lt;code&gt;std::memory_order_acq_rel&lt;/code&gt;？**&lt;/p&gt;
&lt;p&gt;此处 &lt;code&gt;m_tail&lt;/code&gt; 充当了同步枢纽，我们需要它同时发挥双向屏障的作用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Acquire (向后屏障)&lt;/strong&gt;：&lt;br&gt;
防止&lt;strong&gt;后续&lt;/strong&gt;对 Slot 的写入操作（Step 3）被 CPU 或编译器重排到 CAS &lt;strong&gt;之前&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;风险&lt;/strong&gt;：如果没有 Acquire，可能出现“还没抢到座位（CAS 未完），就开始往座位上放东西（Write Slot）”的情况，导致数据踩踏。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Release (向前屏障)&lt;/strong&gt;：&lt;br&gt;
确保&lt;strong&gt;此前&lt;/strong&gt;所有的依赖计算（如 &lt;code&gt;item&lt;/code&gt; 的准备）对其他线程可见。同时，它向消费者宣告：“&lt;code&gt;tail&lt;/code&gt; 已经推进，这个位置归我了”。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;** 为什么不直接用默认的 &lt;code&gt;std::memory_order_seq_cst&lt;/code&gt;？**&lt;/p&gt;
&lt;p&gt;很多开发者习惯一把梭使用 &lt;code&gt;seq_cst&lt;/code&gt;（顺序一致性），它是 C++ 原子操作的默认选项，提供全局最强的同步保证。但在高性能场景下，它是我们极力避免的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;开销巨大&lt;/strong&gt;：在 x86 架构下，&lt;code&gt;seq_cst&lt;/code&gt; 的 Store 操作通常需要 &lt;code&gt;MFENCE&lt;/code&gt; 指令或 &lt;code&gt;LOCK&lt;/code&gt; 前缀，这会强制刷新 CPU 的 Store Buffer，导致流水线停顿，开销可达几十到上百个时钟周期。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需求过剩&lt;/strong&gt;：我们只需要&lt;strong&gt;成对的同步 (Pairwise Synchronization)&lt;/strong&gt;——即生产者与消费者之间达成共识。我们并不需要整个系统的所有变量维持一个全局的全序关系。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;优化结论&lt;/strong&gt;：使用 &lt;code&gt;acq_rel&lt;/code&gt;，我们构建了刚好够用的 Happens-Before 关系，既保证了安全性，又避免了 &lt;code&gt;seq_cst&lt;/code&gt; 带来的总线同步风暴。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="3-physical-publish"&gt;3. 第三阶段：发布 (Physical Publish)&lt;/h4&gt;
&lt;p&gt;一旦 CAS 成功，当前线程就拥有了 &lt;code&gt;cur_tail&lt;/code&gt; 指向的 Slot 的独占写入权。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;m_slots&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur_tail&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_release&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Release 语义&lt;/strong&gt;：这是数据真正对外界“可见”的时刻。它保证了：当消费者随后读取到这个非空指针时，指针所指向的对象内容（&lt;code&gt;item&lt;/code&gt;）一定已经初始化完毕。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配合 Consumer&lt;/strong&gt;：这与消费者侧的 &lt;code&gt;load(..., acquire)&lt;/code&gt; 完美配对，构成了完整的数据发布-订阅链条。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="3-try_dequeue"&gt;3. 消费者逻辑：try_dequeue&lt;/h2&gt;
&lt;p&gt;消费者的处理流程相对线性，但包含了一个非常关键的“等待”逻辑。&lt;/p&gt;
&lt;h3 id="_3"&gt;代码实现&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;try_dequeue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noexcept&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 1. 本地状态读取（relaxed）&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m_head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 2. 获取尾部索引（acquire，感知生产者的发布）&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m_tail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acquire&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 3. 关键：自旋等待数据发布完成&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m_slots&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acquire&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;this_thread&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 4. 消费完成，回收 Slot&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;m_slots&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 5. 推进 Head，向生产者宣告资源释放&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;m_head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m_mask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_release&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="while"&gt;关键设计：为什么需要 while 循环？&lt;/h3&gt;
&lt;p&gt;这是本队列设计的精髓所在：&lt;strong&gt;“先逻辑声明，再物理发布”。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;生产者在 &lt;code&gt;enqueue&lt;/code&gt; 时，先修改了 &lt;code&gt;tail&lt;/code&gt;（宣告占位），然后才写入 &lt;code&gt;m_slots&lt;/code&gt;（发布数据）。这意味着存在一个微小的时间窗口：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;head != tail&lt;/code&gt; （队列看起来非空），但 &lt;code&gt;m_slots[head]&lt;/code&gt; 仍然是 &lt;code&gt;nullptr&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此，消费者必须在读取 Slot 时进行检查。如果读到空指针，说明生产者“占了坑但还没填土”，此时通过 &lt;code&gt;yield()&lt;/code&gt; 让出 CPU 等待数据就绪。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="4-happens-before"&gt;4. 深度原理：Happens-Before 关系图谱&lt;/h2&gt;
&lt;p&gt;判断一个无锁队列是否正确，不能靠“感觉”，必须依靠严格的 &lt;strong&gt;Happens-Before (先行发生)&lt;/strong&gt; 关系推导。&lt;/p&gt;
&lt;p&gt;在这个实现中，正确性完全由&lt;strong&gt;两条对称的同步链&lt;/strong&gt;支撑。&lt;/p&gt;
&lt;h3 id="producer-consumer"&gt;链条一：数据发布链 (Producer  Consumer)&lt;/h3&gt;
&lt;p&gt;这条链保证了&lt;strong&gt;消费者读取数据时的安全性&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Producer&lt;/strong&gt;: &lt;code&gt;m_slots[i].store(..., release)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consumer&lt;/strong&gt;: &lt;code&gt;m_slots[i].load(..., acquire)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;推导结果&lt;/strong&gt;：&lt;br&gt;
当消费者通过 &lt;code&gt;acquire&lt;/code&gt; 读到非空指针时，生产者在 &lt;code&gt;release&lt;/code&gt; 之前的所有内存写入（即 &lt;code&gt;item&lt;/code&gt; 对象的初始化）都对消费者可见。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;保证：绝不会读取到未初始化的脏数据。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="consumer-producer"&gt;链条二：资源回收链 (Consumer  Producer)&lt;/h3&gt;
&lt;p&gt;这条链保证了&lt;strong&gt;生产者复用 Slot 时的安全性&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Consumer&lt;/strong&gt;: &lt;code&gt;m_head.store(..., release)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Producer&lt;/strong&gt;: &lt;code&gt;m_head.load(..., acquire)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;推导结果&lt;/strong&gt;：&lt;br&gt;
当生产者通过 &lt;code&gt;acquire&lt;/code&gt; 观察到 &lt;code&gt;head&lt;/code&gt; 前进时，消费者在 &lt;code&gt;release&lt;/code&gt; 之前的所有操作（即读取并清理 Slot）都已完成。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;保证：绝不会在数据未被消费前覆盖 Slot。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="relaxed"&gt;为什么 Relaxed 是安全的？&lt;/h3&gt;
&lt;p&gt;在代码中，&lt;code&gt;relaxed&lt;/code&gt; 被用于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CAS 失败后的重试路径。&lt;/li&gt;
&lt;li&gt;Consumer 更新 &lt;code&gt;m_slots&lt;/code&gt; 为 &lt;code&gt;nullptr&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;Consumer 读取自己的 &lt;code&gt;head&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这些操作的共同点是：&lt;strong&gt;它们不承载跨线程的“通知”任务&lt;/strong&gt;。真正的同步边界（可见性保证）完全由上述两条 &lt;code&gt;Acquire-Release&lt;/code&gt; 链条严密把控，&lt;code&gt;relaxed&lt;/code&gt; 仅用于降低非关键路径的 CPU 开销。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="5"&gt;5. 总结&lt;/h2&gt;
&lt;p&gt;实现一个生产级的高性能无锁队列，难点不在于代码行数，而在于对内存模型的精准把控：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;分离关注点&lt;/strong&gt;：将“位置抢占”（修改 tail）与“数据发布”（写入 slot）解耦，虽然引入了短暂的中间态，但极大降低了竞争复杂度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;显式同步&lt;/strong&gt;：利用 &lt;code&gt;Release-Acquire&lt;/code&gt; 语义建立清晰的 Happens-Before 桥梁。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最小化开销&lt;/strong&gt;：在不破坏因果关系的路径上大胆使用 &lt;code&gt;Relaxed&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过这种设计，我们实现了一个既安全又高效的 MPSC 缓冲队列，完美适配高并发网络 I/O 场景。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/Wizmann/57e6ec4fb326f7acb8a46fe8a4b658fc"&gt;Full Code&lt;/a&gt;&lt;/p&gt;</content><category term="Blog"/><category term="C++"/><category term="Concurrency"/><category term="Lock-Free"/><category term="MPSC"/><category term="Atomic"/><category term="Memory Model"/></entry><entry><title>Luogu P14761 - CCD 的序列【动态序列统计】（之二）</title><link href="https://wizmann.top/luogu-P14761-splay-2.html" rel="alternate"/><published>2025-12-27T21:00:00+08:00</published><updated>2025-12-27T21:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-12-27:/luogu-P14761-splay-2.html</id><summary type="html">&lt;p&gt;本文围绕隐式 Splay 的基本原理与实现方式，重点说明 splay 操作、旋转模式以及区间隔离的工程实现细节，并展示其在动态序列问题中的实际用法。&lt;/p&gt;</summary><content type="html">&lt;p&gt;在上一篇中，我们已经完成了整道题&lt;strong&gt;最关键的建模工作&lt;/strong&gt;：&lt;br&gt;
把“匹配关系发生变更”转化为区间统计问题。问题最终被化简为：&lt;strong&gt;在一个动态变化的序列上，支持区间查询与任意位置插入&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这一篇我们将会讨论：&lt;strong&gt;Splay 数据结构本身的功能与实现方式&lt;/strong&gt;，以及它为什么适合承载这个问题。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-splay"&gt;1. Splay 是“自调整”的，而不是“显式平衡”的&lt;/h2&gt;
&lt;p&gt;在 AVL、SBT 等平衡树中，我们的核心目标是维护某种平衡条件。一旦条件被破坏，就通过旋转把树“修回来”。也就是说，&lt;strong&gt;平衡是目标，旋转是手段&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Splay 的思路是反过来的。它并不关心当前这棵树“是不是平衡”，而只关心一件事：&lt;strong&gt;把刚刚访问过的节点，拉到树的上层&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;直观理解就是：&lt;br&gt;
经常被访问的节点，就应该离根更近；这样后续再访问它，代价自然更小。因此在 Splay 中，&lt;strong&gt;访问本身，就是结构调整的理由&lt;/strong&gt;。至于整棵树的形态是否平衡，并不是一个被显式维护的目标。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="2-splay"&gt;2. 什么是 splay 操作&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;splay(x)&lt;/code&gt; 的含义非常直接：&lt;br&gt;
&lt;strong&gt;通过一系列旋转，把节点 &lt;code&gt;x&lt;/code&gt; 拉到当前树的根节点（或某个指定节点之下）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;需要注意的是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt; 不一定是叶子；&lt;/li&gt;
&lt;li&gt;整个过程中可能发生多次旋转；&lt;/li&gt;
&lt;li&gt;每次旋转都只是普通的左旋或右旋。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Splay 的复杂性不在于旋转本身，而在于&lt;strong&gt;旋转顺序的选择&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="3-splay"&gt;3. Splay 中的三种经典旋转模式&lt;/h2&gt;
&lt;p&gt;设当前要 splay 的节点是 &lt;code&gt;x&lt;/code&gt;，其父节点是 &lt;code&gt;p&lt;/code&gt;，祖父节点是 &lt;code&gt;g&lt;/code&gt;。根据 &lt;code&gt;x&lt;/code&gt;、&lt;code&gt;p&lt;/code&gt;、&lt;code&gt;g&lt;/code&gt; 三者之间的位置关系，旋转会分为三种典型情况。&lt;/p&gt;
&lt;h3 id="zig"&gt;Zig（单旋）&lt;/h3&gt;
&lt;p&gt;当 &lt;code&gt;p&lt;/code&gt; 本身就是根节点（即不存在祖父 &lt;code&gt;g&lt;/code&gt;）时，只需要一次旋转。&lt;/p&gt;
&lt;p&gt;此时旋转的目标非常明确：&lt;br&gt;
&lt;strong&gt;让 &lt;code&gt;x&lt;/code&gt; 成为新的根节点&lt;/strong&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    p               x
   / \             / \
  x   C   ==&amp;gt;     A   p
 / \                 / \
A   B               B   C
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;旋转结束后，&lt;code&gt;x&lt;/code&gt; 被直接提升到了根位置，这是最简单的一种情况。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="zig-zig"&gt;Zig-Zig（同向双旋）&lt;/h3&gt;
&lt;p&gt;当 &lt;code&gt;x&lt;/code&gt; 和 &lt;code&gt;p&lt;/code&gt; 方向相同（同为左儿子，或同为右儿子）时，就会出现一条“歪着的链”。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;        g
       /
      p
     /
    x
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这种结构如果只旋一次，无法有效把 &lt;code&gt;x&lt;/code&gt; 提到高位。因此需要连续两次旋转：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先旋转 &lt;code&gt;p&lt;/code&gt; 与 &lt;code&gt;g&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;再旋转 &lt;code&gt;x&lt;/code&gt; 与 &lt;code&gt;p&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;目标并不是单纯把 &lt;code&gt;x&lt;/code&gt; 提到根，而是&lt;strong&gt;整体压缩这条同向的访问路径&lt;/strong&gt;，让常访问的节点整体靠上。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;        g                 g                  x
       / \               / \                / \
      p   D   (1)       x   D    (2)       A   p
     / \       ==&amp;gt;     / \       ==&amp;gt;          / \
    x   C             A   p                  B   g
   / \                   / \                    / \
  A   B                 B   C                  C   D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;h3 id="zig-zag"&gt;Zig-Zag（反向双旋）&lt;/h3&gt;
&lt;p&gt;当 &lt;code&gt;x&lt;/code&gt; 和 &lt;code&gt;p&lt;/code&gt; 方向相反时，结构呈现出“拧着”的形态：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;        g
       /
      p
       \
        x
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这种情况下，如果直接旋 &lt;code&gt;p&lt;/code&gt; 和 &lt;code&gt;g&lt;/code&gt;，结构会变得更糟。因此正确的顺序是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先旋转 &lt;code&gt;x&lt;/code&gt; 与 &lt;code&gt;p&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;再旋转 &lt;code&gt;x&lt;/code&gt; 与 &lt;code&gt;g&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;目标是先把结构“拧正”，再把 &lt;code&gt;x&lt;/code&gt; 提到更高的位置。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;        g                 g                    x
       / \               / \                  / \
      p   D   (1)       x   D     (2)        p   g
     / \       ==&amp;gt;     / \        ==&amp;gt;       / \ / \
    A   x             p   C                A  B C  D
       / \           / \
      B   C         A   B
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;h2 id="4-splay"&gt;4. 为什么 Splay 不需要维护平衡条件&lt;/h2&gt;
&lt;p&gt;直观地看：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果一棵树长期非常“歪”，&lt;/li&gt;
&lt;li&gt;那说明你反复在访问某一侧的节点，&lt;/li&gt;
&lt;li&gt;而 Splay 会不断把这些节点旋转到上层，&lt;/li&gt;
&lt;li&gt;最终这条路径会被逐渐压缩。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，&lt;strong&gt;坏结构往往对应“不常用”的访问路径，而常用路径会被不断优化&lt;/strong&gt;。这也是为什么：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单次操作的复杂度可能很高；&lt;/li&gt;
&lt;li&gt;但在一整段操作序列上，Splay 的&lt;strong&gt;均摊复杂度是 &lt;code&gt;O(log n)&lt;/code&gt;&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在竞赛环境中，这样的保证是足够可靠的。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="5-splay-splay"&gt;5. 隐式 Splay 与普通 Splay 的区别&lt;/h2&gt;
&lt;p&gt;普通 Splay 是一棵标准的 BST，节点中有显式的 key，满足左小右大的性质。&lt;/p&gt;
&lt;p&gt;而在本题中使用的是&lt;strong&gt;隐式 Splay&lt;/strong&gt;。换句话说，&lt;strong&gt;节点本身不存 key，而是把整个序列按顺序映射到一棵 BST 的中序遍历上&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;中序遍历顺序 = 序列顺序；&lt;/li&gt;
&lt;li&gt;第 &lt;code&gt;k&lt;/code&gt; 个元素 = 中序遍历第 &lt;code&gt;k&lt;/code&gt; 个节点。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样一来：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查找第 &lt;code&gt;k&lt;/code&gt; 个位置；&lt;/li&gt;
&lt;li&gt;在第 &lt;code&gt;k&lt;/code&gt; 个位置插入；&lt;/li&gt;
&lt;li&gt;查询区间 &lt;code&gt;[l, r]&lt;/code&gt;；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;都可以统一转化为&lt;strong&gt;基于子树大小的树操作&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="6"&gt;6. 区间信息的维护&lt;/h2&gt;
&lt;p&gt;在每个节点中，我们维护该节点所代表区间的信息。这一点与 AVL、SBT 等平衡树在旋转中维护区间信息并无本质区别。&lt;/p&gt;
&lt;p&gt;旋转只会改变父子关系，不会破坏区间的连续性，因此只要在旋转后正确更新受影响节点的区间信息即可。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="7-push_up"&gt;7. 为什么 &lt;code&gt;push_up&lt;/code&gt; 是“三段合并”&lt;/h2&gt;
&lt;p&gt;在隐式 Splay 中，一个节点天然代表如下区间结构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;[ 左子树 ] + [ 当前字符 ] + [ 右子树 ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;因此在更新节点信息时，只需要按顺序合并这三段区间：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;info = merge( merge(left, self), right )
size = size(left) + 1 + size(right)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;每一次旋转结束后，只需对被下沉和被提升的节点各执行一次 &lt;code&gt;push_up&lt;/code&gt;，区间信息就会自动恢复正确。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="8"&gt;8. 总结&lt;/h2&gt;
&lt;p&gt;到这里，Splay 的功能与实现已经足够清晰了。&lt;/p&gt;
&lt;p&gt;在本题中，Splay 本身并不承担复杂的逻辑，它只是提供了一种能够支持动态序列插入与区间定位的结构。真正与题目模型直接相关的，是节点中维护的区间信息及其合并方式。&lt;/p&gt;</content><category term="算法与数据结构"/><category term="Splay"/><category term="隐式Splay"/><category term="平衡树"/><category term="动态序列"/><category term="括号序列"/></entry><entry><title>Luogu P14761 - CCD 的序列 【动态序列统计】 （之一）</title><link href="https://wizmann.top/luogu-P14761-splay-1.html" rel="alternate"/><published>2025-12-20T12:00:00+08:00</published><updated>2025-12-20T12:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-12-20:/luogu-P14761-splay-1.html</id><summary type="html">&lt;p&gt;通过区间统计模型与隐式 Splay 树，解决动态合法括号序列中“匹配发生变更”的统计问题。&lt;/p&gt;</summary><content type="html">&lt;h2 id="1"&gt;1. 题意概述&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.luogu.com.cn/problem/P14761"&gt;题目&lt;/a&gt;要求维护一个&lt;strong&gt;动态变化的合法括号序列&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;初始时序列为空。接下来进行 &lt;span class="math"&gt;\(n\)&lt;/span&gt; 次操作，每次操作给定两个整数 &lt;span class="math"&gt;\((l, r)\)&lt;/span&gt;（&lt;span class="math"&gt;\(0 \le l \le r \le |S|\)&lt;/span&gt;），表示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在当前序列的第 &lt;span class="math"&gt;\(l\)&lt;/span&gt; 个插入位置插入一个左括号 &lt;code&gt;'('&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;在当前序列的第 &lt;span class="math"&gt;\(r\)&lt;/span&gt; 个插入位置插入一个右括号 &lt;code&gt;')'&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;题目保证：&lt;strong&gt;每次操作完成后，整个括号序列仍然是合法的&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="_1"&gt;匹配关系与“匹配发生变更”&lt;/h3&gt;
&lt;p&gt;在一个合法括号序列中，每个括号都有且仅有一个与之匹配的括号，匹配关系由括号的嵌套结构唯一确定。&lt;/p&gt;
&lt;p&gt;若某个括号在一次操作前匹配的是括号 &lt;span class="math"&gt;\(A\)&lt;/span&gt;，在操作后匹配对象变为括号 &lt;span class="math"&gt;\(B\)&lt;/span&gt;（且 &lt;span class="math"&gt;\(A \neq B\)&lt;/span&gt;），则称该括号的&lt;strong&gt;匹配发生了变更&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="_2"&gt;本题的核心问题&lt;/h3&gt;
&lt;p&gt;在每一次插入操作完成后，需要输出：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;由于本次操作导致匹配对象发生变化的旧括号数量&lt;/strong&gt;&lt;br&gt;
（不包括本次新插入的两个括号）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="2"&gt;2. 题目分析与建模：从匹配变化到区间统计&lt;/h2&gt;
&lt;p&gt;本题的关键不在于维护“谁和谁匹配”，而在于&lt;strong&gt;如何刻画“哪些匹配会发生变化”&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="_3"&gt;插入操作的结构本质&lt;/h3&gt;
&lt;p&gt;一次操作在原括号序列 &lt;span class="math"&gt;\(S\)&lt;/span&gt; 上同时插入一对新括号 &lt;code&gt;'('&lt;/code&gt; 和 &lt;code&gt;')'&lt;/code&gt;，并保证新序列仍然合法。&lt;/p&gt;
&lt;p&gt;从结构角度看，这等价于：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;在原序列中，将一段连续子串整体包裹进一层新的括号中。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;给定操作 &lt;span class="math"&gt;\((l, r)\)&lt;/span&gt;，被包裹的原有区间为：&lt;br&gt;
&lt;/p&gt;
&lt;div class="math"&gt;$$
(l+1,\ r)
$$&lt;/div&gt;
&lt;hr&gt;
&lt;h3 id="_4"&gt;哪些括号的匹配会发生变化？&lt;/h3&gt;
&lt;p&gt;将原序列中的括号按其位置与匹配关系分类，可以发现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;完全位于区间 &lt;span class="math"&gt;\((l+1, r)\)&lt;/span&gt; 外的括号，匹配关系不变；&lt;/li&gt;
&lt;li&gt;匹配对象也完全位于区间 &lt;span class="math"&gt;\((l+1, r)\)&lt;/span&gt; 内的括号对，匹配关系不变；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一端在区间内、另一端在区间外的匹配对，其匹配关系一定会发生变化。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此可以得到结论：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;一个旧括号的匹配发生变更，当且仅当它原本匹配的括号与它位于区间 &lt;span class="math"&gt;\((l+1, r)\)&lt;/span&gt; 的不同侧。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="_5"&gt;转化为区间统计问题&lt;/h3&gt;
&lt;p&gt;于是，原问题可以被精确地重述为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在原括号序列中，统计区间 &lt;span class="math"&gt;\((l+1, r)\)&lt;/span&gt; 内，有多少括号是&lt;strong&gt;与区间外的括号直接匹配的&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为此，引入两个区间统计量：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(open\)&lt;/span&gt;：区间内无法在区间内部完成匹配的左括号数量；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(close\)&lt;/span&gt;：区间内无法在区间内部完成匹配的右括号数量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;显然：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(open\)&lt;/span&gt; 个左括号必然向区间右侧寻找匹配；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(close\)&lt;/span&gt; 个右括号必然向区间左侧寻找匹配。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，跨区间匹配对的数量为：&lt;br&gt;
&lt;/p&gt;
&lt;div class="math"&gt;$$
open + close
$$&lt;/div&gt;
&lt;p&gt;而每一对这样的匹配，会导致两个旧括号的匹配关系发生变化。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="_6"&gt;核心公式&lt;/h3&gt;
&lt;p&gt;设区间 &lt;span class="math"&gt;\((l+1, r)\)&lt;/span&gt; 的统计结果为 &lt;span class="math"&gt;\((open, close)\)&lt;/span&gt;，则答案为：&lt;br&gt;
&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{answer} = 2 \times (open + close)
$$&lt;/div&gt;
&lt;p&gt;这一步是整道题的&lt;strong&gt;建模核心&lt;/strong&gt;。&lt;br&gt;
问题至此被转化为：&lt;strong&gt;如何动态维护括号序列，并支持区间 &lt;span class="math"&gt;\((open, close)\)&lt;/span&gt; 查询。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="open-close"&gt;区间 &lt;span class="math"&gt;\((open, close)\)&lt;/span&gt; 在动态插入下的维护方式&lt;/h3&gt;
&lt;p&gt;单个括号本身就是一个最小区间：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;'('&lt;/code&gt; 对应 &lt;span class="math"&gt;\((1,0)\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;')'&lt;/code&gt; 对应 &lt;span class="math"&gt;\((0,1)\)&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当相邻区间合并时，唯一可能产生的新匹配是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;左区间剩余的 &lt;code&gt;'('&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;与右区间剩余的 &lt;code&gt;')'&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此合并规则固定为：&lt;br&gt;
&lt;/p&gt;
&lt;div class="math"&gt;$$
t = \min(open_L,, close_R)
$$&lt;/div&gt;
&lt;div class="math"&gt;$$
\begin{aligned}
open &amp;amp;= open_L + open_R - t, \\
close &amp;amp;= close_L + close_R - t.
\end{aligned}
$$&lt;/div&gt;
&lt;p&gt;一次插入操作，本质上只是向序列中插入新的最小区间 &lt;span class="math"&gt;\((1,0)\)&lt;/span&gt; 或 &lt;span class="math"&gt;\((0,1)\)&lt;/span&gt;，&lt;br&gt;
原有区间内部的匹配关系不会被破坏，只需在插入位置附近按上述规则重新合并区间信息。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="3-splay"&gt;3. 为什么需要平衡树，以及为什么选择 Splay&lt;/h2&gt;
&lt;p&gt;经过建模后，问题转化为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;动态维护一个序列，支持：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任意位置插入元素；&lt;/li&gt;
&lt;li&gt;任意区间 &lt;span class="math"&gt;\((open, close)\)&lt;/span&gt; 查询。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="_7"&gt;朴素与线段树方案的不足&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;数组或字符串模拟，中间插入为 &lt;span class="math"&gt;\(O(n)\)&lt;/span&gt;，总复杂度 &lt;span class="math"&gt;\(O(n^2)\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;普通线段树依赖静态下标，无法处理动态插入。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此需要一种&lt;strong&gt;支持动态序列维护&lt;/strong&gt;的数据结构。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="splay"&gt;为什么选择隐式 Splay？&lt;/h3&gt;
&lt;p&gt;隐式 Splay 具备以下特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;中序遍历顺序即为序列顺序；&lt;/li&gt;
&lt;li&gt;通过子树大小隐式表示下标；&lt;/li&gt;
&lt;li&gt;可以在节点中维护区间 &lt;span class="math"&gt;\((open, close)\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;均摊时间复杂度为 &lt;span class="math"&gt;\(O(\log n)\)&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="_8"&gt;区间信息如何挂在树上？&lt;/h3&gt;
&lt;p&gt;在这种序列型树结构中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个节点维护的是“以自身为根的一段连续区间”的统计信息；&lt;/li&gt;
&lt;li&gt;左子树、当前节点、右子树分别对应三段连续区间；&lt;/li&gt;
&lt;li&gt;节点的 &lt;span class="math"&gt;\((open, close)\)&lt;/span&gt; 由这三部分按合并规则得到。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当插入新节点或树结构调整时，只需在受影响节点处重新计算区间信息，即可保证整体正确性。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="4-splay"&gt;4. Splay 树的基本性质（简述）&lt;/h2&gt;
&lt;p&gt;Splay 树是一种&lt;strong&gt;自调整二叉搜索树&lt;/strong&gt;，通过访问后的一系列旋转操作，将常访问的节点逐渐拉近根节点。&lt;/p&gt;
&lt;p&gt;隐式 Splay 不存储显式 key，而是通过子树大小隐式表示序列下标，因此非常适合处理“第 &lt;span class="math"&gt;\(k\)&lt;/span&gt; 个位置”“区间查询”等操作。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="5"&gt;5. 实现思路与代码结构&lt;/h2&gt;
&lt;p&gt;整体实现可以自然分为三层：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;括号段信息 &lt;span class="math"&gt;\((open, close)\)&lt;/span&gt; 的定义与合并；&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;隐式 Splay 的通用实现（维护 size 与区间信息）；&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;题目逻辑：查询区间 &lt;span class="math"&gt;\((l+1, r)\)&lt;/span&gt;，计算答案并插入新括号。&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id="_9"&gt;单点与区间信息&lt;/h3&gt;
&lt;div class="math"&gt;$$
\text{info}(c)=
\begin{cases}
(1,0), &amp;amp; c='(' \\
(0,1), &amp;amp; c=')' \\
(0,0), &amp;amp; \text{哨兵}
\end{cases}
$$&lt;/div&gt;
&lt;p&gt;区间合并规则同第 2 节所述。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="_10"&gt;区间查询与插入&lt;/h3&gt;
&lt;p&gt;通过两次结构调整，将目标区间隔离为一棵子树，其根节点维护的 &lt;span class="math"&gt;\((open, close)\)&lt;/span&gt; 即为查询结果。&lt;/p&gt;
&lt;p&gt;每次插入与查询的均摊复杂度均为 &lt;span class="math"&gt;\(O(\log n)\)&lt;/span&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="_11"&gt;总体复杂度&lt;/h3&gt;
&lt;p&gt;总时间复杂度：&lt;br&gt;
&lt;/p&gt;
&lt;div class="math"&gt;$$
O(n \log n)
$$&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="_12"&gt;结语&lt;/h2&gt;
&lt;p&gt;解决问题的第一步，一定不是写出代码，而是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正确抽象“匹配发生变更”的含义；&lt;/li&gt;
&lt;li&gt;找到稳定、可维护的区间结构量；&lt;/li&gt;
&lt;li&gt;选择合适的数据结构承载这一结构。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一旦模型建立，剩下只是工程实现问题。&lt;/p&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="算法与数据结构"/><category term="括号序列"/><category term="Splay"/><category term="平衡树"/><category term="动态序列"/><category term="数据结构"/></entry><entry><title>从字符串替换到图灵机：A=B 的完备性构造</title><link href="https://wizmann.top/ab-turing-completeness.html" rel="alternate"/><published>2025-10-01T10:00:00+08:00</published><updated>2025-10-01T10:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-10-01:/ab-turing-completeness.html</id><summary type="html">&lt;h2 id="0-ab"&gt;0. 背景：A=B 是什么&lt;/h2&gt;
&lt;p&gt;A=B 是在一款&lt;a href="https://store.steampowered.com/app/1720850/AB/"&gt;解谜游戏&lt;/a&gt;中引入的一种极简编程语言。它的语法只有一种形式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;A = B
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;含义是“在字符串中 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="0-ab"&gt;0. 背景：A=B 是什么&lt;/h2&gt;
&lt;p&gt;A=B 是在一款&lt;a href="https://store.steampowered.com/app/1720850/AB/"&gt;解谜游戏&lt;/a&gt;中引入的一种极简编程语言。它的语法只有一种形式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;A = B
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;含义是“在字符串中找到子串 &lt;code&gt;A&lt;/code&gt;，并把它替换为 &lt;code&gt;B&lt;/code&gt;”。程序运行过程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;从输入串开始；&lt;/li&gt;
&lt;li&gt;逐条检查规则，从&lt;strong&gt;第一条规则&lt;/strong&gt;开始，寻找&lt;strong&gt;第一个匹配的左部&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;一旦找到，就立即执行替换；&lt;/li&gt;
&lt;li&gt;然后从头再来（回到规则表开头）；&lt;/li&gt;
&lt;li&gt;如果没有任何规则可用，则程序停机，并输出当前字符串。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在游戏后期，会出现扩展关键字（如 &lt;code&gt;(start)&lt;/code&gt; 匹配开头、&lt;code&gt;(end)&lt;/code&gt; 匹配结尾、&lt;code&gt;(once)&lt;/code&gt; 限制只替换一次、&lt;code&gt;(return)&lt;/code&gt; 表示立即输出并停机），它们能让表达力更强。但关键是：&lt;strong&gt;即使完全不依赖这些扩展，A=B 也已经足够强大，可以达到图灵完备性&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="_1"&gt;什么是“图灵完备”？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;图灵完备&lt;/strong&gt;表示该系统能模拟任意图灵机：只要时间与存储足够，任何可计算的算法都能实现。直观地，它意味着：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;能够存储和操作任意量的信息；&lt;/li&gt;
&lt;li&gt;能够分支（条件判断）；&lt;/li&gt;
&lt;li&gt;能够循环（无限计算，直到停机）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;证明 A=B 图灵完备，就是证明它并非“替换小游戏”，而是具备通用计算能力的编程语言。&lt;/p&gt;
&lt;h2 id="1"&gt;1. 理论背景：字符串重写系统为何图灵完备？&lt;/h2&gt;
&lt;p&gt;早在 20 世纪初，数学家 &lt;strong&gt;Axel Thue&lt;/strong&gt; 就提出了&lt;strong&gt;字符串重写系统&lt;/strong&gt;（Thue system），研究如何通过规则替换来生成和变换字符串。后来，&lt;strong&gt;Emil Post&lt;/strong&gt; 进一步发展出 &lt;strong&gt;Post 规范系统&lt;/strong&gt;，并证明这类系统足以表达任意可计算过程。&lt;/p&gt;
&lt;p&gt;核心结论是：&lt;strong&gt;半 Thue 系统（Semi-Thue system，即字符串重写系统）能够模拟任意图灵机&lt;/strong&gt;。其思路是将“图灵机的一个配置（状态 + 带子内容）”编码成一个字符串，再用重写规则逐步执行机器的转移函数。&lt;/p&gt;
&lt;p&gt;下面是维基百科条目给出的一个&lt;strong&gt;标准构造&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用字母表中的若干符号表示带子符号（&lt;span class="math"&gt;\(S_k\)&lt;/span&gt;）；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用一个&lt;strong&gt;唯一的&lt;/strong&gt;状态标记（&lt;span class="math"&gt;\(q_i\)&lt;/span&gt;）表示当前机内状态，并保证它在配置中&lt;strong&gt;恰好出现一次&lt;/strong&gt;。其右侧符号即为当前读头所在位置的带子符号；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;向右移动的转移&lt;/strong&gt;&lt;br&gt;
在图灵机里，&lt;em&gt;“向右移动”&lt;/em&gt; 的意思是：读写头在处理完当前位置后，&lt;strong&gt;把读写位置移动到右边的一个格子&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="math"&gt;$$
  \delta(q_i, S_k) = (q_j, S_l, \rightarrow)
  $$&lt;/div&gt;
&lt;p&gt;对应的重写规则是&lt;/p&gt;
&lt;div class="math"&gt;$$
  q_i S_k \to S_l q_j
  $$&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;解释：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(\delta\)&lt;/span&gt;：转移函数；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(q_i\)&lt;/span&gt;：当前状态；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(S_k\)&lt;/span&gt;：当前读到的符号；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(S_l\)&lt;/span&gt;：要写回去的新符号；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(q_j\)&lt;/span&gt;：更新后的状态；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(\rightarrow\)&lt;/span&gt;：表示读头右移；&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;规则的含义是：把「状态 + 符号」替换为「新符号 + 新状态」，等价于完成写入并把状态标记移动到右边。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;向左移动的转移&lt;/strong&gt;&lt;br&gt;
  在图灵机里，&lt;em&gt;“向左移动”&lt;/em&gt; 的意思是：读写头在处理完当前位置后，&lt;strong&gt;把读写位置移动到左边的一个格子&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="math"&gt;$$
  \delta(q_i, S_k) = (q_j, S_l, \leftarrow)
  $$&lt;/div&gt;
&lt;p&gt;对应一簇规则（需对左邻符号 &lt;span class="math"&gt;\(S_p\)&lt;/span&gt; 枚举）：&lt;/p&gt;
&lt;div class="math"&gt;$$
  S_p q_i S_k \to q_j S_p S_l
  $$&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;解释：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当读头左移时，必须知道左边的符号 &lt;span class="math"&gt;\(S_p\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;左邻符号 + 状态标记 + 当前符号，一起被替换成「新状态 + 左邻符号 + 新符号」；&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这使得状态标记成功左移，同时完成写入操作。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;无限带子的处理&lt;/strong&gt;&lt;br&gt;
为了模拟“无限长”的带子，需要在两端加哨兵符号 &lt;span class="math"&gt;\(h\)&lt;/span&gt;，并加入特殊的延展规则，使得机器在靠近边界时可以“创造”新的空白格子，从而对应无限内存的假设。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于&lt;strong&gt;每次重写都必须包含且仅包含一个 &lt;span class="math"&gt;\(q_i\)&lt;/span&gt;&lt;/strong&gt;，所以在任意时刻都只有&lt;strong&gt;唯一可用的匹配位置&lt;/strong&gt;。整个替换过程严格对应图灵机的一步步执行。因此，字符串重写系统具备完整的计算能力，也就是&lt;strong&gt;图灵完备&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="2-ab"&gt;2. 核心命题与证明纲要（把任意图灵机编译成 A=B 程序）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;命题.&lt;/strong&gt; A=B（即使不用任何关键字）也是图灵完备的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;证明思路（构造式归约）&lt;/strong&gt;&lt;br&gt;
给定任意一台&lt;strong&gt;确定性的&lt;/strong&gt;单带图灵机：&lt;/p&gt;
&lt;div class="math"&gt;$$
M = (Q, \Gamma, \sqcup, \delta, q_0, q_{\text{halt}})
$$&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;解释：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(Q\)&lt;/span&gt;：有限的状态集合；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(\Gamma\)&lt;/span&gt;：带子符号集合；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(\sqcup\)&lt;/span&gt;：空白符；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(\delta\)&lt;/span&gt;：转移函数，定义“遇到某符号时怎么写、状态怎么变、头怎么动”；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(q_0\)&lt;/span&gt;：初始状态；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(q_{\text{halt}}\)&lt;/span&gt;：停机状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;构造一组 A=B 规则，使其在任意初始输入编码上&lt;strong&gt;逐步等价&lt;/strong&gt;地重写到 &lt;span class="math"&gt;\(M\)&lt;/span&gt; 的后续配置，直到停机。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;编码配置&lt;/strong&gt;&lt;br&gt;
   用字符串来编码一台机器的状态：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="math"&gt;$$
   h , L , q_i , R , h
   $$&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;解释：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(L\)&lt;/span&gt;：读头左边的带内容；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(R\)&lt;/span&gt;：读头当前位置以及右边的内容；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(q_i\)&lt;/span&gt;：当前状态，只出现一次；&lt;/li&gt;
&lt;li&gt;两端的 &lt;span class="math"&gt;\(h\)&lt;/span&gt; 是哨兵，确保机器永远不会“掉出带子”。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;生成规则&lt;/strong&gt;&lt;br&gt;
   对每条转移 &lt;span class="math"&gt;\(\delta(q_i,S_k) = (q_j,S_l,\text{dir})\)&lt;/span&gt;，生成对应的 A=B 规则：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;右移：&lt;br&gt;
&lt;div class="math"&gt;$$
    q_i S_k \to S_l q_j
    $$&lt;/div&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;左移（对所有 &lt;span class="math"&gt;\(S_p \in \Gamma\)&lt;/span&gt;）：&lt;br&gt;
&lt;div class="math"&gt;$$
    S_p q_i S_k \to q_j S_p S_l
    $$&lt;/div&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;遇到带子右端（&lt;span class="math"&gt;\(S_0=\sqcup\)&lt;/span&gt;）：&lt;br&gt;
&lt;div class="math"&gt;$$
    h q_i S_k \to h q_j S_0 S_l
    $$&lt;/div&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果进入停机状态 &lt;span class="math"&gt;\(q_{\text{halt}}\)&lt;/span&gt;，没有进一步规则匹配，程序就自然停机。即使没有 &lt;code&gt;(return)&lt;/code&gt;，停机时当前字符串就是输出。&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;正确性&lt;/strong&gt;&lt;br&gt;
  * &lt;strong&gt;唯一匹配位置&lt;/strong&gt;：每个串里只有一个 &lt;span class="math"&gt;\(q_i\)&lt;/span&gt;，所以只有一个规则能触发；这与 A=B 的“从左到右、按顺序找”完全兼容。&lt;br&gt;
  * &lt;strong&gt;一步对应&lt;/strong&gt;：每条替换规则严格模拟图灵机的一步（写入、移动、更新状态）。&lt;br&gt;
  * &lt;strong&gt;停机&lt;/strong&gt;：进入 &lt;span class="math"&gt;\(q_{\text{halt}}\)&lt;/span&gt; 后没有规则匹配，A=B 程序停机。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，A=B 可以模拟任意图灵机，所以它是&lt;strong&gt;图灵完备的&lt;/strong&gt;。 &lt;span class="math"&gt;\(\square\)&lt;/span&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="3"&gt;3. 举例：计数器程序（用例证法说明完备性）&lt;/h2&gt;
&lt;p&gt;上节我们给出了严格的归约证明，这里再展示一个&lt;strong&gt;具体程序&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;把输入的二进制数（&lt;span class="math"&gt;\(1 \leq n  \leq 63\)&lt;/span&gt;）转换成对应数量的 &lt;code&gt;a&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="_2"&gt;程序规则&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;X$&lt;/span&gt;
&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;Y$&lt;/span&gt;
&lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="n"&gt;YXXXXX$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XXXXX$aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&lt;/span&gt;
&lt;span class="n"&gt;YXXXX$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XXXX$aaaaaaaaaaaaaaaa&lt;/span&gt;
&lt;span class="n"&gt;YXXX$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XXX$aaaaaaaa&lt;/span&gt;
&lt;span class="n"&gt;YXX$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XX$aaaa&lt;/span&gt;
&lt;span class="n"&gt;YX$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;X$a&lt;/span&gt;
&lt;span class="n"&gt;Y$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;X$a&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;h3 id="_3"&gt;与图灵机构造的对应关系&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;字母表（Alphabet）&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;符号集合 &lt;span class="math"&gt;\(\Gamma\)&lt;/span&gt;：&lt;code&gt;0,1,X,Y,$,a&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;就像图灵机带子上的有限符号集。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;状态（States）&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;在一般构造中，状态由 &lt;span class="math"&gt;\(q_i\)&lt;/span&gt; 标记。&lt;/li&gt;
&lt;li&gt;在这里，「状态」由当前匹配的模式体现：&lt;ul&gt;
&lt;li&gt;匹配 &lt;code&gt;YXXX$&lt;/code&gt; = “状态 = 等待展开 8 个 a”；&lt;/li&gt;
&lt;li&gt;匹配 &lt;code&gt;YX$&lt;/code&gt; = “状态 = 等待展开 2 个 a”。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;所以规则本身就扮演了转移函数 &lt;span class="math"&gt;\(\delta\)&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读写头（Head）&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;在 A=B 里没有显式的“头”，但每次替换只能在&lt;strong&gt;一个匹配窗口&lt;/strong&gt;里发生：&lt;/li&gt;
&lt;li&gt;例如 &lt;code&gt;YXXX$ → XXX$aaaaaaaa&lt;/code&gt;：可以看成&lt;strong&gt;读写头在 Y 上&lt;/strong&gt;，读到右边 3 个 X 和 &lt;code&gt;$&lt;/code&gt;，然后写出 &lt;code&gt;a&lt;/code&gt; 并右移。&lt;/li&gt;
&lt;li&gt;例如 &lt;code&gt;YX$ → X$a&lt;/code&gt;：可以看成&lt;strong&gt;读写头在 Y 上&lt;/strong&gt;，它左边的 X 会被保留，头位置连带移动到右边继续展开。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;右移的体现&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;替换 &lt;code&gt;YXXX$ → XXX$aaaaaaaa&lt;/code&gt;：&lt;/li&gt;
&lt;li&gt;相当于图灵机在 Y 所在格写入若干 a；&lt;/li&gt;
&lt;li&gt;然后状态标记（匹配窗口）自动“滑到右边的 $”处，继续执行。&lt;/li&gt;
&lt;li&gt;这对应于「写入后头向右移」。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;左移的体现&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;在展开尾部规则 &lt;code&gt;Y$ → X$a&lt;/code&gt; 中：&lt;ul&gt;
&lt;li&gt;当 Y 已经贴近 &lt;code&gt;$&lt;/code&gt; 时，替换会把 &lt;code&gt;$&lt;/code&gt;左边的 X 替出来，并在 Y 的左边补上 a；&lt;/li&gt;
&lt;li&gt;这等价于&lt;strong&gt;把读写头往左看一格&lt;/strong&gt;，再进行展开。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;整个效果就和「写入后头左移」一致。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;带子与哨兵（Tape &amp;amp; Sentinel）&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;符号 &lt;code&gt;$&lt;/code&gt; 就是带子的边界标记；&lt;/li&gt;
&lt;li&gt;末尾两条规则会逐步清理辅助符号，等价于无限带的“空白格”处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$X =
$ =
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_4"&gt;为什么这个例子能说明图灵完备性？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;存储&lt;/strong&gt;：输入二进制串被转写成 Y/X/$ 的带子配置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分支&lt;/strong&gt;：不同的规则（&lt;code&gt;YXXX$&lt;/code&gt;, &lt;code&gt;YXX$&lt;/code&gt;, &lt;code&gt;YX$&lt;/code&gt;, …）体现条件分支。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;循环&lt;/strong&gt;：展开过程需要不断触发相同的规则，直到消耗完所有 Y，体现迭代。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;左/右移动&lt;/strong&gt;：匹配窗口的替换效果对应于头在带子上左右移动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;停机&lt;/strong&gt;：当所有符号都归约成 &lt;code&gt;a&lt;/code&gt;，再无规则可用时，程序自然停机。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，这个计数器程序已经在完整地模拟图灵机的运行：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;字母表&lt;/strong&gt; → &lt;code&gt;{0,1,X,Y,$,a}&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;状态&lt;/strong&gt; → 匹配模式决定；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读写头&lt;/strong&gt; → 当前匹配窗口位置决定；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;左右移动&lt;/strong&gt; → 替换结果把窗口推到左/右；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;停机&lt;/strong&gt; → 无规则可用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这说明 A=B 并非“看似字符串替换”，而是真正能模拟一台图灵机。&lt;/p&gt;
&lt;h2 id="4"&gt;4. 顺序/左端优先会不会削弱能力？&lt;/h2&gt;
&lt;p&gt;不会。因为在构造中我们保证了&lt;strong&gt;唯一状态标记 &lt;span class="math"&gt;\(q_i\)&lt;/span&gt;&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每条规则都包含且仅包含一个 &lt;span class="math"&gt;\(q_i\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;串中也只有一个 &lt;span class="math"&gt;\(q_i\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;因此始终只有唯一匹配。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，不管是左端优先还是其他策略，运行轨迹都是唯一的，能力不受影响。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="5"&gt;5. 关系图（理论坐标系）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A=B&lt;/strong&gt;：一个带优先级与锚点关键字的字符串替换语言。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semi-Thue / SRS&lt;/strong&gt;：字符串重写系统，图灵完备。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Post 规范系统&lt;/strong&gt;：可化归为 SRS，同样图灵完备。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thue 语言&lt;/strong&gt;：非确定性重写为核心的怪诞语言，图灵完备。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="6"&gt;6. 结语&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;形式化&lt;/strong&gt;：任意图灵机都能编译成 A=B 规则，逐步等价执行 → 图灵完备。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;直观例子&lt;/strong&gt;：A+B 展现了进位传播，A–B 展现了借位传播；它们分别是&lt;strong&gt;算术电路的基石&lt;/strong&gt;，而算术电路+控制逻辑=通用机。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，A=B 不只是一个小游戏，而是一个极简却&lt;strong&gt;图灵完备&lt;/strong&gt;的语言。&lt;/p&gt;
&lt;p&gt;p.s. &lt;a href="/A2B.html"&gt;一些参考解法&lt;/a&gt;&lt;/p&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="理论计算机"/><category term="图灵完备性"/><category term="字符串重写系统"/><category term="A=B"/><category term="Thue"/><category term="Post"/></entry><entry><title>C++ 的 `volatile`：它到底管啥、不管啥</title><link href="https://wizmann.top/volatile-in-cpp-cppcon-2024-notes.html" rel="alternate"/><published>2025-10-01T09:00:00+08:00</published><updated>2025-10-01T09:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-10-01:/volatile-in-cpp-cppcon-2024-notes.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;CppCon 2024 — What Volatile Means (and Doesn’t Mean), Ben Saks &lt;br&gt;
(&lt;a href="https://www.youtube.com/watch?v=GeblxEQIPFM&amp;amp;list=PLHTh1InhhwT6U7t1yP2K8AtTEKmcM3XU_&amp;amp;index=2&amp;amp;t=2s"&gt;video&lt;/a&gt;, &lt;a href="https://github.com/CppCon/CppCon2024/blob/main/Presentations/What_Volatile_Means_(and_Doesn't_Mean).pdf"&gt;slides&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;CppCon 2024 上，Ben Saks 做了一场题为 &lt;em&gt;What Volatile Means (and Doesn’t Mean)&lt;/em&gt; 的演讲，专门澄清 C++ 中 volatile 的真实语义，以及它被 …&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;CppCon 2024 — What Volatile Means (and Doesn’t Mean), Ben Saks &lt;br&gt;
(&lt;a href="https://www.youtube.com/watch?v=GeblxEQIPFM&amp;amp;list=PLHTh1InhhwT6U7t1yP2K8AtTEKmcM3XU_&amp;amp;index=2&amp;amp;t=2s"&gt;video&lt;/a&gt;, &lt;a href="https://github.com/CppCon/CppCon2024/blob/main/Presentations/What_Volatile_Means_(and_Doesn't_Mean).pdf"&gt;slides&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;CppCon 2024 上，Ben Saks 做了一场题为 &lt;em&gt;What Volatile Means (and Doesn’t Mean)&lt;/em&gt; 的演讲，专门澄清 C++ 中 volatile 的真实语义，以及它被长期误用的原因。&lt;/p&gt;
&lt;p&gt;volatile 的设计目标其实非常单一：&lt;strong&gt;阻止编译器进行某些会破坏程序语义的优化&lt;/strong&gt;。&lt;br&gt;
但在现实工程中，它要么被滥用（不必要地关掉优化），要么被误信（以为它能解决并发或同步问题），从而导致非常隐蔽、难以复现的 bug。&lt;/p&gt;
&lt;p&gt;这篇文章整理了演讲中的核心观点，重点放在三个问题上：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么 volatile 存在&lt;/li&gt;
&lt;li&gt;它到底保证了什么、不保证什么&lt;/li&gt;
&lt;li&gt;在现实工程中，如何正确而克制地使用它&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="volatile"&gt;为什么需要 volatile&lt;/h2&gt;
&lt;p&gt;volatile 几乎唯一正当、也是最重要的使用场景，是&lt;strong&gt;访问硬件寄存器&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在嵌入式系统中，设备通常通过内存映射寄存器与 CPU 通信。这些寄存器在语法上看起来像普通内存，但语义完全不同：&lt;/p&gt;
&lt;p&gt;写控制寄存器会触发一次硬件动作；&lt;br&gt;
读状态寄存器可能清除或设置硬件标志位；&lt;br&gt;
同一个地址的值，也可能在程序控制之外随时发生变化。&lt;/p&gt;
&lt;p&gt;问题在于：&lt;strong&gt;编译器并不知道这些事&lt;/strong&gt;。&lt;br&gt;
如果你不告诉它某些访问有副作用，它就会把这些地址当成普通对象，自由地进行优化。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="volatile_1"&gt;没有 volatile，编译器会“更高效地做错事”&lt;/h2&gt;
&lt;p&gt;下面这段代码是一个典型的 UART 发送路径示例，刻意没有使用 volatile：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;USTAT0&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x03FFD008&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;UTXBUF0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x03FFD00C&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;USTAT0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TBE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;UTXBUF0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\r&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;USTAT0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TBE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;UTXBUF0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;从人类视角看，这段代码逻辑非常直观：&lt;br&gt;
等待发送缓冲区空闲，然后依次发送 &lt;code&gt;\r\n&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;但在优化器眼里，情况完全不同：&lt;/p&gt;
&lt;p&gt;循环体为空，条件看起来不会变化，busy wait 可能被折叠成一次判断，甚至直接变成死循环；&lt;br&gt;
两次对状态寄存器的检查在语义上没有依赖关系，第二次检查可能被删除；&lt;br&gt;
两次写发送缓冲区相邻，第二次覆盖第一次，于是第一次写被当作“无用代码”删除。&lt;/p&gt;
&lt;p&gt;最终代码可能只剩下一次写入，甚至在某些情况下直接卡死。&lt;br&gt;
这不是编译器“太聪明”，而是程序&lt;strong&gt;没有表达真实语义&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="volatile_2"&gt;volatile 的真实语义&lt;/h2&gt;
&lt;p&gt;给这些寄存器加上 volatile，本质上是在向编译器传达两点信息：&lt;/p&gt;
&lt;p&gt;第一，这些对象的值可能在程序控制之外发生变化；&lt;br&gt;
第二，对它们的每一次读写都可能有副作用，&lt;strong&gt;不能被省略、合并或随意重排&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;典型写法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;USTAT0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x03FFD008&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;UTXBUF0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x03FFD00C&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;有了这个声明，编译器就必须老老实实地：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 busy wait 中反复读取状态寄存器；&lt;/li&gt;
&lt;li&gt;保证对发送缓冲区的写不会被提前、合并或删除。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要特别强调的是：&lt;br&gt;
volatile 的约束单位是&lt;strong&gt;对象&lt;/strong&gt;，而不是“一段代码”。&lt;br&gt;
编译器仍然可以自由重排对&lt;strong&gt;非 volatile 对象&lt;/strong&gt;的访问。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="volatile_3"&gt;volatile 的声明位置，别修饰错对象&lt;/h2&gt;
&lt;p&gt;volatile 和 const 一样，都是类型说明符。&lt;br&gt;
它既可以修饰“指向的对象”，也可以修饰“指针本身”。&lt;/p&gt;
&lt;p&gt;寄存器访问中，几乎总是需要“所指对象是 volatile”，而不是“指针是 volatile”。&lt;/p&gt;
&lt;p&gt;一个简单且不容易出错的经验法则是 &lt;strong&gt;East const / East volatile&lt;/strong&gt;：&lt;br&gt;
先写不带修饰的类型，再把 const 或 volatile 放到你想修饰的那个类型或运算符的右边。&lt;/p&gt;
&lt;p&gt;例如，“N 个 const 指针，指向 volatile 的 uint32_t”：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;h2 id="volatile_4"&gt;volatile 能做什么，不能做什么&lt;/h2&gt;
&lt;h3 id="_1"&gt;顺序保证是有限的&lt;/h3&gt;
&lt;p&gt;volatile 能保证所有 volatile 访问之间的相对顺序不会被打乱，即使它们是不同的对象。&lt;/p&gt;
&lt;p&gt;但它并不能阻止编译器把&lt;strong&gt;非 volatile 的访问&lt;/strong&gt;重排到 volatile 之前或之后。&lt;/p&gt;
&lt;p&gt;下面这个例子是经典反例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buffer_ready&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;BUF_SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;buffer_init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BUF_SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;buffer_ready&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;编译器完全可以把 &lt;code&gt;buffer_ready = true&lt;/code&gt; 提前执行，&lt;br&gt;
导致另一个线程看到“准备好了”，但数据实际上还没初始化完。&lt;/p&gt;
&lt;p&gt;这也是为什么必须明确一点：&lt;br&gt;
&lt;strong&gt;volatile 不是线程同步工具&lt;/strong&gt;。&lt;br&gt;
线程通信应使用 mutex、condition variable、原子类型或内存栅栏。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="volatile_5"&gt;volatile 不提供原子性&lt;/h3&gt;
&lt;p&gt;volatile 只影响优化行为，不提供任何原子性保证。&lt;/p&gt;
&lt;p&gt;对 volatile 对象的自增、复合赋值或普通写入，通常都会被拆成多条机器指令。在并发环境中，这可能导致数据竞争，甚至读到“撕裂”的中间值。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要原子操作，使用 &lt;code&gt;std::atomic&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;需要建立顺序关系，使用同步原语或内存栅栏&lt;/li&gt;
&lt;li&gt;访问硬件寄存器，使用 volatile，但不要指望它解决并发问题&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="const-volatile"&gt;const volatile 的组合很常见&lt;/h3&gt;
&lt;p&gt;对于“硬件会变，但软件只读”的状态寄存器，可以使用 const volatile：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;USTAT0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x03FFD008&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这样既防止误写，又明确告诉编译器该值可能随时变化。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="volatile_6"&gt;当编译器把 volatile 搞砸时&lt;/h2&gt;
&lt;p&gt;现实并不完美。Eide 和 Regehr 在 EMSOFT 2008 的研究中发现，多款主流编译器在某些情况下都曾错误优化 volatile，而且新版本未必更少。&lt;/p&gt;
&lt;p&gt;工程上常见的应对方式有三种：&lt;/p&gt;
&lt;p&gt;第一，局部关闭优化，只在问题函数中降级优化级别；&lt;br&gt;
第二，更换编译器或版本；&lt;br&gt;
第三，用&lt;strong&gt;非内联函数包裹 volatile 读写&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;实践表明，第三种方法在多数工具链上都非常有效。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;vol_read_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;vol_id_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;关键点在于：&lt;strong&gt;这些函数必须是非内联的&lt;/strong&gt;。&lt;br&gt;
函数调用本身会形成一个优化边界，迫使编译器保守处理副作用，从而避免错误合并、删除或重排访问。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="_2"&gt;实用清单&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;访问硬件寄存器：使用 volatile，只读寄存器使用 const volatile&lt;/li&gt;
&lt;li&gt;声明时注意修饰对象，不要把指针和所指对象写反&lt;/li&gt;
&lt;li&gt;不要用 volatile 做线程通信&lt;/li&gt;
&lt;li&gt;volatile 不等于原子性&lt;/li&gt;
&lt;li&gt;遇到工具链问题时，考虑局部关优化、换版本或非内联包裹&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="_3"&gt;总结&lt;/h2&gt;
&lt;p&gt;volatile 的核心价值只有一个：&lt;br&gt;
&lt;strong&gt;告诉编译器，这里的读写可能有副作用，不能被省略、合并或重排。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;它不会解决线程可见性、顺序或原子性问题。&lt;br&gt;
在硬件寄存器访问中，它不可或缺；在并发编程中，它几乎从不适合。&lt;/p&gt;
&lt;p&gt;一旦越界使用，问题往往不会立刻爆炸，而是以最难调试的方式潜伏下来。&lt;/p&gt;
&lt;div class="alert alert-warning" role="alert"&gt;
  ⚠️ 本文根据视频字幕和 slides 由 AI 生成
&lt;/div&gt;</content><category term="Blog"/><category term="C++"/><category term="volatile"/><category term="编译器优化"/><category term="并发"/><category term="内存模型"/><category term="CppCon2024"/></entry><entry><title>Deeplearning.ai 《Retrieval-Augmented Generation (RAG)》课程导读（四）</title><link href="https://wizmann.top/deeplearning-ai-rag-course-intro-4.html" rel="alternate"/><published>2025-09-29T10:00:00+08:00</published><updated>2025-09-29T10:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-09-29:/deeplearning-ai-rag-course-intro-4.html</id><summary type="html">&lt;p&gt;[源视频][1]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;根据视频字幕生成，是给不想看视频的人准备的速读文档&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;简介&lt;/h2&gt;
&lt;p&gt;本部分聚焦 &lt;strong&gt;如何将 RAG 系统真正投入生产&lt;/strong&gt;。你将学 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;[源视频][1]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;根据视频字幕生成，是给不想看视频的人准备的速读文档&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;简介&lt;/h2&gt;
&lt;p&gt;本部分聚焦 &lt;strong&gt;如何将 RAG 系统真正投入生产&lt;/strong&gt;。你将学习部署前的准备步骤，并回顾多种系统评估策略：既可针对单个组件，也可面向整体系统，同时需在运行过程中持续观测性能表现。课程还特别强调 &lt;strong&gt;日志记录&lt;/strong&gt; 的重要性，它不仅能追踪调用，还能帮助定位低质量响应的根源。&lt;/p&gt;
&lt;p&gt;随后，你会接触几项关键实践：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从真实流量中构建 &lt;strong&gt;自定义数据集&lt;/strong&gt;，用客户数据测试系统更新。&lt;/li&gt;
&lt;li&gt;在设计与调优中处理常见权衡，如成本、内存、存储与延迟，并学习在不显著降低质量的前提下对齐需求。&lt;/li&gt;
&lt;li&gt;探索前沿方法，将 &lt;strong&gt;多模态数据&lt;/strong&gt;（图像、PDF 等）整合进知识库，让系统具备处理非文本信息的能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本模块旨在帮助你掌握 从原型走向生产的关键实践：建立评估与监控体系，权衡成本、延迟与质量，并通过量化、安全机制和多模态扩展不断优化 RAG 系统。&lt;/p&gt;
&lt;h2 id="rag"&gt;RAG 评估策略&lt;/h2&gt;
&lt;p&gt;部署 RAG 的第一步是搭建 &lt;strong&gt;可观测性系统&lt;/strong&gt;，并建立系统化的评估方法。&lt;/p&gt;
&lt;h3 id="_2"&gt;可观测性与指标收集&lt;/h3&gt;
&lt;p&gt;系统需同时追踪：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;性能指标：延迟、吞吐量、内存、计算资源。&lt;/li&gt;
&lt;li&gt;质量指标：用户满意度、回复准确性、检索器召回率。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除聚合统计外，还应保存详细日志，以便追踪单个提示在管道中的流转，定位低效或错误响应。&lt;/p&gt;
&lt;h3 id="_3"&gt;评估与实验&lt;/h3&gt;
&lt;p&gt;系统应支持 A/B 测试，便于验证模型切换、提示修改或检索器调整的效果。&lt;/p&gt;
&lt;p&gt;评估维度：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;范围&lt;/strong&gt;：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;系统级评估 → 把握整体表现&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;组件级评估 → 定位瓶颈（如检索器或 LLM）&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;方法&lt;/strong&gt;：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;基于代码 → 自动化、低成本（吞吐量、单元测试）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;人工反馈 → 捕捉代码遗漏的问题（用户点赞/点踩、调查问卷）&lt;/li&gt;
&lt;li&gt;LLM 作为裁判 → 成本低于人工、灵活，但需防止偏见（如判定“相关/不相关”）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最佳做法是 &lt;strong&gt;多方法结合&lt;/strong&gt;：&lt;br&gt;
性能监控 + 人工标注测试集 + LLM 评估，在低/高成本间取得平衡，同时兼顾系统整体与组件质量。&lt;/p&gt;
&lt;h2 id="_4"&gt;日志与监控&lt;/h2&gt;
&lt;p&gt;课程推荐借助 &lt;strong&gt;现代可观测性平台&lt;/strong&gt;，而非完全自建。&lt;/p&gt;
&lt;p&gt;以 &lt;strong&gt;Phoenix&lt;/strong&gt;（Arise 开源工具）为例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;追踪&lt;/strong&gt;：记录提示在 RAG 管道中的完整路径（检索、重排、拼接提示、生成响应），并标注延迟。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;指标收集&lt;/strong&gt;：与 RaaS 库集成，计算检索相关性、验证引用准确性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实验&lt;/strong&gt;：支持提示迭代与 A/B 测试。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;聚合监控&lt;/strong&gt;：提供日报与趋势统计，如检索准确率、幻觉率。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但 Phoenix 不覆盖所有需求，如 GPU/内存监控，仍需 &lt;strong&gt;Datadog、Grafana&lt;/strong&gt; 等传统工具。&lt;/p&gt;
&lt;p&gt;良好的可观测性管道能形成 &lt;strong&gt;改进飞轮&lt;/strong&gt;：&lt;br&gt;
通过生产流量发现问题 → 在日志和自定义数据集上验证改动 → 优化 → 回到生产环境验证。&lt;/p&gt;
&lt;h2 id="_5"&gt;定制化评估体系&lt;/h2&gt;
&lt;p&gt;核心方法是：把 &lt;strong&gt;真实用户提示&lt;/strong&gt; 整理为 &lt;strong&gt;自定义数据集&lt;/strong&gt;，用于回放与对比。&lt;/p&gt;
&lt;p&gt;数据集粒度可分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;最小集&lt;/strong&gt;：仅包含用户输入与最终回复，适合端到端评估。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组件集&lt;/strong&gt;：额外存储检索结果、重排前后结果、查询重写等，便于诊断具体问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实践案例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在客服场景中，日志分析可能揭示“退款”问题表现良好，而“物流延迟”表现差 → 原因是检索器缺乏相关文档。&lt;/li&gt;
&lt;li&gt;在支持文本转图像/图表的系统中，路由 LLM 错误分配任务，导致图表输出错误 → 调整系统提示后修复。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当数据量大时，可用 &lt;strong&gt;聚类与可视化&lt;/strong&gt; 提炼主题（如新品发布、故障排查），再对主题单独评估，发现薄弱环节。&lt;/p&gt;
&lt;h2 id="_6"&gt;模型量化技术&lt;/h2&gt;
&lt;p&gt;量化是生产环境中 &lt;strong&gt;成本、速度、质量&lt;/strong&gt; 权衡的关键。&lt;/p&gt;
&lt;h3 id="_7"&gt;主要形式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LLM 量化&lt;/strong&gt;：将 16 位参数压缩为 8 位或 4 位，大幅降低显存占用与推理延迟，代价是轻微质量下降。&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;向量量化&lt;/strong&gt;：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;8 位整数量化 → 体积降至约 1/4，召回率仅下降几个百分点。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;1 位（二值化）→ 规模缩小 32 倍，但检索质量损失大；常配合“粗检-重排”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;套娃嵌入&lt;/strong&gt;：按信息密度排序维度，部分场景只用前 100–500 维快速检索，必要时再全量重排。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_8"&gt;实践建议&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;优先使用 &lt;strong&gt;8 位整数量化&lt;/strong&gt;（适用于 LLM 与嵌入模型）。&lt;/li&gt;
&lt;li&gt;结合评估体系，监控延迟、吞吐、召回率、幻觉率，验证量化效果。&lt;/li&gt;
&lt;li&gt;可采用“低精度检索 + 高精度重排”组合策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总的来看，量化能够在几乎不损失质量的前提下，显著降低显存和存储消耗，并提升推理与检索速度，是生产环境中最实用的优化手段之一。&lt;/p&gt;
&lt;h2 id="_9"&gt;成本与响应质量的平衡&lt;/h2&gt;
&lt;p&gt;RAG 的主要成本来自 &lt;strong&gt;LLM 推理&lt;/strong&gt; 与 &lt;strong&gt;向量数据库&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="llm"&gt;LLM 成本优化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用更小或量化后的模型。&lt;/li&gt;
&lt;li&gt;限制令牌数量（减少 top-k，裁剪长段落，设置输出上限）。&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;选择合适的部署方式：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;原型 → 公共推理端点&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;规模化 → 专用推理硬件（更划算且稳定）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_10"&gt;向量库成本优化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;分层存储&lt;/strong&gt;：热数据放 RAM，冷数据放磁盘/对象存储。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态迁移&lt;/strong&gt;：根据访问模式自动调整。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多租户优化&lt;/strong&gt;：只在 RAM 中加载当前活跃租户的索引。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;核心思路：用实验与监控量化权衡，确保节省成本不以显著质量下降为代价。&lt;/p&gt;
&lt;h2 id="_11"&gt;时延与质量的权衡&lt;/h2&gt;
&lt;p&gt;每新增一个质量优化组件，都会增加延迟。取舍取决于场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;电商推荐 → 极低延迟优先&lt;/li&gt;
&lt;li&gt;医疗诊断 → 高质量优先&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;优化顺序：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;核心 LLM&lt;/strong&gt;：用小模型/量化模型；路由简单任务给小模型；利用缓存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;管道组件&lt;/strong&gt;：剔除低性价比步骤（如价值有限的查询生成器）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检索优化&lt;/strong&gt;：使用量化嵌入，加快距离计算；或采用数据库分片。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;关键原则：&lt;strong&gt;持续测量延迟与质量指标，找到项目可接受的平衡点&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="_12"&gt;安全防护机制&lt;/h2&gt;
&lt;p&gt;RAG 系统面临独特的安全风险，尤其是知识库中常包含敏感信息。&lt;/p&gt;
&lt;p&gt;主要风险：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提示攻击诱导模型泄露文档。&lt;/li&gt;
&lt;li&gt;外部调用时暴露知识片段。&lt;/li&gt;
&lt;li&gt;向量数据库被入侵。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键防护：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;访问控制&lt;/strong&gt;：基于身份验证与多租户隔离。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;本地化部署&lt;/strong&gt;：在安全场景中，完全自建 LLM 与数据库。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;加密存储&lt;/strong&gt;：加密文本块，检索后解密；但向量必须明文存放，存在风险。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;向量攻击防护&lt;/strong&gt;：通过加噪、变换或降维降低可逆性（会增加复杂度与性能损耗）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;核心结论：&lt;strong&gt;敏感信息必须有明确的边界与控制机制&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="rag_1"&gt;多模态RAG系统&lt;/h2&gt;
&lt;p&gt;多模态 RAG 将文本扩展到 &lt;strong&gt;图像（甚至音频/视频）&lt;/strong&gt;，检索与提示均可跨模态，输出仍为文本。&lt;/p&gt;
&lt;p&gt;关键机制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;strong&gt;多模态嵌入器&lt;/strong&gt; 将文本与图像映射到同一向量空间。&lt;/li&gt;
&lt;li&gt;使用 &lt;strong&gt;语言-视觉模型（VLM）&lt;/strong&gt; 接收多模态输入并生成文本输出。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在检索流程中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;同模空间检索&lt;/strong&gt;：查询可为文本或图像，统一编码后进行向量搜索。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文档格式扩展&lt;/strong&gt;：PPT、PDF 等转为图像再分块嵌入。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PDF-RAG 技术&lt;/strong&gt;：将页面切分成数百小块嵌入，支持细粒度检索，但会显著增加向量规模。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;要点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;架构升级成本低，仅需替换嵌入器和 LLM。&lt;/li&gt;
&lt;li&gt;检索更精准，但存储与计算开销增加（可用量化、分层存储、粗检-精排优化）。&lt;/li&gt;
&lt;li&gt;生态正在快速发展，主流厂商已推出 VLM，多模态嵌入器逐渐成熟。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一句话总结：&lt;strong&gt;多模态 RAG 通过“同空间嵌入 + VLM 生成”打通文本与图像，实现更丰富的知识检索与问答&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="_13"&gt;总结&lt;/h2&gt;
&lt;p&gt;进入生产环境后，RAG 系统将面临更复杂的挑战：高流量、不确定性错误、潜在安全风险。&lt;br&gt;
本模块的核心收获：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;评估体系&lt;/strong&gt;：可观测性、日志、系统级与组件级评估。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;权衡策略&lt;/strong&gt;：在质量、成本、延迟之间找到最佳平衡点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全防护&lt;/strong&gt;：确保敏感信息的边界。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多模态扩展&lt;/strong&gt;：突破文本限制，支持更广泛的知识格式。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;至此，你已具备从 &lt;strong&gt;原型到生产&lt;/strong&gt; 构建 RAG 系统的完整基础。课程希望你不仅掌握方法与技巧，也能带着灵感去探索更复杂、更真实的 AI 应用场景。&lt;/p&gt;</content><category term="Blog"/><category term="RAG"/><category term="信息检索"/><category term="LLM"/><category term="检索增强生成"/></entry><entry><title>展望未来十年：C++ 的下一步 —— Herb Sutter @ CppCon 2024</title><link href="https://wizmann.top/peering-forward-cpp-next-decade.html" rel="alternate"/><published>2025-09-29T10:00:00+08:00</published><updated>2025-09-29T10:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-09-29:/peering-forward-cpp-next-decade.html</id><summary type="html">&lt;div class="alert alert-warning" role="alert"&gt;
  ⚠️ 本文根据视频字幕和 slides 由 AI 生成
&lt;/div&gt;

&lt;hr&gt;
&lt;p&gt;Keynote：&lt;a href="https://github.com/CppCon/CppCon2024/blob/main/Presentations/Peering_Forward_Cpps_Next_Decade.pdf"&gt;&lt;strong&gt;Peering Forward: C++’s Next Decade&lt;/strong&gt;（CppCon 2024）&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="tldr"&gt;TL;DR（官方脉络）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;重大进展在路上&lt;/strong&gt;：&lt;code&gt;std::execution&lt;/code&gt; 并发/并行、类型与内存安全改 …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;div class="alert alert-warning" role="alert"&gt;
  ⚠️ 本文根据视频字幕和 slides 由 AI 生成
&lt;/div&gt;

&lt;hr&gt;
&lt;p&gt;Keynote：&lt;a href="https://github.com/CppCon/CppCon2024/blob/main/Presentations/Peering_Forward_Cpps_Next_Decade.pdf"&gt;&lt;strong&gt;Peering Forward: C++’s Next Decade&lt;/strong&gt;（CppCon 2024）&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="tldr"&gt;TL;DR（官方脉络）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;重大进展在路上&lt;/strong&gt;：&lt;code&gt;std::execution&lt;/code&gt; 并发/并行、类型与内存安全改进、反射 + 代码生成（“注入”）、Contracts；其中部分内容&lt;strong&gt;已进入 C++26&lt;/strong&gt; 的初始投票/合入节奏。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主旋律&lt;/strong&gt;：把更多工作“左移”到编译期；以 &lt;strong&gt;安全性对标（parity）&lt;/strong&gt; 为目标（而非完美），逐步减少未定义行为；通过&lt;strong&gt;泛化带来简化&lt;/strong&gt;，让代码直接表达“意图”。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="1"&gt;1) 术语澄清：三种“安全”，别混了&lt;/h2&gt;
&lt;p&gt;Herb 明确区分了三个层面的“安全”，并给出行业场景示例（ISO/IEC 23643:2020 术语脉络）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Software security（网络/信息安全）&lt;/strong&gt;：让软件能抵御恶意攻击、保护资产（电网、医院、银行、个人数据等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Software safety（生命/功能安全）&lt;/strong&gt;：避免对人、财产、环境造成不可接受的风险（如医院设备、自动驾驶/武器）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Programming language safety（语言/内存安全）&lt;/strong&gt;：对程序正确性的静态/动态保证，既能提升前两者，也能普遍提高质量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Herb 把“内存安全攻击”称作一场&lt;strong&gt;进行中的冷战&lt;/strong&gt;，强调这既有现实紧迫性，也影响语言设计优先级。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="2-c2629"&gt;2) 大方向：C++26/29 的主线与“安全对标”目标&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优先处理的四大类问题&lt;/strong&gt;：类型、边界、初始化、生命周期（正好对应最严重的四类 CWE，且现代语言普遍做得更好）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“安全 Profile” 框架&lt;/strong&gt;（Stroustrup &amp;amp; Dos Reis）：把（多半已知的）静态安全规则&lt;strong&gt;上移到编译期&lt;/strong&gt;，可按“代码体积/模块”选择地逐步启用，并&lt;strong&gt;可增量演进&lt;/strong&gt;。给“Profile”下了明确定义：一组在编译期强制的规则，保证消除某类缺陷。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;采用策略&lt;/strong&gt;：仍旧坚持“默认性能与可控性”，同时做到“安全随处可用”，愿景是&lt;strong&gt;“今天：靠警惕；明天：可选择 opt-out”&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="3-c26-erroneous-behavior"&gt;3) C++26 新武器：“erroneous behavior”（错误行为）&lt;/h2&gt;
&lt;h3 id="31"&gt;3.1 背景与改变&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;读取未初始化局部变量，传统上是 &lt;strong&gt;UB（未定义行为）&lt;/strong&gt; —— 这会导致“时间旅行/泄密”等坏结果。C++26 将&lt;strong&gt;引入“错误行为（erroneous behavior）”&lt;/strong&gt; 的概念：&lt;strong&gt;行为被明确定义为“就是错”&lt;/strong&gt;，编译器需写入“错误值”，从而避免“UB 的魔法”破坏安全。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;量化收益&lt;/strong&gt;：预计可&lt;strong&gt;自动消除一大类（5%-10%）&lt;/strong&gt; 的漏洞/缺陷，而且&lt;strong&gt;无需改动旧代码，只要重编译即可&lt;/strong&gt;——这对“可采纳性”极为关键。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="32"&gt;3.2 小例子（信息泄露不再发生）&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;s&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;e&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;e&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;t&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;// 未初始化&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// C++26: 打印“错误值”（绝不会是 &amp;quot;secret&amp;quot;）&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f1&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;如上示例中，旧世界里常见的“泄密”将不再发生。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;为什么不“统一零初始化”？Herb 给出的理由包括：零并不总是语义正确值，且会&lt;strong&gt;掩盖真实问题&lt;/strong&gt;（让静态/动态工具难以发现），还有成本因素（大对象清零）。需要时也可以&lt;strong&gt;显式 opt-out&lt;/strong&gt;：&lt;code&gt;int a [[indeterminate]];&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="4"&gt;4) “初始化前置”与“边界安全”：从规范到工程可采纳&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;不要强行“声明即初始化”或“用模式填充”&lt;/strong&gt;：这类“塞入无意义写入”的做法会给优化与静态分析带来困境。真正想要的是&lt;strong&gt;“首次使用前必然完成初始化（definite initialization）”&lt;/strong&gt;。Herb 指出 C#、Ada 等已有实践，且在 &lt;strong&gt;Cpp2&lt;/strong&gt; 中已实现原型：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;局部变量默认&lt;strong&gt;未初始化&lt;/strong&gt;（性能优先），但&lt;strong&gt;任一路径首次使用前必须完成构造&lt;/strong&gt;；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;通过直接构造或“out 形参的填充函数”均可；&lt;/li&gt;
&lt;li&gt;这样即可组合化地表达“初始化策略”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;边界检查（Bounds）&lt;/strong&gt;：在 &lt;strong&gt;Cpp2&lt;/strong&gt; 的实证中，对&lt;strong&gt;连续容器的 &lt;code&gt;a[b]&lt;/code&gt;&lt;/strong&gt; 注入 &lt;code&gt;0 &amp;lt;= b &amp;amp;&amp;amp; b &amp;lt; size(a)&lt;/code&gt; 形式的&lt;strong&gt;调用点检查&lt;/strong&gt;，违例通过契约处理（可自定义）。无需改 STL 或大多数容器实现，也适用于 C 数组（在衰变前）。这类检查可通过将来标准的 &lt;strong&gt;“bounds Profile”&lt;/strong&gt; 一键启用（理念上“启用 Profile 并重编译”）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例（越界检测理念）&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;//   int              a[] = {1,2,3};&lt;/span&gt;
&lt;span class="c1"&gt;//   std::vector&amp;lt;int&amp;gt; a   = {1,2,3};&lt;/span&gt;

&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ok&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 触发边界违例（在 Cpp2 原型中通过契约报告）&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;h2 id="5-aka"&gt;5) “海啸将至”：反射 + 代码生成（a.k.a. 注入）&lt;/h2&gt;
&lt;p&gt;Herb 认为 &lt;strong&gt;反射 + 生成&lt;/strong&gt; 将是&lt;strong&gt;未来十年最重要的语言能力&lt;/strong&gt;，与 &lt;code&gt;constexpr&lt;/code&gt; 一同构成“把更多意图抬到编译期”的关键通道；并强调 &lt;strong&gt;C++ 是我们想要的“编译期语言”，也是我们想要的“GPU 语言”&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="51-p2996"&gt;5.1 P2996：以“命令行解析器”为例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MyOpts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;input.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// --file_name &amp;lt;string&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;// --count &amp;lt;int&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MyOpts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parse_options&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyOpts&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string_view&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;opts.file=&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;opts.count=&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;parse_options&lt;/code&gt; 利用反射枚举数据成员、识别标识符、推导成员类型，并拼接生成解析逻辑（示例里可见 &lt;code&gt;nonstatic_data_members_of&lt;/code&gt;, &lt;code&gt;identifier_of&lt;/code&gt;, &lt;code&gt;type_of&lt;/code&gt;, 以及“&lt;strong&gt;splices&lt;/strong&gt;/注入语法”）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;实现进展：已有 &lt;strong&gt;EDG&lt;/strong&gt; 与 &lt;strong&gt;Clang&lt;/strong&gt; 原型跟进 P2996（EDG：Daveed Vandevoorde；Clang：Dan Katz/Bloomberg；另有 Lock3、Circle、cppfront 等相关探索）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="52-p0707metafunctionsmetaclass"&gt;5.2 P0707（metafunctions/metaclass）：“接口”一键生成&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;手写接口类&lt;/strong&gt;（纯虚 + 析构 + 禁复制）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;IFoo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;IFoo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IFoo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IFoo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IFoo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IFoo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;用元类表达“意图”&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IFoo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;底层可由 &lt;code&gt;interface(...)&lt;/code&gt; 元函数在编译期&lt;strong&gt;反射原型并生成&lt;/strong&gt;上述纯虚骨架与语义约束。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;幻灯还给出了 &lt;code&gt;interface&lt;/code&gt; 的实现片段：使用 &lt;code&gt;identifier_of&lt;/code&gt;, &lt;code&gt;members_of&lt;/code&gt;, &lt;code&gt;return_type_of&lt;/code&gt;, &lt;code&gt;parameter_list_of&lt;/code&gt; 等元函数在编译期&lt;strong&gt;拼接类定义&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="53"&gt;5.3 “通过泛化获得简化”：三条“北极星”准则&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;源代码中所有信息都必须可反射&lt;/strong&gt;（包括属性、默认值等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;凡是能手写的源代码，都必须能生成&lt;/strong&gt;（类型、自由函数、对 &lt;code&gt;std::&lt;/code&gt; 模板的特化等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;所有代码（手写或生成）都必须可见&lt;/strong&gt;（可 pretty-print、可调试、可展开）。&lt;br&gt;
   此处还延展到&lt;strong&gt;编译期产物&lt;/strong&gt;（如 &lt;code&gt;.winmd&lt;/code&gt; 等）也应能在编译期生成。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="6-qtcom"&gt;6) 生态/工具的“可表达性扩展”：从 Qt/COM 到物理数据模型&lt;/h2&gt;
&lt;p&gt;Herb 展示了若干“把外部代码生成/IDL/脚本&lt;strong&gt;收回到 C++ 源&lt;/strong&gt;”的&lt;strong&gt;草案式&lt;/strong&gt;思路：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Qt moc&lt;/strong&gt;：用 &lt;code&gt;class(Qclass) ...&lt;/code&gt; + &lt;code&gt;property/signal/slot&lt;/code&gt; 的语义化声明，代替额外的 &lt;code&gt;.moc&lt;/code&gt; 生成链路。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;COM/WinRT&lt;/strong&gt;：以 &lt;code&gt;class(rt_interface&amp;lt;...&amp;gt;)&lt;/code&gt; 形式表达 IDL 语义（比如 &lt;code&gt;property&amp;lt;UINT, SomeClass&amp;gt;&lt;/code&gt;），统一到编译期反射+生成。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;粒子物理的 podio&lt;/strong&gt;：将原本的 YAML 数据模型描述迁回到 &lt;strong&gt;&lt;code&gt;class(podio::datatype)&lt;/code&gt;&lt;/strong&gt; 里，用 &lt;code&gt;constexpr&lt;/code&gt; 静态字符串与生成管线&lt;strong&gt;在常规 C++ 编译中完成同等产物&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="7"&gt;7) 更多实用范例&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;instrumented vector&lt;/strong&gt;：对模板实体执行 &lt;strong&gt;“identity+增强”&lt;/strong&gt; 的生成（示例在 &lt;code&gt;operator[]&lt;/code&gt; 包裹统计逻辑），说明“反射+生成”不仅能&lt;strong&gt;复制粘贴&lt;/strong&gt;，还能&lt;strong&gt;普遍地为一类实体注入横切逻辑&lt;/strong&gt;（计数、日志、检测等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;编译期 regex&lt;/strong&gt;：对比 &lt;strong&gt;CTRE&lt;/strong&gt; 与 &lt;strong&gt;cppfront 的 &lt;code&gt;@regex&lt;/code&gt;&lt;/strong&gt;，均通过编译期解析/生成专用匹配器以获高效实现，体现“&lt;strong&gt;把意图抬到编译期&lt;/strong&gt;”的性能与可维护性价值。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="8-gpu-constexpr-c"&gt;8) GPU 与 &lt;code&gt;constexpr&lt;/code&gt; 的共同语言：C++ 本体&lt;/h2&gt;
&lt;p&gt;幻灯强调了一个观察：多年来 C++ 在 &lt;strong&gt;&lt;code&gt;constexpr&lt;/code&gt; 的可执行性&lt;/strong&gt; 与 &lt;strong&gt;GPU 编程模型&lt;/strong&gt; 的融合路径上不断前进，&lt;strong&gt;“C++ 就是我们想要的编译期语言，也是 GPU 语言”&lt;/strong&gt;，因此&lt;strong&gt;不要引入背离 C++ 本体的“特殊循环/方言”&lt;/strong&gt;，而是尽可能让&lt;strong&gt;同一语言&lt;/strong&gt;在不同阶段/目标上自然工作。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="9"&gt;9) 风险与设计护栏&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;这类演进需要“&lt;strong&gt;北极星&lt;/strong&gt;”（目标用例的前瞻清单）与“&lt;strong&gt;护栏&lt;/strong&gt;”（防止底层碎片化导致拼不上整体图景）。&lt;/li&gt;
&lt;li&gt;建议目标：&lt;strong&gt;P0707 元函数&lt;/strong&gt;、&lt;strong&gt;Andrei 的 instrumented_vector&lt;/strong&gt;、以及“&lt;strong&gt;反射+再生成任意类型（恒等变换）&lt;/strong&gt;”。&lt;/li&gt;
&lt;li&gt;应&lt;strong&gt;吸取 C#、D、Lock3、cppfront&lt;/strong&gt; 等经验，避免“只顾底层细节而忽略端到端场景”。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="10-c"&gt;10) 结语：欢迎来到 C++ 的下一个十年&lt;/h2&gt;
&lt;p&gt;Herb 的判断：&lt;strong&gt;反射+生成&lt;/strong&gt; 将主导下一个十年；&lt;br&gt;
它会&lt;strong&gt;让难事变易&lt;/strong&gt;（如 复杂 Template MetaProgramming、表达式模板），也会&lt;strong&gt;让“原本做不到”的事成为可能&lt;/strong&gt;（如大规模生成式编程）。第一阶段的标准化蓝图&lt;strong&gt;已经在望&lt;/strong&gt;。&lt;/p&gt;</content><category term="C++"/><category term="C++"/><category term="CppCon"/><category term="Herb Sutter"/><category term="编译期编程"/><category term="安全性"/><category term="反射"/><category term="元类"/></entry><entry><title>Deeplearning.ai 《Retrieval-Augmented Generation (RAG)》课程导读（三）</title><link href="https://wizmann.top/deeplearning-ai-rag-course-intro-3.html" rel="alternate"/><published>2025-09-24T10:00:00+08:00</published><updated>2025-09-24T10:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-09-24:/deeplearning-ai-rag-course-intro-3.html</id><summary type="html">&lt;p&gt;&lt;a href="https://www.bilibili.com/video/BV1QRbnzTEyK?spm_id_from=333.788.videopod.episodes&amp;amp;vd_source=dbe2034ffbdf969aa84f0fa33428b1ae"&gt;源视频&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;根据视频字幕生成，是给不想看视频的人准备的速读文档&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="llm"&gt;LLM 简介&lt;/h2&gt;
&lt;p&gt;RAG 系统由检索器和 LLM 两部分组成。检索器负责找 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://www.bilibili.com/video/BV1QRbnzTEyK?spm_id_from=333.788.videopod.episodes&amp;amp;vd_source=dbe2034ffbdf969aa84f0fa33428b1ae"&gt;源视频&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;根据视频字幕生成，是给不想看视频的人准备的速读文档&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="llm"&gt;LLM 简介&lt;/h2&gt;
&lt;p&gt;RAG 系统由检索器和 LLM 两部分组成。检索器负责找到信息，但真正决定回答效果的，是 LLM。&lt;/p&gt;
&lt;p&gt;在这一部分，学习目标包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;理解 LLM 的工作原理；&lt;/li&gt;
&lt;li&gt;掌握提升性能的方法；&lt;/li&gt;
&lt;li&gt;熟悉 Transformer 架构；&lt;/li&gt;
&lt;li&gt;学习如何在代码中调用 LLM，并逐步改进；&lt;/li&gt;
&lt;li&gt;探索一些高级技术和实用建议。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;完成后，你将能亲手构建一个小型 RAG 系统。&lt;/p&gt;
&lt;h2 id="transformer"&gt;Transformer 架构&lt;/h2&gt;
&lt;h3 id="_1"&gt;起源&lt;/h3&gt;
&lt;p&gt;Transformer 架构来自 2017 年的论文 &lt;strong&gt;《Attention Is All You Need》&lt;/strong&gt;。它最初用于机器翻译，由编码器和解码器组成。如今大多数语言模型使用解码器，嵌入模型使用编码器。&lt;/p&gt;
&lt;h3 id="_2"&gt;输入处理&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;分词：输入文本切分成 token；&lt;/li&gt;
&lt;li&gt;嵌入：每个 token 转换成向量；&lt;/li&gt;
&lt;li&gt;位置编码：加入顺序信息；&lt;/li&gt;
&lt;li&gt;注意力机制：token 之间相互“关注”，捕捉关联；&lt;br&gt;
   * 多头注意力可以从不同角度建模关系；&lt;/li&gt;
&lt;li&gt;前馈层：大量参数更新向量；&lt;/li&gt;
&lt;li&gt;堆叠：多层重复这些步骤，逐渐提升理解。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="_3"&gt;文本生成&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;模型基于向量预测下一个 token 的概率分布；&lt;/li&gt;
&lt;li&gt;按概率抽样生成 token；&lt;/li&gt;
&lt;li&gt;将新 token 加回输入，重复处理；&lt;/li&gt;
&lt;li&gt;直到生成结束符或达到长度限制。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="rag"&gt;与 RAG 的关系&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;注意力机制让模型能理解注入的检索信息；&lt;/li&gt;
&lt;li&gt;生成存在随机性，可能与检索内容不一致；&lt;/li&gt;
&lt;li&gt;计算开销大，是 RAG 成本的主要来源。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="llm_1"&gt;LLM 采样策略&lt;/h2&gt;
&lt;p&gt;LLM 每一步生成 token 都是从概率分布中随机选择。控制随机性很重要。&lt;/p&gt;
&lt;p&gt;常见方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;贪心解码&lt;/strong&gt;：总选最高概率 → 稳定但僵化；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;温度（Temperature）&lt;/strong&gt;：调节分布尖锐度，低温度更确定，高温度更随机；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Top-K&lt;/strong&gt;：从前 K 个候选中选；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Top-P（核采样）&lt;/strong&gt;：从累计概率 ≤ P 的候选集中选；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重复惩罚&lt;/strong&gt;：降低重复 token 的概率；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对数偏差（Logit Bias）&lt;/strong&gt;：人为调整特定 token 的概率。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;推荐默认配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;温度 = 0.8&lt;/li&gt;
&lt;li&gt;Top-P = 0.9&lt;/li&gt;
&lt;li&gt;重复惩罚 = 1.2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;应用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;低温度 + 低 Top-P&lt;/strong&gt;：适合代码、事实类任务；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高温度 + 高 Top-P&lt;/strong&gt;：适合写作、开放问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_4"&gt;模型选择方法&lt;/h2&gt;
&lt;p&gt;选择模型会影响速度、质量和成本。&lt;/p&gt;
&lt;h3 id="_5"&gt;主要指标&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;参数规模：1–100 亿为小模型，100–500 亿为大模型；&lt;/li&gt;
&lt;li&gt;成本：按百万 token 计价；&lt;/li&gt;
&lt;li&gt;上下文窗口：可处理的最大输入输出长度；&lt;/li&gt;
&lt;li&gt;延迟与速度：响应和生成速度；&lt;/li&gt;
&lt;li&gt;知识截止日期：越新越好。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_6"&gt;评估方式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;自动化基准：如 MMLU、编程测试；&lt;/li&gt;
&lt;li&gt;人工评估：如 LM Arena，基于 Elo 排名；&lt;/li&gt;
&lt;li&gt;模型评估模型（LLM-as-a-judge）：需注意偏差。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;方法论：先用量化指标缩小范围，再用质量评估确认。保持灵活，方便更新替换。&lt;/p&gt;
&lt;h2 id="_7"&gt;提示词工程（基础）&lt;/h2&gt;
&lt;p&gt;提示词通常包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;系统提示（设定语气和规则）；&lt;/li&gt;
&lt;li&gt;历史对话；&lt;/li&gt;
&lt;li&gt;检索结果；&lt;/li&gt;
&lt;li&gt;用户输入。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;RAG 中常用提示模板，把这些要素固定下来，方便实验和改进。&lt;/p&gt;
&lt;h2 id="_8"&gt;提示词工程（高级）&lt;/h2&gt;
&lt;p&gt;常见技术：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;上下文学习（ICL）&lt;/strong&gt;：在提示中加入示例（one-shot / few-shot）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;推理导向提示&lt;/strong&gt;：&lt;/li&gt;
&lt;li&gt;Scratchpad：先推理再回答；&lt;/li&gt;
&lt;li&gt;Chain-of-Thought：逐步推理；&lt;/li&gt;
&lt;li&gt;推理模型：自带推理能力，成本更高；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文管理&lt;/strong&gt;：对话过长时进行摘要或剪枝，避免占满上下文窗口。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_9"&gt;幻觉处理&lt;/h2&gt;
&lt;p&gt;幻觉指模型生成的虚假信息。常见类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;轻微错误（数值说错）；&lt;/li&gt;
&lt;li&gt;否认真实事实；&lt;/li&gt;
&lt;li&gt;编造不存在的信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;应对方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在系统提示中要求模型只基于检索结果回答，并引用来源；&lt;/li&gt;
&lt;li&gt;使用 Context Cite 等工具验证回答与文档的对应关系；&lt;/li&gt;
&lt;li&gt;用 ALCE 基准测试幻觉率和引用质量。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_10"&gt;性能评估&lt;/h2&gt;
&lt;p&gt;评估的目标是量化 LLM 在 RAG 中的表现。&lt;/p&gt;
&lt;p&gt;常用指标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;相关性&lt;/strong&gt;：回答是否满足用户需求；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可信度&lt;/strong&gt;：回答是否由检索文档支持；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;其他指标&lt;/strong&gt;：如引用准确性、抗干扰性（Ragas 库提供）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还可以结合：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户反馈（点赞/点踩）；&lt;/li&gt;
&lt;li&gt;A/B 测试（对比不同模型或参数）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;建议：结合自动化评估和人工反馈。&lt;/p&gt;
&lt;h2 id="rag_1"&gt;自主式 RAG&lt;/h2&gt;
&lt;p&gt;自主式 RAG 使用多个模型协作，而不是一个模型完成所有步骤。&lt;/p&gt;
&lt;p&gt;常见工作流：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;顺序工作流：按步骤依次完成；&lt;/li&gt;
&lt;li&gt;条件工作流：由路由模型决定是否检索或走哪条路径；&lt;/li&gt;
&lt;li&gt;迭代工作流：不断尝试直到合格；&lt;/li&gt;
&lt;li&gt;并行工作流：多个模型并行处理，再合并结果。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;小模型负责简单任务（高效低成本）；&lt;/li&gt;
&lt;li&gt;大模型负责复杂生成；&lt;/li&gt;
&lt;li&gt;专用模型负责引用或验证。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_11"&gt;总结&lt;/h2&gt;
&lt;p&gt;这一部分课程带来的主要收获：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;理解 Transformer 架构和 LLM 的工作机制；&lt;/li&gt;
&lt;li&gt;掌握采样策略，能控制输出的稳定性与多样性；&lt;/li&gt;
&lt;li&gt;学会如何在成本、速度、质量之间选择合适的模型；&lt;/li&gt;
&lt;li&gt;掌握提示工程的基本与高级方法；&lt;/li&gt;
&lt;li&gt;了解幻觉的成因与缓解方式；&lt;/li&gt;
&lt;li&gt;学习性能评估方法；&lt;/li&gt;
&lt;li&gt;认识多模型协作的自主式 RAG 思路。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些内容组成了构建和优化 RAG 系统的完整知识框架，也为将原型发展为生产系统奠定了基础。&lt;/p&gt;</content><category term="Blog"/><category term="RAG"/><category term="信息检索"/><category term="LLM"/><category term="检索增强生成"/></entry><entry><title>Deeplearning.ai 《Retrieval-Augmented Generation (RAG)》课程导读（二）</title><link href="https://wizmann.top/deeplearning-ai-rag-course-intro-2.html" rel="alternate"/><published>2025-09-22T10:00:00+08:00</published><updated>2025-09-22T10:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-09-22:/deeplearning-ai-rag-course-intro-2.html</id><summary type="html">&lt;p&gt;&lt;a href="https://www.bilibili.com/video/BV1QRbnzTEyK?spm_id_from=333.788.videopod.episodes&amp;amp;vd_source=dbe2034ffbdf969aa84f0fa33428b1ae"&gt;课程视频&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;根据视频字幕生成，是给不想看视频的人准备的速读文档&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;简介&lt;/h2&gt;
&lt;p&gt;在实际生产环境中，信息检索理论需要与大规模 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://www.bilibili.com/video/BV1QRbnzTEyK?spm_id_from=333.788.videopod.episodes&amp;amp;vd_source=dbe2034ffbdf969aa84f0fa33428b1ae"&gt;课程视频&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;根据视频字幕生成，是给不想看视频的人准备的速读文档&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;简介&lt;/h2&gt;
&lt;p&gt;在实际生产环境中，信息检索理论需要与大规模数据处理结合。传统关系型数据库虽能支撑大部分基础检索，但当文档规模扩展至数百万甚至数十亿，尤其涉及语义搜索时，其性能会显著下降。&lt;/p&gt;
&lt;p&gt;为此，我们需要&lt;strong&gt;向量数据库&lt;/strong&gt;。它专为存储与检索海量向量而设计，几乎等同于 RAG（Retrieval-Augmented Generation）系统的底层设施。本模块的核心目标是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;理解为什么向量数据库在向量检索方面更优；&lt;/li&gt;
&lt;li&gt;掌握多种搜索操作的执行方式；&lt;/li&gt;
&lt;li&gt;学习在生产级 RAG 系统中常用的优化技术（文档分块、查询解析、结果重排序等）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ann"&gt;ANN 算法&lt;/h2&gt;
&lt;p&gt;在语义搜索中，关键词匹配与向量相似度是基础。但若直接进行精确向量搜索，随着数据扩展，计算资源消耗与系统延迟会急剧增加。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;k近邻（kNN）&lt;/strong&gt;：计算查询与所有文档向量的距离并排序，返回前 k 个邻居。直观但扩展性差，计算量随数据线性增长。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;近似最近邻（ANN）&lt;/strong&gt;：通过牺牲精确度换取效率，保证结果“足够接近”。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;典型方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;NSW（可导航小世界）&lt;/strong&gt;：构建邻近图，搜索从随机起点出发逐步靠近目标。速度快但可能错过全局最优。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HNSW（分层 NSW）&lt;/strong&gt;：构建多层邻近图，从顶层到低层逐步收敛，时间复杂度近似对数级，能在十亿级规模下将延迟保持在几百毫秒。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;三大特性总结：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;搜索速度远超精确 kNN；&lt;/li&gt;
&lt;li&gt;返回近似最优解；&lt;/li&gt;
&lt;li&gt;依赖高质量的图构建（预处理耗时但可离线完成）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，ANN 是现代向量检索的核心基础。&lt;/p&gt;
&lt;h2 id="_2"&gt;向量数据库&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;向量数据库（Vector Database）&lt;/strong&gt;专为高维向量的存储与 ANN 检索而设计，在语义搜索中优势明显。&lt;/p&gt;
&lt;p&gt;核心优化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高效构建邻近图（如 HNSW 索引）；&lt;/li&gt;
&lt;li&gt;快速计算向量距离；&lt;/li&gt;
&lt;li&gt;在大规模应用中保持高扩展性与低延迟。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;典型产品：&lt;strong&gt;Weaviate&lt;/strong&gt;（开源，支持本地与云端），同时市面上还有 Milvus、Pinecone 等。&lt;/p&gt;
&lt;p&gt;操作流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;配置数据库&lt;/strong&gt;：连接或创建实例；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;准备数据&lt;/strong&gt;：生成稀疏向量（关键词搜索）和密集向量（语义搜索）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;创建索引&lt;/strong&gt;：构建 ANN 所需结构；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;添加数据&lt;/strong&gt;：批量写入集合（如 &lt;em&gt;article&lt;/em&gt;），自动生成语义向量并跟踪错误。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;支持的检索类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;向量搜索&lt;/strong&gt;（基于向量距离）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关键词搜索&lt;/strong&gt;（BM25 倒排索引）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;混合搜索&lt;/strong&gt;（按权重结合语义与关键词结果）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;过滤查询&lt;/strong&gt;（属性条件筛选）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;流程总结：配置数据库 → 数据加载与索引 → 混合搜索 + 过滤。&lt;/p&gt;
&lt;h2 id="_3"&gt;文本分块技术&lt;/h2&gt;
&lt;p&gt;虽然向量数据库已对向量检索高度优化，但在生产环境中，&lt;strong&gt;文本分块（chunking）&lt;/strong&gt;依然是必需步骤。&lt;/p&gt;
&lt;p&gt;意义：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;嵌入模型有输入长度限制；&lt;/li&gt;
&lt;li&gt;分块能提升搜索相关性；&lt;/li&gt;
&lt;li&gt;仅将最相关片段传递给 LLM，节省上下文窗口。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;问题：若知识库中只有整本书的嵌入，检索相关性差且上下文占用过大。通过分块，可生成数百万片段向量，数据库能高效存储与检索。&lt;/p&gt;
&lt;p&gt;方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;固定大小分块&lt;/strong&gt;：如 250 字符/块，设置 10% 重叠，避免截断语义。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;递归字符切分&lt;/strong&gt;：优先按换行等标记切分，保持结构完整。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类型感知切分&lt;/strong&gt;：HTML 按标签，代码按函数，文本按段落等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;推荐默认方案：&lt;strong&gt;每块约 500 字符，重叠 50–100 字符&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="_4"&gt;高级分块技术&lt;/h2&gt;
&lt;p&gt;基础分块可能破坏语义，因此出现了高级方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;语义分块&lt;/strong&gt;：逐句向量化，若与前块相似度高则合并，否则切分。优点是块更符合语义转折，缺点是计算量大。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LLM 分块&lt;/strong&gt;：用语言模型直接根据语义和主题切分，黑箱但效果好，随着模型成本下降越来越可行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文感知分块（chunk enrichment）&lt;/strong&gt;：为每块生成摘要或上下文说明并与其一同嵌入，提升检索与生成效果。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;结论：多数系统使用固定或递归切分，语义/LLM 分块适合高质量场景；上下文感知分块可与任意方法叠加，常带来双重收益。&lt;/p&gt;
&lt;h2 id="_5"&gt;查询语句解析&lt;/h2&gt;
&lt;p&gt;用户查询往往模糊或冗余，直接送入数据库效果差，因此需做&lt;strong&gt;查询解析&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;常见方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;查询重写&lt;/strong&gt;（推荐优先）：利用 LLM 将冗长自然语言转为结构化检索友好语句，常显著提升效果。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;命名实体识别（NER）&lt;/strong&gt;：抽取地点、人名、日期等实体，用于元数据过滤。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;假设文档嵌入（HIDE）&lt;/strong&gt;：生成理想搜索结果的假设文档，嵌入后与知识库匹配。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;经验：多数场景下，&lt;strong&gt;查询重写&lt;/strong&gt;是性价比最高的必选步骤；NER 和 HIDE 更适合特定高精度场景。&lt;/p&gt;
&lt;h2 id="colbert"&gt;交叉编码器与 ColBERT&lt;/h2&gt;
&lt;p&gt;三类语义检索架构：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基础编码器（bi-encoder）&lt;/strong&gt;：查询与文档分别嵌入，依赖向量数据库搜索，速度快、存储小，但语境交互有限。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交叉编码器（cross-encoder）&lt;/strong&gt;：提示与文档拼接输入模型，直接输出相关性分数，质量最佳但极慢，仅适合重排序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ColBERT&lt;/strong&gt;：文档与查询逐词嵌入，评分时逐词匹配相加，兼具交互性与效率，但存储需求极大。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;结论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;默认用 bi-encoder；&lt;/li&gt;
&lt;li&gt;重排序用 cross-encoder；&lt;/li&gt;
&lt;li&gt;高精度场景（法律、医疗）可采用 ColBERT。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_6"&gt;检索结果重排序&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;重排序（reranking）&lt;/strong&gt;是在初始检索后、送入 LLM 前进行的关键步骤。&lt;/p&gt;
&lt;p&gt;流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;初始检索返回 20–100 个候选；&lt;/li&gt;
&lt;li&gt;用交叉编码器或 LLM 对候选重新打分；&lt;/li&gt;
&lt;li&gt;最终选取 5–10 个结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;优势：既利用 ANN 的高效性，又保证结果质量，显著提升相关性。&lt;/p&gt;
&lt;p&gt;工程实现：在大多数框架中，只需为查询添加参数即可启用重排序，改造成本低。实践表明，这是优化 RAG 时最值得优先尝试的手段之一。&lt;/p&gt;
&lt;h2 id="_7"&gt;总结&lt;/h2&gt;
&lt;p&gt;本模块内容涵盖了从算法原理到生产优化的完整路径：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ANN 算法&lt;/strong&gt;：以近似解换取高效搜索；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;向量数据库&lt;/strong&gt;：为高维向量检索而生，支撑大规模 RAG 系统；&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;优化技术&lt;/strong&gt;：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;文档分块：更细粒度语义捕捉 + 上下文节省；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;查询解析：让自然语言提示更适配检索；&lt;/li&gt;
&lt;li&gt;重排序：用强模型精修候选结果。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些方法常与混合搜索组合使用，是大多数生产级系统的标准做法。进阶方法（语义分块、LLM 分块、HIDE 等）则适合在验证效果后引入。&lt;/p&gt;
&lt;p&gt;最终，学习者将把这些知识整合进完整的 RAG 系统，掌握从&lt;strong&gt;基础检索到性能优化&lt;/strong&gt;的全链路技能。下一模块将转向 RAG 的另一核心：&lt;strong&gt;大语言模型&lt;/strong&gt;，探索如何在检索结果基础上生成更优答案。&lt;/p&gt;</content><category term="Blog"/><category term="RAG"/><category term="信息检索"/><category term="LLM"/><category term="检索增强生成"/></entry><entry><title>Deeplearning.ai 《Retrieval-Augmented Generation (RAG)》课程导读（一）</title><link href="https://wizmann.top/deeplearning-ai-rag-course-intro-1.html" rel="alternate"/><published>2025-09-13T10:00:00+08:00</published><updated>2025-09-13T10:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-09-13:/deeplearning-ai-rag-course-intro-1.html</id><summary type="html">&lt;p&gt;&lt;a href="https://www.bilibili.com/video/BV1QRbnzTEyK?spm_id_from=333.788.videopod.episodes&amp;amp;vd_source=dbe2034ffbdf969aa84f0fa33428b1ae"&gt;课程视频&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;根据视频字幕生成，是给不想看视频的人准备的速读文档&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="_1"&gt;课程背景&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;核心思想与价值&lt;/strong&gt;&lt;br&gt;
   RAG 将传统检索系统与大型 …&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://www.bilibili.com/video/BV1QRbnzTEyK?spm_id_from=333.788.videopod.episodes&amp;amp;vd_source=dbe2034ffbdf969aa84f0fa33428b1ae"&gt;课程视频&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;根据视频字幕生成，是给不想看视频的人准备的速读文档&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="_1"&gt;课程背景&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;核心思想与价值&lt;/strong&gt;&lt;br&gt;
   RAG 将传统检索系统与大型语言模型（LLM）结合，提升回答的准确性和时效性。它能接入额外数据（文档、内部资料等），解决训练数据覆盖不到的事实性问题。常用于客服、内部知识查询、医疗、教育等，是当前最主流的 AI 应用之一。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;发展趋势&lt;/strong&gt;&lt;br&gt;
   随着模型输入窗口增大和新一代推理模型出现，RAG 在减少幻觉、处理复杂任务、利用长文档方面进步显著。新趋势包括：&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;多模型协作（不同模型分工处理环节）；&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自主检索策略（模型自行决定查询方式）。&lt;/p&gt;
&lt;p&gt;这使 RAG 更智能、更实用。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;课程目标&lt;/strong&gt;&lt;br&gt;
   本课程覆盖从入门到进阶的 RAG 技术：数据准备、提示设计、上下文管理、超参调优与系统评估。重点是如何构建、优化和持续改进 RAG 系统，所学方法也能迁移到更广泛的生成式 AI 应用中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;学习收获&lt;/strong&gt;&lt;br&gt;
   学员将系统理解 RAG 原理，掌握构建与调优技能，并具备将其应用到复杂场景的能力。这是一项跨行业的高价值技能。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="_2"&gt;课程导览&lt;/h2&gt;
&lt;h3 id="_3"&gt;总述&lt;/h3&gt;
&lt;p&gt;LLM 在问答、总结、改写、代码生成中表现突出，但知识仅限训练数据，缺乏&lt;strong&gt;最新、私有、专业信息&lt;/strong&gt;，容易产生错误或“幻觉”。RAG 通过检索额外上下文，使输出更准确可靠，适应更多场景。&lt;/p&gt;
&lt;h3 id="llm"&gt;LLM 的能力与局限&lt;/h3&gt;
&lt;p&gt;LLM 本质是基于概率的“智能补全”：预测最可能的词序列，而非事实。当遇到未知知识（如企业数据或新闻）时，容易生成听似合理但错误的答案。&lt;br&gt;
局限包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;幻觉问题&lt;/strong&gt;：模型生成了听起来合理但事实错误的内容&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文窗口限制&lt;/strong&gt;：提示过长会增加成本甚至溢出&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="rag"&gt;RAG 架构&lt;/h3&gt;
&lt;p&gt;RAG = &lt;strong&gt;检索 + 生成&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用户问题 → 检索器 → 找到相关文档；&lt;/li&gt;
&lt;li&gt;问题 + 文档 → 增强提示 → 交给 LLM 生成回答。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;三大组件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;语言模型&lt;/strong&gt;：生成自然语言回答；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;知识库&lt;/strong&gt;：存放结构化/非结构化文档；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检索器&lt;/strong&gt;：搜索并排序最相关的内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_4"&gt;优势与挑战&lt;/h3&gt;
&lt;p&gt;优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;接入外部信息（私有/最新/专业）；&lt;/li&gt;
&lt;li&gt;减少幻觉；&lt;/li&gt;
&lt;li&gt;更新知识只需替换文档，不用重新训练；&lt;/li&gt;
&lt;li&gt;回答可带来源，便于验证；&lt;/li&gt;
&lt;li&gt;分工明确：检索器找信息，LLM 负责生成。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;挑战：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检索结果排序难以完美；&lt;/li&gt;
&lt;li&gt;返回文档过多或过少都会影响效果；&lt;/li&gt;
&lt;li&gt;需要持续评估和调优。&lt;br&gt;
  向量数据库是高效检索器的核心，但传统搜索引擎和关系型数据库的理念依然重要。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_5"&gt;课程展望&lt;/h3&gt;
&lt;p&gt;后续将深入探讨：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LLM 的生成与训练机制；&lt;/li&gt;
&lt;li&gt;检索器的相似度计算与优化；&lt;/li&gt;
&lt;li&gt;知识库的设计与更新策略。&lt;br&gt;
  学员将掌握原理与工程实践，能在不同场景中优化 RAG 系统。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="_6"&gt;信息检索与搜索基础&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;现实挑战&lt;/strong&gt;：用户提问自然语言；知识库数据多样且为“人读型”；系统需毫秒级返回高相关结果。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;目标&lt;/strong&gt;：掌握检索核心技术、混合搜索、性能评估与调优；通过实操为生产级 RAG 打基础。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_7"&gt;检索器架构：混合搜索&lt;/h3&gt;
&lt;p&gt;流程：查询 → 并行执行&lt;strong&gt;关键词检索&lt;/strong&gt;与&lt;strong&gt;语义检索&lt;/strong&gt; → 得到候选 → &lt;strong&gt;元数据过滤&lt;/strong&gt; → 融合排序 → 返回 Top-k。&lt;/p&gt;
&lt;p&gt;三大技术：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;关键词检索&lt;/strong&gt;：快、稳，适合术语/SKU/法条；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语义检索&lt;/strong&gt;：覆盖同义表达；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;元数据过滤&lt;/strong&gt;：基于权限、地区、时间等硬规则。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;融合方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RRF（Reciprocal Rank Fusion）&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="math"&gt;\(d\)&lt;/span&gt;&lt;/strong&gt;：一个候选结果（文档/段落/块）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="math"&gt;\(i\)&lt;/span&gt;&lt;/strong&gt;：第 &lt;span class="math"&gt;\(i\)&lt;/span&gt; 个独立的检索通道（或“基排器”）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="math"&gt;\(\operatorname{rank}_i(d)\)&lt;/span&gt;&lt;/strong&gt;：&lt;span class="math"&gt;\(d\)&lt;/span&gt; 在通道 &lt;span class="math"&gt;\(i\)&lt;/span&gt; 的&lt;strong&gt;名次&lt;/strong&gt;（1 表示第 1 名，2 表示第 2 名……）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;若 &lt;span class="math"&gt;\(d\)&lt;/span&gt; 不在该通道的候选截断（如 top-50）里，可视为&lt;strong&gt;没有贡献&lt;/strong&gt;（等价于 rank → ∞，分数趋近 0）。&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="math"&gt;\(K\)&lt;/span&gt;&lt;/strong&gt;：一个&lt;strong&gt;平滑常数&lt;/strong&gt;，用来“压低”尾部名次的贡献、凸显头部。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;越小&lt;/strong&gt;的 &lt;span class="math"&gt;\(K\)&lt;/span&gt;：前几名与后面名次的差距被&lt;strong&gt;放大&lt;/strong&gt;（更偏爱头部）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;越大&lt;/strong&gt;的 &lt;span class="math"&gt;\(K\)&lt;/span&gt;：各名次之间差别被&lt;strong&gt;缩小&lt;/strong&gt;（融合更温和）。&lt;/li&gt;
&lt;li&gt;经验上常取 10～100；也有人把 &lt;span class="math"&gt;\(K\)&lt;/span&gt; 设成与各通道候选截断（如 50/100）同量级。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="math"&gt;$$
\text{RRF}(d)=\sum_i \frac{1}{K+\operatorname{rank}_i(d)}
$$&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;线性加权和分&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="math"&gt;\(\text{score}(d)\)&lt;/span&gt;&lt;/strong&gt;：融合后的&lt;strong&gt;最终分数&lt;/strong&gt;（用于排序）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="math"&gt;\(\text{score}_{\text{sem}}(d)\)&lt;/span&gt;&lt;/strong&gt;：来自&lt;strong&gt;语义检索&lt;/strong&gt;的分数（如余弦相似度、内积或其变体）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="math"&gt;\(\text{score}_{\text{kw}}(d)\)&lt;/span&gt;&lt;/strong&gt;：来自&lt;strong&gt;关键词检索&lt;/strong&gt;的分数（如 BM25）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="math"&gt;\(\beta\in[0,1]\)&lt;/span&gt;&lt;/strong&gt;：权重系数，表示&lt;strong&gt;语义分数所占比例&lt;/strong&gt;；&lt;span class="math"&gt;\(1-\beta\)&lt;/span&gt; 是关键词分数比例。&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(\beta\)&lt;/span&gt; 大 → 更看重语义；&lt;span class="math"&gt;\(\beta\)&lt;/span&gt; 小 → 更看重关键词。  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="math"&gt;$$
\text{score}(d)=\beta\,\text{score}_{\text{sem}}(d)+(1-\beta)\,\text{score}_{\text{kw}}(d)
$$&lt;/div&gt;
&lt;p&gt;业务取舍：关键词优先 → 提高关键词权重；语义优先 → 提高语义权重。&lt;/p&gt;
&lt;h3 id="_8"&gt;三大技术要点&lt;/h3&gt;
&lt;h4 id="1"&gt;1) 元数据过滤&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;基于标题/作者/日期/部门/权限/地区等字段裁剪结果；&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优点&lt;/strong&gt;：简单、高速、可审计；能用硬规则保证“该/不该返回”；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;局限&lt;/strong&gt;：不考虑内容相关性，不能排序，需与其他检索结合。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-tf-idf-bm25"&gt;2) 关键词搜索（TF-IDF / BM25）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心思想&lt;/strong&gt;：根据词频与重要性打分。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优缺点&lt;/strong&gt;：快、稳、保证命中精确词，但无法处理同义改写，需语义补充。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;TF-IDF&lt;/strong&gt;&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{TF-IDF}(t,d)=\text{TF}(t,d)\times \text{IDF}(t)
$$&lt;/div&gt;
&lt;p&gt;其中，&lt;span class="math"&gt;\(t\)&lt;/span&gt; 表示一个词（term），&lt;span class="math"&gt;\(d\)&lt;/span&gt; 表示某个文档。词频（TF）刻画的是词在文档中的相对出现频率：&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{TF}(t,d)=\frac{f_{t,d}}{\sum_{t'} f_{t',d}}
$$&lt;/div&gt;
&lt;p&gt;这里 &lt;span class="math"&gt;\(f_{t,d}\)&lt;/span&gt; 是词 &lt;span class="math"&gt;\(t\)&lt;/span&gt; 在文档 &lt;span class="math"&gt;\(d\)&lt;/span&gt; 中出现的次数，分母是文档中所有词的出现总数。&lt;/p&gt;
&lt;p&gt;逆文档频率（IDF）则衡量一个词的区分能力：&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{IDF}(t)=\log\frac{N}{1+n_t}
$$&lt;/div&gt;
&lt;p&gt;其中 &lt;span class="math"&gt;\(N\)&lt;/span&gt; 是语料库的总文档数，&lt;span class="math"&gt;\(n_t\)&lt;/span&gt; 是包含词 &lt;span class="math"&gt;\(t\)&lt;/span&gt; 的文档数。一个词在语料中越常见，它的 IDF 值就越小，因而在计算 TF-IDF 时权重越低。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BM25&lt;/strong&gt;&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{BM25}(q,d)=\sum_{t\in q}\text{IDF}(t)\cdot
\frac{f_{t,d}(k_1+1)}{f_{t,d}+k_1\left(1-b+b\frac{|d|}{\text{avgdl}}\right)}
$$&lt;/div&gt;
&lt;p&gt;这里，&lt;span class="math"&gt;\(q\)&lt;/span&gt; 表示查询，&lt;span class="math"&gt;\(d\)&lt;/span&gt; 表示候选文档，求和遍历查询中的每个词 &lt;span class="math"&gt;\(t\)&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;其中的 &lt;span class="math"&gt;\(\text{IDF}(t)\)&lt;/span&gt; 与 TF-IDF 中类似，用来衡量词的区分能力：&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{IDF}(t)=\log\frac{N-n_t+0.5}{n_t+0.5}+1
$$&lt;/div&gt;
&lt;p&gt;公式里的 &lt;span class="math"&gt;\(f_{t,d}\)&lt;/span&gt; 是词 &lt;span class="math"&gt;\(t\)&lt;/span&gt; 在文档 &lt;span class="math"&gt;\(d\)&lt;/span&gt; 中出现的次数；&lt;span class="math"&gt;\(|d|\)&lt;/span&gt; 表示文档的长度（通常用词数计），&lt;span class="math"&gt;\(\text{avgdl}\)&lt;/span&gt; 是语料库中的平均文档长度。&lt;/p&gt;
&lt;p&gt;分母部分的参数 &lt;span class="math"&gt;\(k_1\)&lt;/span&gt; 和 &lt;span class="math"&gt;\(b\)&lt;/span&gt; 起调节作用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(k_1\)&lt;/span&gt;（常取 1.2–2.0）控制&lt;strong&gt;词频饱和度&lt;/strong&gt;，即当词频越来越大时，得分增加会逐渐放缓；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(b\)&lt;/span&gt;（取值在 0–1，常设 0.75）控制&lt;strong&gt;文档长度归一化&lt;/strong&gt;，防止长文档因为词数多而天然占优。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;换句话说，BM25 在保留 IDF 权重的同时，对词频做了非线性饱和处理，并根据文档长度进行校正，比简单的 TF-IDF 更适合实际检索。&lt;/p&gt;
&lt;h4 id="3"&gt;3) 语义搜索（向量检索）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;机制&lt;/strong&gt;：嵌入模型 → 文本 → 高维向量；语义相似 → 向量接近。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;相似度度量&lt;/strong&gt;：余弦相似度、点积、欧氏距离。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;流程&lt;/strong&gt;：建向量索引 → 查询编码 → 相似度搜索 → 返回近邻。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;训练直觉&lt;/strong&gt;：对比学习让相似语义靠近，不同语义远离。注意不同嵌入模型不可直接对比。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_9"&gt;评估与调优&lt;/h3&gt;
&lt;p&gt;在评估检索器或 RAG 系统时，需要三类数据：一组查询、系统返回的排序列表，以及人工标注的“相关文档”基准集。基于这些数据，可以计算以下指标：&lt;/p&gt;
&lt;h4 id="1-precision-recallk"&gt;1. Precision / Recall（@k）&lt;/h4&gt;
&lt;p&gt;精确率与召回率是最常见的指标。&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{Precision@}k=\frac{\#\text{ relevant in top-}k}{k}
$$&lt;/div&gt;
&lt;div class="math"&gt;$$
\text{Recall@}k=\frac{\#\text{ relevant in top-}k}{|\text{Relevant}|}
$$&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Precision@k：前 k 个结果中有多少比例是相关文档；&lt;/li&gt;
&lt;li&gt;Recall@k：前 k 个结果覆盖了多少比例的相关文档。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通常，召回率上升往往会带来精度下降，因此需要根据场景设定合适的 k 值。&lt;/p&gt;
&lt;h4 id="2-ap-map"&gt;2. AP / MAP（排序质量）&lt;/h4&gt;
&lt;p&gt;平均精度（AP）用于衡量排序效果，强调“相关文档排得越靠前越好”。&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{AP@}k=\frac{1}{\min(R,k)}\sum_{i=1}^{k}\big[\text{rel}(i)\cdot \text{Precision@}i\big]
$$&lt;/div&gt;
&lt;p&gt;其中 &lt;span class="math"&gt;\(R\)&lt;/span&gt; 是相关文档总数，&lt;span class="math"&gt;\(\text{rel}(i)\)&lt;/span&gt; 表示第 i 个结果是否相关。&lt;/p&gt;
&lt;p&gt;将多个查询的 AP 取平均，就得到 MAP（Mean Average Precision）：&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{MAP@}k=\text{mean of AP@}k
$$&lt;/div&gt;
&lt;h4 id="3-mrrmean-reciprocal-rank"&gt;3. MRR（Mean Reciprocal Rank）&lt;/h4&gt;
&lt;p&gt;MRR 衡量系统把&lt;strong&gt;第一个相关文档&lt;/strong&gt;排在什么位置：&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{MRR}=\text{mean}\left(\frac{1}{\text{rank of first relevant}}\right)
$$&lt;/div&gt;
&lt;p&gt;相关文档越早出现，MRR 越高。&lt;/p&gt;
&lt;h4 id="_10"&gt;调优抓手&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;BM25&lt;/strong&gt;：调整 &lt;span class="math"&gt;\(k_1\)&lt;/span&gt;（词频饱和）和 &lt;span class="math"&gt;\(b\)&lt;/span&gt;（长度归一化）；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语义索引&lt;/strong&gt;：调整近邻搜索的参数；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;元数据&lt;/strong&gt;：权限、地区、时间窗等过滤策略；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;融合层&lt;/strong&gt;：RRF 的 &lt;span class="math"&gt;\(K\)&lt;/span&gt;，线性加权的 &lt;span class="math"&gt;\(\beta\)&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;调优方法通常是基于 &lt;strong&gt;Precision\@k、Recall\@k、MAP、MRR&lt;/strong&gt; 的 A/B 测试，验证系统是否“找得到、排得对”。虽然这些指标依赖人工标注，但可以通过抽样和滚动监控，形成持续的评估闭环。&lt;/p&gt;
&lt;h3 id="_11"&gt;实操与落地&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;设计顺序&lt;/strong&gt;：先设定硬过滤 → 再调关键词/语义权重与候选规模 → 最后融合排序。&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;业务权衡&lt;/strong&gt;：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;法条/零件号/药品名 → 关键词优先；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;客服问答/自然语言 → 语义优先。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工程目标&lt;/strong&gt;：平衡延迟、吞吐与质量；用少量超参（\&lt;span class="math"&gt;\(k\_1,b,K,\beta\\)&lt;/span&gt;）做精细调优。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_12"&gt;结论&lt;/h3&gt;
&lt;p&gt;掌握“关键词 × 语义 × 元数据”的混合检索，并用可重复的评估体系迭代优化，是构建&lt;strong&gt;可用、可控、可维护&lt;/strong&gt; RAG 系统的关键。接下来可以将这些方法应用到生产级检索器和增强提示链路中。&lt;/p&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Blog"/><category term="RAG"/><category term="信息检索"/><category term="LLM"/><category term="检索增强生成"/></entry><entry><title>树上启发式合并（DSU on Tree）</title><link href="https://wizmann.top/dsu-on-tree.html" rel="alternate"/><published>2025-07-13T00:00:00+08:00</published><updated>2025-07-13T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-07-13:/dsu-on-tree.html</id><summary type="html">&lt;h2 id="dsu-on-tree"&gt;什么是 DSU on Tree？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;DSU on Tree（Disjoint Set Union on Tree）&lt;/strong&gt;，中文称为“树上启发式合并”，是一种用于高效处理&lt;strong&gt;树上子树统计类问题&lt;/strong&gt;的算法技巧。尽管 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="dsu-on-tree"&gt;什么是 DSU on Tree？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;DSU on Tree（Disjoint Set Union on Tree）&lt;/strong&gt;，中文称为“树上启发式合并”，是一种用于高效处理&lt;strong&gt;树上子树统计类问题&lt;/strong&gt;的算法技巧。尽管其名称中含有 “DSU（并查集）”，但本质上与并查集并无直接关联。&lt;/p&gt;
&lt;p&gt;该方法广泛应用于以下场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;统计每个节点子树中的某类属性（如颜色种类、频次、权重等）；&lt;/li&gt;
&lt;li&gt;在递归过程中合并不同子树的统计信息，显著提升效率；&lt;/li&gt;
&lt;li&gt;避免大量冗余的 insert/delete 操作所造成的性能浪费。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其核心策略结合了&lt;strong&gt;启发式合并&lt;/strong&gt;（小的合并到大的）与&lt;strong&gt;重儿子优先保留&lt;/strong&gt;的思想，与树链剖分中的轻重边划分具有一致性。&lt;/p&gt;
&lt;p&gt;近年 LeetCode 也多次考察相关题目，说明该技巧即将成为面试中的高频考点（误&lt;/p&gt;
&lt;h2 id="_1"&gt;问题背景与动机&lt;/h2&gt;
&lt;h3 id="_2"&gt;示例题目：树上统计颜色种类数&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.luogu.com.cn/problem/U41492"&gt;题目链接&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一棵以 1 为根的树，每个节点有一个颜色。&lt;br&gt;
多次询问：以某个节点为根的子树中，有多少种不同的颜色？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;输出：对于每个查询，输出对应子树中的颜色种类数。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ 注意：原题中颜色 c[i] 可能为 0，代码中需进行特殊处理。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="dp"&gt;为什么不能直接使用树形 DP？&lt;/h3&gt;
&lt;p&gt;树形 DP 的典型做法是：递归处理每个子节点，将其统计结果合并到父节点。但这种策略在本问题中存在效率问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每次合并都需要对 map 或数组进行 insert/delete；&lt;/li&gt;
&lt;li&gt;若对子树数据进行暴力合并，可能会产生大量重复操作；&lt;/li&gt;
&lt;li&gt;最坏情况下，时间复杂度可能达到 O(n²)。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为解决这些问题，我们引入 &lt;strong&gt;DSU on Tree&lt;/strong&gt;。通过对重儿子保留、轻儿子清除的启发式策略，可以将时间复杂度优化至 &lt;strong&gt;O(n log n)&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="dsu-on-tree_1"&gt;DSU on Tree 的算法流程&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;预处理每个节点的子树大小，确定其重儿子（子树最大的孩子）；&lt;/li&gt;
&lt;li&gt;以 DFS 遍历整棵树，处理流程如下：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;首先递归处理所有轻儿子，并在处理后清除其统计结构；&lt;/li&gt;
&lt;li&gt;然后递归处理重儿子，保留其统计结果；&lt;/li&gt;
&lt;li&gt;接着将所有轻儿子的统计信息合并到当前维护的结构中；&lt;/li&gt;
&lt;li&gt;将当前节点自身的信息加入统计；&lt;/li&gt;
&lt;li&gt;更新该节点的答案。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;该策略确保：&lt;strong&gt;每个节点的信息最多被合并 log n 次&lt;/strong&gt;，大幅降低了总体复杂度。&lt;/p&gt;
&lt;h2 id="_3"&gt;算法原理与复杂度分析&lt;/h2&gt;
&lt;h3 id="_4"&gt;正确性说明&lt;/h3&gt;
&lt;p&gt;DSU on Tree 在整体结构上与树形 DP 一致，都是自底向上合并子树信息。不同之处在于合并顺序与数据结构管理策略更具启发性，从而降低了时间复杂度。其正确性自然继承于递归式的子树遍历结构。&lt;/p&gt;
&lt;h3 id="_5"&gt;重/轻儿子与边的定义&lt;/h3&gt;
&lt;p&gt;对于每个节点 &lt;span class="math"&gt;\(u\)&lt;/span&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;重儿子&lt;/strong&gt;：其所有子节点中，子树大小最大的一个；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;轻儿子&lt;/strong&gt;：其余所有子节点；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重边&lt;/strong&gt;：&lt;span class="math"&gt;\(u\)&lt;/span&gt; 与其重儿子之间的边；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;轻边&lt;/strong&gt;：&lt;span class="math"&gt;\(u\)&lt;/span&gt; 与轻儿子之间的边。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这一划分方式与树链剖分中的定义完全一致，旨在最大程度复用统计结构，减少数据迁移成本。&lt;/p&gt;
&lt;h3 id="log-n"&gt;为什么每个节点最多被合并 &lt;span class="math"&gt;\(\log n\)&lt;/span&gt; 次？&lt;/h3&gt;
&lt;p&gt;设某节点从根开始向下，在 DFS 过程中每经过一条轻边，子树规模至多减半：&lt;/p&gt;
&lt;div class="math"&gt;$$
\frac{n}{2^x} \geq 1 \Rightarrow x \leq \log_2 n
$$&lt;/div&gt;
&lt;p&gt;因此，一个节点作为被合并对象，最多经历 &lt;span class="math"&gt;\(\log n\)&lt;/span&gt; 次合并操作，从而将总体复杂度限制在 &lt;span class="math"&gt;\(O(n \log n)\)&lt;/span&gt; 范围内。&lt;/p&gt;
&lt;h3 id="_6"&gt;重边的作用&lt;/h3&gt;
&lt;p&gt;重边连接的是子树最大的孩子。在合并过程中，我们选择保留重儿子的统计结构，不清空、不重建，从而实现结构的复用和效率提升。&lt;/p&gt;
&lt;h2 id="_7"&gt;伪代码示例&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# 全局变量说明：&lt;/span&gt;
&lt;span class="c1"&gt;# g[u]：邻接表表示的树结构&lt;/span&gt;
&lt;span class="c1"&gt;# sz[u]：以 u 为根的子树大小&lt;/span&gt;
&lt;span class="c1"&gt;# big[u]：u 的重儿子（子树最大的孩子）&lt;/span&gt;
&lt;span class="c1"&gt;# col[u]：每个节点的颜色&lt;/span&gt;
&lt;span class="c1"&gt;# L[u], R[u]：u 的 DFS 序区间&lt;/span&gt;
&lt;span class="c1"&gt;# Node[i]：DFS 序编号 i 对应的节点编号&lt;/span&gt;
&lt;span class="c1"&gt;# cnt[c]：颜色为 c 的节点出现次数&lt;/span&gt;
&lt;span class="c1"&gt;# totColor：当前颜色种类数&lt;/span&gt;
&lt;span class="c1"&gt;# ans[u]：以 u 为根的子树的答案&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dfs0&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
    &lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;
    &lt;span class="n"&gt;sz&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;dfs0&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sz&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;sz&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;sz&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sz&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]]:&lt;/span&gt;
            &lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
    &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;totColor&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;totColor&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_answer&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;totColor&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dfs1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# 处理所有轻儿子并清除其贡献&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;dfs1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 处理重儿子，保留其统计数据&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;dfs1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 把所有轻儿子的 DFS 区间数据合并进来&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="c1"&gt;# 加入当前节点自身&lt;/span&gt;
    &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 保存当前节点答案&lt;/span&gt;
    &lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_answer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# 若不保留此子树信息，则清除&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_8"&gt;时间复杂度分析&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;每个节点的信息最多被合并 &lt;span class="math"&gt;\(\log n\)&lt;/span&gt; 次；&lt;/li&gt;
&lt;li&gt;每次合并操作为 &lt;span class="math"&gt;\(O(1)\)&lt;/span&gt;（若使用数组）或 &lt;span class="math"&gt;\(O(\log n)\)&lt;/span&gt;（若使用 map）；&lt;/li&gt;
&lt;li&gt;因此总复杂度为：$ O(n \log n) $&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于多数题目中，颜色值范围有限时可使用数组，使整体操作更接近线性。&lt;/p&gt;
&lt;h2 id="leetcode3575-maximum-good-subtree-score"&gt;例题：LeetCode3575 - Maximum Good Subtree Score&lt;/h2&gt;
&lt;p&gt;🔗 &lt;a href="https://leetcode.com/problems/maximum-good-subtree-score/description/"&gt;题目链接&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="_9"&gt;题意简述&lt;/h3&gt;
&lt;p&gt;给定一棵以 0 为根的树，每个节点有一个整数权值 &lt;code&gt;vals[i]&lt;/code&gt;，及其父节点 &lt;code&gt;par[i]&lt;/code&gt;。一个子树中，若&lt;strong&gt;任意子集&lt;/strong&gt;中所有节点的十进制表示中每个数字最多出现一次，该子集为“合法子集”。合法子集的得分为其节点权值之和。子集可以不连通。&lt;/p&gt;
&lt;p&gt;定义 &lt;code&gt;maxScore[u]&lt;/code&gt; 表示以节点 &lt;code&gt;u&lt;/code&gt; 为根的子树中，合法子集的最大得分。求所有节点的 &lt;code&gt;maxScore[u]&lt;/code&gt; 之和。&lt;/p&gt;
&lt;h3 id="_10"&gt;解法思路&lt;/h3&gt;
&lt;p&gt;这是典型的 DSU on Tree 应用场景，适用于子树统计类问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个节点 DFS 时记录子树中数字出现情况（用 bitmask）；&lt;/li&gt;
&lt;li&gt;合并时保留重儿子的统计结构，将轻儿子信息逐步合并进来；&lt;/li&gt;
&lt;li&gt;遇到重复数字时及时剪枝；&lt;/li&gt;
&lt;li&gt;使用“重儿子保留，轻儿子清除”策略，确保总复杂度不超限。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总复杂度控制在 &lt;span class="math"&gt;\(O(n \log n)\)&lt;/span&gt;，显著优于暴力枚举或者树形DP。&lt;/p&gt;
&lt;h2 id="_11"&gt;小结&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;DSU on Tree 是解决树上子树信息统计类问题的高效工具&lt;/strong&gt;，其主要优势包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;避免重复统计，提升合并效率；&lt;/li&gt;
&lt;li&gt;时间复杂度优秀，达 &lt;span class="math"&gt;\(O(n \log n)\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;与树链剖分的轻重边思想互补；&lt;/li&gt;
&lt;li&gt;实用性强，广泛应用于竞赛与工程题中。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_12"&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://oi-wiki.org/graph/dsu-on-tree/"&gt;OI Wiki：树上启发式合并&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/problems/maximum-good-subtree-score/description/"&gt;LeetCode3575 - Maximum Good Subtree Score&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.luogu.com.cn/problem/U41492"&gt;Luogu U41492 树上数颜色&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Blog"/><category term="数据结构"/><category term="树形DP"/><category term="启发式合并"/><category term="树链剖分"/><category term="DSU on Tree"/><category term="Leetcode"/></entry><entry><title>理解 C++ 同步原语的死锁风险</title><link href="https://wizmann.top/cpp-sync-deadlock-risks.html" rel="alternate"/><published>2025-06-22T10:00:00+08:00</published><updated>2025-06-22T10:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-06-22:/cpp-sync-deadlock-risks.html</id><summary type="html">&lt;p&gt;并发编程中最容易出错的地方之一，是对同步原语的误用，特别是死锁问题。使用 &lt;code&gt;std::mutex&lt;/code&gt;、&lt;code&gt;std::condition_variable&lt;/code&gt; 和 &lt;code&gt;std::semaphore&lt;/code&gt; 等机制时，一些表面上看 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;并发编程中最容易出错的地方之一，是对同步原语的误用，特别是死锁问题。使用 &lt;code&gt;std::mutex&lt;/code&gt;、&lt;code&gt;std::condition_variable&lt;/code&gt; 和 &lt;code&gt;std::semaphore&lt;/code&gt; 等机制时，一些表面上看似合理的代码，可能在某些边界条件下导致程序卡死，且难以调试。&lt;/p&gt;
&lt;p&gt;本文将列举一些典型易错模式，并提供对应的改进建议。&lt;/p&gt;
&lt;h2 id="stdmutex"&gt;std::mutex 的常见误用模式&lt;/h2&gt;
&lt;h3 id="11-mutex"&gt;1.1 多个 mutex 锁顺序不一致导致死锁&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Thread A&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mutex1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mutex2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Thread B&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mutex2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mutex1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ❌ 死锁风险&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;问题分析&lt;/strong&gt;：两个线程以不同的顺序加锁，可能互相等待对方释放资源，造成死锁。&lt;br&gt;
&lt;strong&gt;建议&lt;/strong&gt;：&lt;br&gt;
* 统一加锁顺序（如按锁的内存地址排序）&lt;br&gt;
* 使用 &lt;code&gt;std::scoped_lock&lt;/code&gt; 一次性加多个锁（C++17 起）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;scoped_lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mutex1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mutex2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="12"&gt;1.2 在持锁状态下调用外部函数&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;some_external_function&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ❌ 如果该函数内部也尝试加锁，可能死锁&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;建议&lt;/strong&gt;：避免在持锁状态下调用外部函数。必要时应将调用逻辑移至锁作用域之外。&lt;/p&gt;
&lt;h3 id="13"&gt;1.3 锁中递归调用自身或间接调用自己&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ❌ 间接递归调用，重复加锁，死锁&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;建议&lt;/strong&gt;：&lt;br&gt;
* 避免递归持有 &lt;code&gt;std::mutex&lt;/code&gt;。&lt;br&gt;
* 若必须递归使用，应改用 &lt;code&gt;std::recursive_mutex&lt;/code&gt;，但应慎用。&lt;/p&gt;
&lt;h3 id="14-mutex"&gt;1.4 使用裸指针或悬空 mutex 对象&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_mutex&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ❌ 如果 m 已析构，行为未定义&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;问题分析&lt;/strong&gt;：多个线程共享裸 mutex 指针，生命周期不可控，易造成悬空引用或崩溃。&lt;br&gt;
&lt;strong&gt;建议&lt;/strong&gt;：&lt;br&gt;
* 使用智能指针管理 mutex 生命周期。&lt;br&gt;
* 或将 mutex 作为静态变量或类成员持有。&lt;/p&gt;
&lt;h3 id="15-return"&gt;1.5 手动加锁，异常或提前 return 导致未解锁&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ❌ 忘记解锁，死锁风险&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;建议&lt;/strong&gt;：始终使用 RAII 风格的 &lt;code&gt;std::lock_guard&lt;/code&gt; 或 &lt;code&gt;std::unique_lock&lt;/code&gt;，避免忘记解锁：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ✅ 安全&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="stdrecursive_mutex"&gt;std::recursive_mutex 的误用风险&lt;/h2&gt;
&lt;p&gt;虽然 &lt;code&gt;std::recursive_mutex&lt;/code&gt; 允许同一线程多次加锁，但它&lt;strong&gt;不是死锁的万灵药&lt;/strong&gt;，常常掩盖设计缺陷或状态混乱。&lt;/p&gt;
&lt;h3 id="_1"&gt;示例问题：资源未及时释放&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;recursive_mutex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;recursive_mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 很长的逻辑，期间可能递归调用自身&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;问题分析&lt;/strong&gt;：虽然不会死锁，但锁持有时间可能过长，降低系统并发性。&lt;br&gt;
&lt;strong&gt;建议&lt;/strong&gt;：&lt;br&gt;
* 优先重构逻辑，避免递归加锁。&lt;br&gt;
* 仅在确实需要递归的少数场景使用。&lt;/p&gt;
&lt;h2 id="stdcondition_variable"&gt;std::condition_variable 的常见陷阱&lt;/h2&gt;
&lt;h3 id="31"&gt;3.1 忘记使用谓词检查条件&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;cv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ❌ 如果通知早于 wait，线程会永久阻塞&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;建议&lt;/strong&gt;：始终使用谓词版本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;cv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;理由&lt;/strong&gt;：防止虚假唤醒和时序问题。&lt;/p&gt;
&lt;h3 id="32-notify_one-notify_all"&gt;3.2 误用 &lt;code&gt;notify_one()&lt;/code&gt; 与 &lt;code&gt;notify_all()&lt;/code&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;cv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notify_one&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ❌ 多线程等待时，可能遗漏唤醒&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;建议&lt;/strong&gt;：&lt;br&gt;
* 多线程等待时，优先使用 &lt;code&gt;notify_all()&lt;/code&gt;。&lt;br&gt;
* 确保 notify 发生时 mutex 已持有，避免竞态。&lt;/p&gt;
&lt;h3 id="33-wait"&gt;3.3 wait 前未持有锁&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;cv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ❌ lock 未加锁，行为未定义&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;建议&lt;/strong&gt;：必须先通过 &lt;code&gt;std::unique_lock&amp;lt;std::mutex&amp;gt;&lt;/code&gt; 加锁，确保 &lt;code&gt;wait()&lt;/code&gt; 调用合法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_lock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;cv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="stdsemaphore-c20"&gt;std::semaphore 的使用误区（C++20 起）&lt;/h2&gt;
&lt;h3 id="41-release"&gt;4.1 忘记配对 &lt;code&gt;release()&lt;/code&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;binary_semaphore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ❌ 若未调用 release，线程将永久阻塞&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;建议&lt;/strong&gt;：&lt;br&gt;
* 保证每次 &lt;code&gt;acquire()&lt;/code&gt; 有对应的 &lt;code&gt;release()&lt;/code&gt;。&lt;br&gt;
* 使用带超时版本避免无限阻塞：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;try_acquire_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;chrono&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 超时处理逻辑&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="42-acquire-release"&gt;4.2 信号丢失：acquire 在 release 之后调用&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;binary_semaphore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ✅ 提前释放&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;this_thread&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sleep_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;chrono&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;milliseconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ❌ 晚于 release 执行&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ❌ 永久阻塞风险&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;问题分析&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;std::binary_semaphore&lt;/code&gt; 类似一个布尔标志，仅记录是否被释放过一次。&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;release()&lt;/code&gt; 先于 &lt;code&gt;acquire()&lt;/code&gt; 调用，且调用之间没有明确同步关系，信号可能“被丢失”。&lt;/li&gt;
&lt;li&gt;由于 &lt;code&gt;binary_semaphore&lt;/code&gt; 不累加信号（只能表示 0 或 1），先发生的 &lt;code&gt;release()&lt;/code&gt; 在没有等待者时不会保存“通知”。&lt;/li&gt;
&lt;li&gt;此问题在“先通知、后等待”场景中尤为常见，与 &lt;code&gt;condition_variable&lt;/code&gt; 的使用误区类似。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;建议&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保证 &lt;code&gt;acquire()&lt;/code&gt; 的调用时机在 &lt;code&gt;release()&lt;/code&gt; 之前或两者明确同步。&lt;/li&gt;
&lt;li&gt;如需支持先通知后等待，改用 &lt;code&gt;std::counting_semaphore&lt;/code&gt;，它支持信号积累。&lt;/li&gt;
&lt;li&gt;或使用超时接口避免无限阻塞：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;try_acquire_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;chrono&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 超时处理逻辑&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="43"&gt;4.3 多线程共享时释放不足&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;binary_semaphore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 做一些工作&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ❌ 仅释放一次，其余线程会永久等待&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;建议&lt;/strong&gt;：&lt;br&gt;
* 对 N 个等待线程，应调用 N 次 &lt;code&gt;release()&lt;/code&gt;。&lt;br&gt;
* 或使用 &lt;code&gt;counting_semaphore&lt;/code&gt; 表示资源总量。&lt;/p&gt;
&lt;h2 id="5"&gt;5. 总结建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;所有锁的使用都应&lt;strong&gt;结构化管理&lt;/strong&gt;，优先使用 RAII（如 &lt;code&gt;std::lock_guard&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;加锁逻辑应&lt;strong&gt;保持一致性&lt;/strong&gt;，避免递归加锁、交叉持锁、或生命周期不一致。&lt;/li&gt;
&lt;li&gt;条件变量使用时应始终搭配&lt;strong&gt;谓词检查&lt;/strong&gt;，避免时序或虚假唤醒问题。&lt;/li&gt;
&lt;li&gt;对 &lt;code&gt;semaphore&lt;/code&gt; 等底层原语，应设置&lt;strong&gt;超时保护&lt;/strong&gt;，防止意外永久阻塞。&lt;/li&gt;
&lt;li&gt;尽量避免裸指针、手动 lock/unlock 以及难以维护的状态共享逻辑。&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="C++"/><category term="并发编程"/><category term="死锁"/><category term="多线程"/><category term="mutex"/><category term="condition_variable"/><category term="semaphore"/></entry><entry><title>使用31mm灯片打造拓竹LED001的低配平替方案</title><link href="https://wizmann.top/led001-mini-alternative.html" rel="alternate"/><published>2025-06-22T00:00:00+08:00</published><updated>2025-06-22T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-06-22:/led001-mini-alternative.html</id><summary type="html">&lt;p&gt;拓竹 LED001 套件的标准尺寸为 &lt;strong&gt;直径 59mm、高度 35mm&lt;/strong&gt;（包含灯座和灯板），售价约为 28 元。虽然这是一款常见的标准件，市面上也能买到价 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;拓竹 LED001 套件的标准尺寸为 &lt;strong&gt;直径 59mm、高度 35mm&lt;/strong&gt;（包含灯座和灯板），售价约为 28 元。虽然这是一款常见的标准件，市面上也能买到价格更便宜（约 10 元）的兼容产品，但对于一些轻量级实验或原型用途来说，这个体积可能还是偏大。&lt;/p&gt;
&lt;p&gt;举例来说，如果我们将整个 3D 模型按某一维度缩小 50%，理论上材料使用量可以减少 75%，既降低成本，也更便于快速迭代。&lt;/p&gt;
&lt;p&gt;幸运的是，拼多多等平台上可以找到 &lt;strong&gt;直径 31mm 的小尺寸灯片&lt;/strong&gt;，带焊 USB 线的版本不到 5 元，裸灯片甚至不到 3 元。只要设计一个对应尺寸的灯板与灯座，我们就能轻松实现 LED001 的低配小型替代方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="_1"&gt;灯板设计&lt;/h2&gt;
&lt;p&gt;常见的 31mm 灯片实际直径略大，因此建议灯板设计的内径设为 &lt;strong&gt;33mm&lt;/strong&gt;，外径 &lt;strong&gt;35mm&lt;/strong&gt; 为宜。同时预留走线孔和散热孔，确保电源线可以顺利穿过，避免过热。&lt;/p&gt;
&lt;p&gt;此外，可选择是否加入导光板：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;不加导光板&lt;/strong&gt;：亮度更集中，但可能刺眼。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;加入导光板&lt;/strong&gt;：可适当柔化光线，提升视觉舒适度。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;导光板厚度建议在 &lt;strong&gt;0.6mm ~ 1mm&lt;/strong&gt; 之间，厚一些会降低亮度但提升均匀度。&lt;/p&gt;
&lt;p&gt;示意图如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/dengban-D33.png"&gt;&lt;br&gt;
&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/dengban-3mf-D33.png"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="_2"&gt;灯座设计&lt;/h2&gt;
&lt;p&gt;在 MakerWorld 平台上可以找到许多 LED001 的灯座模型，这些模型大多采用标准的旋转卡扣设计。我们可以复用这些设计，简单调整尺寸即可适配小尺寸灯片。&lt;/p&gt;
&lt;p&gt;推荐使用这个 &lt;a href="https://makerworld.com.cn/zh/models/637818-led001deng-gua-pei-di-zuo?from=search#profileId-576969"&gt;灯座模型&lt;/a&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/deng-zuo-led001.png"&gt;&lt;/p&gt;
&lt;p&gt;按 &lt;strong&gt;60% 比例&lt;/strong&gt; 缩小，使其内径为约 &lt;strong&gt;36mm&lt;/strong&gt;，同时扩大出线孔（可以直接在模型中添加负零件。后期用锉刀加工也可以，但是不推荐）。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/deng-zuo-led001-D18.png"&gt;&lt;/p&gt;
&lt;p&gt;修改后可直接打印。&lt;br&gt;
👉 缩小版模型可直接下载：&lt;a href="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/led001%E5%BA%95%E5%BA%A7-D18.3mf"&gt;点击这里&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="_3"&gt;灯体适配（简单版）&lt;/h2&gt;
&lt;p&gt;对于原本就设计用于 LED001 套件的灯体，我们同样可以将其 &lt;strong&gt;等比例缩小至 60%&lt;/strong&gt;，从而适配我们的小型灯板与灯座。&lt;/p&gt;
&lt;p&gt;以 &lt;a href="https://makerworld.com.cn/zh/models/1099900-lian-yi-tai-deng-tao-jian-ban?from=search#profileId-1148153"&gt;“涟漪”台灯模型&lt;/a&gt; 为例：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/lianyi-3mf.png"&gt;&lt;/p&gt;
&lt;p&gt;按 60% 缩小后，仅需约 &lt;strong&gt;28.2g 材料&lt;/strong&gt; 即可打印完成，而原模型则需约 &lt;strong&gt;88.7g&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/lianyi-components.png"&gt;&lt;br&gt;
&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/lianyi-light.png"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="_4"&gt;灯体适配（进阶版）&lt;/h2&gt;
&lt;p&gt;有些灯体模型并非专为 LED001 卡扣设计，或者我们使用的是自己建模的结构，但仍希望引入 LED001 的灯座卡口进行标准化连接。&lt;/p&gt;
&lt;p&gt;这时，可以利用 &lt;strong&gt;Bambu Lab 切片软件&lt;/strong&gt;的布尔运算功能，快速完成“翻模”操作，而无需手动建模。&lt;/p&gt;
&lt;p&gt;参考这个&lt;a href="https://www.bilibili.com/video/BV1pjPiekEqP/"&gt;教学视频&lt;/a&gt;，简要步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;导入模型&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;导入 LED 灯座卡扣模型并缩放到合适尺寸。&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;创建一个略大于开孔的圆柱体模型。&lt;br&gt;
&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/copy-model-step1.png"&gt;&lt;br&gt;
2. &lt;strong&gt;布尔运算 - 获取翻模件&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将两个模型居中对齐。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;右键组合 -&amp;gt; 使用布尔运算“差集”，选择“从中减去”圆柱体，“与之相减”为卡扣模型。勾选“删除输入”。&lt;br&gt;
&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/copy-model-step2.png"&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;制作孔洞模型&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;用生成的“翻模件”再对目标底座进行一次“差集”操作，即可获得精准匹配卡扣的孔位。&lt;br&gt;
&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/copy-model-step3.png"&gt;&lt;br&gt;
&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/copy-model-step4.png"&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="_5"&gt;小结&lt;/h2&gt;
&lt;p&gt;通过使用市售 31mm 灯片搭配自制小型灯板和灯座，我们可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;大幅降低成本&lt;/strong&gt;（灯片约 3 元，整体成本 &amp;lt;10 元）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;节省打印材料&lt;/strong&gt;（体积缩小后材料用量减少约 70%~75%）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;保持模块化设计&lt;/strong&gt;（可复用 LED001 卡口标准）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;适用于快速原型开发、创意DIY灯具、小空间照明等场景。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="_6"&gt;更多作品展示&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;瑞幸 LOGO 小夜灯&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;灯罩材质：JAYO PETG 透明蓝&lt;/li&gt;
&lt;li&gt;LOGO 部分：PLA 蓝色 + 白色&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/sample1.png"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;火焰灯（融合设计）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;灯罩：JAYO PETG 透明&lt;/li&gt;
&lt;li&gt;灯座：JAYO PETG 黑 + PLA 红&lt;/li&gt;
&lt;li&gt;模型融合自&lt;a href="https://makerworld.com.cn/zh/models/1166865-ling-hun-huo-yan-deng-led-deng-tao-jian-mh001?from=search#profileId-1232590"&gt;灵魂火焰灯&lt;/a&gt; 和 &lt;a href="https://makerworld.com.cn/zh/models/676999-diao-guang-di-zuo-001ledxi-lie-tong-yong?from=search#profileId-622765"&gt;调光底座&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/LED001-alternative/sample2.png"&gt;&lt;/p&gt;</content><category term="Blog"/><category term="3D打印"/><category term="3D模型"/><category term="DIY"/><category term="LED"/><category term="灯具设计"/></entry><entry><title>线段树入门：一种基于不变式的理解方式</title><link href="https://wizmann.top/segment-tree-by-invariant.html" rel="alternate"/><published>2025-06-12T00:00:00+08:00</published><updated>2025-06-12T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-06-12:/segment-tree-by-invariant.html</id><summary type="html">&lt;h2 id="_1"&gt;前言&lt;/h2&gt;
&lt;p&gt;线段树是一种在算法中频繁出现的数据结构，既实用又略带挑战性。它之所以常见，是因为在涉及&lt;strong&gt;区间查询与修改&lt;/strong&gt;的 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;前言&lt;/h2&gt;
&lt;p&gt;线段树是一种在算法中频繁出现的数据结构，既实用又略带挑战性。它之所以常见，是因为在涉及&lt;strong&gt;区间查询与修改&lt;/strong&gt;的问题中，线段树常常能提供高效解法；而之所以“高阶”，则是因为在实现过程中需要细致处理边界和递归逻辑，否则容易出现&lt;strong&gt;运行时错误（RE）&lt;/strong&gt;，因此也被戏称为“RE 树”（只有我）。&lt;/p&gt;
&lt;p&gt;市面上已有不少教程通过图解、动画等方式帮助初学者建立对线段树的直观印象。建议读者在阅读本文前，可先参考这些资料（见文末参考链接），以获得对线段树结构的整体感知。&lt;/p&gt;
&lt;p&gt;本文将尝试采用一种更为抽象的方式，从&lt;strong&gt;数据结构不变式&lt;/strong&gt;的角度，系统分析线段树的设计逻辑，并通过若干经典例题，展示如何在实践中运用这些思想来构建高效且可扩展的线段树变体。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="_2"&gt;基本原理：从递归到不变式&lt;/h2&gt;
&lt;p&gt;线段树的核心思想是：&lt;strong&gt;通过递归划分区间，使每个节点维护一个子区间的信息&lt;/strong&gt;，进而高效支持查询和修改操作。&lt;/p&gt;
&lt;h3 id="_3"&gt;示例：求区间最大值&lt;/h3&gt;
&lt;p&gt;以求解一个长度为 &lt;span class="math"&gt;\(n\)&lt;/span&gt; 的静态数组的区间最大值为例：&lt;/p&gt;
&lt;p&gt;设数组为 &lt;span class="math"&gt;\(\text{array}[1 \dots n]\)&lt;/span&gt;，我们定义 &lt;span class="math"&gt;\(\text{maxi}_{i,j}\)&lt;/span&gt; 表示区间 &lt;span class="math"&gt;\([i,j]\)&lt;/span&gt; 的最大值。&lt;/p&gt;
&lt;p&gt;当 &lt;span class="math"&gt;\(i = j\)&lt;/span&gt; 时，显然有：&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{maxi}_{i,i} = \text{array}[i]
$$&lt;/div&gt;
&lt;p&gt;若 &lt;span class="math"&gt;\(i &amp;lt; j\)&lt;/span&gt;，我们可以将其一分为二，划分为 &lt;span class="math"&gt;\([i,m]\)&lt;/span&gt; 与 &lt;span class="math"&gt;\([m+1,j]\)&lt;/span&gt;，其中 &lt;span class="math"&gt;\(m = \left\lfloor \frac{i+j}{2} \right\rfloor\)&lt;/span&gt;，进而递推：&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{maxi}_{i,j} = \max(\text{maxi}_{i,m}, \text{maxi}_{m+1,j})
$$&lt;/div&gt;
&lt;p&gt;这就是线段树的&lt;strong&gt;核心不变式&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;每个区间的信息完全由其左右子区间决定。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;基于这个不变式，我们可以自底向上构建整棵线段树，或在查询和修改过程中维护其正确性。&lt;/p&gt;
&lt;h2 id="_4"&gt;查询操作&lt;/h2&gt;
&lt;p&gt;当我们查询一个区间 &lt;span class="math"&gt;\([l,r]\)&lt;/span&gt; 的最大值时，可以递归地访问其子区间，并合并结果。&lt;/p&gt;
&lt;p&gt;最终，查询过程会遍历一组&lt;strong&gt;恰好覆盖区间 &lt;span class="math"&gt;\([l,r]\)&lt;/span&gt;&lt;/strong&gt; 的子区间，它们的最大值即为所求。&lt;/p&gt;
&lt;h2 id="_5"&gt;修改操作&lt;/h2&gt;
&lt;h3 id="_6"&gt;点修改&lt;/h3&gt;
&lt;p&gt;若数组中某个元素发生变动（如将 &lt;span class="math"&gt;\(\text{array}[k]\)&lt;/span&gt; 修改为 &lt;span class="math"&gt;\(v\)&lt;/span&gt;），只需从对应的叶子节点出发，沿路径向上传播更新信息，确保不变式在修改后依旧成立。该操作的时间复杂度为 &lt;span class="math"&gt;\(O(log n)\)&lt;/span&gt;。&lt;/p&gt;
&lt;h3 id="_7"&gt;区间修改与懒标记&lt;/h3&gt;
&lt;p&gt;对于支持区间修改的线段树，其核心操作可以抽象为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;区间更新&lt;/strong&gt;：对 &lt;span class="math"&gt;\([l, r]\)&lt;/span&gt; 中的所有元素执行某种操作，如加上一个常数 &lt;span class="math"&gt;\(c\)&lt;/span&gt;，即：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="math"&gt;$$
  \forall i \in [l, r],\quad A[i] := A[i] + c
  $$&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
* &lt;strong&gt;区间查询&lt;/strong&gt;：查询某一子区间 &lt;span class="math"&gt;\([l, r]\)&lt;/span&gt; 的某个聚合函数，如最小值、和、最大值等。&lt;/p&gt;
&lt;p&gt;若直接递归修改所有受影响的节点，则时间复杂度最坏为 &lt;span class="math"&gt;\(O(n)\)&lt;/span&gt;。为避免这一问题，引入**懒标记（Lazy Propagation）**机制，通过“延迟计算”优化操作效率。&lt;/p&gt;
&lt;h4 id="_8"&gt;不变式定义&lt;/h4&gt;
&lt;p&gt;设线段树的每个节点表示区间 &lt;span class="math"&gt;\([L, R]\)&lt;/span&gt;，维护的信息为 &lt;span class="math"&gt;\(S_{L,R}\)&lt;/span&gt;。我们希望维护以下&lt;strong&gt;结构不变式&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于区间加法操作：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="math"&gt;$$
  S_{L,R} = \sum_{i=L}^R A[i]
  $$&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;且满足：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="math"&gt;$$
  S_{L,R} = \text{Merge}(S_{L,M},\; S_{M+1,R})
  $$&lt;/div&gt;
&lt;h4 id="_9"&gt;懒标记设计&lt;/h4&gt;
&lt;p&gt;为保持整体结构在多次操作下仍可高效工作，引入&lt;strong&gt;延迟标记变量&lt;/strong&gt; &lt;span class="math"&gt;\(\text{lazy}_{L,R}\)&lt;/span&gt;，用于记录尚未传播的修改信息。更新操作流程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;打标记&lt;/strong&gt;（Apply）：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;当整个区间 &lt;span class="math"&gt;\([L, R]\)&lt;/span&gt; 被完全覆盖时，不递归更新子区间；&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;只需：&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
 S_{L,R} \leftarrow S_{L,R} + (R - L + 1) \cdot c
 $$&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
 \text{lazy}_{L,R} \leftarrow \text{lazy}_{L,R} + c
 $$&lt;/div&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;下推标记&lt;/strong&gt;（PushDown）：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;当访问某节点的子节点时，将标记下传至左右子区间：&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
 \text{lazy}_{L,M} \leftarrow \text{lazy}_{L,M} + \text{lazy}_{L,R}
 $$&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
 S_{L,M} \leftarrow S_{L,M} + (M - L + 1) \cdot \text{lazy}_{L,R}
 $$&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;同理处理 &lt;span class="math"&gt;\([M+1, R]\)&lt;/span&gt;，然后清除父节点标记：&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
 \text{lazy}_{L,R} \leftarrow 0
 $$&lt;/div&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此时，每个节点所维护的信息可能&lt;strong&gt;暂不符合精确值定义&lt;/strong&gt;，但满足以下&lt;strong&gt;宽松不变式&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;若未访问子区间，则本节点记录的是更新后的区间值；一旦访问子区间，将立即下推以恢复精确不变式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="_10"&gt;结构不变式对比总结&lt;/h4&gt;
&lt;table class="table table-bordered table-striped table-hover align-middle"&gt;
  &lt;thead class="table-light"&gt;
    &lt;tr&gt;
      &lt;th&gt;状态&lt;/th&gt;
      &lt;th&gt;不变式形式&lt;/th&gt;
      &lt;th&gt;是否立即满足&lt;/th&gt;
      &lt;th&gt;性质&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;普通节点&lt;/td&gt;
      &lt;td&gt;\( S_{L,R} = \text{Merge}(S_{L,M}, S_{M+1,R}) \)&lt;/td&gt;
      &lt;td&gt;是&lt;/td&gt;
      &lt;td&gt;严格不变式&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;有懒标记&lt;/td&gt;
      &lt;td&gt;\( S_{L,R} = \text{真实值} + \delta \cdot (R - L + 1) \)&lt;/td&gt;
      &lt;td&gt;暂不满足&lt;/td&gt;
      &lt;td&gt;延迟不变式&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;下推后&lt;/td&gt;
      &lt;td&gt;子节点恢复准确值&lt;/td&gt;
      &lt;td&gt;恢复&lt;/td&gt;
      &lt;td&gt;最终仍满足整体一致性&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;如需支持更多操作（如区间赋值、区间最小值+修改等），只需根据操作类型调整：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;标记类型：如记录「待加数 &lt;span class="math"&gt;\(c\)&lt;/span&gt;」或「待赋值为 &lt;span class="math"&gt;\(v\)&lt;/span&gt;」；&lt;/li&gt;
&lt;li&gt;Merge 函数：如 &lt;span class="math"&gt;\(\max\)&lt;/span&gt;、&lt;span class="math"&gt;\(\min\)&lt;/span&gt;、&lt;span class="math"&gt;\(\sum\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;更新函数的结合律或可交换性是否成立。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;只要操作满足&lt;strong&gt;结合律与分配律&lt;/strong&gt;，就可以稳定维护懒标记下的结构正确性。&lt;/p&gt;
&lt;h2 id="_11"&gt;例题&lt;/h2&gt;
&lt;h3 id="luogu-p3372-1"&gt;Luogu P3372 【模板】线段树 1：区间加法与求和查询&lt;/h3&gt;
&lt;p&gt;本题是线段树的经典模板题，支持两种操作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;区间加值：对区间 &lt;span class="math"&gt;\([l, r]\)&lt;/span&gt; 内的每个元素加上一个常数 &lt;span class="math"&gt;\(c\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;区间求和：查询 &lt;span class="math"&gt;\(\sum_{i=l}^r A[i]\)&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;实现要点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个节点维护当前区间 &lt;span class="math"&gt;\([L, R]\)&lt;/span&gt; 的区间和 &lt;span class="math"&gt;\(S_{L,R}\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;引入懒标记 &lt;span class="math"&gt;\(\text{lazy}_{L,R}\)&lt;/span&gt;，用于延迟传播加值操作；&lt;/li&gt;
&lt;li&gt;满足如下不变式（带标记时）：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="math"&gt;$$
  S_{L,R} = \sum_{i=L}^R A[i] + (R - L + 1) \cdot \text{lazy}_{L,R}
  $$&lt;/div&gt;
&lt;p&gt;结合懒标记机制，可将修改与查询操作均优化至 &lt;span class="math"&gt;\(O(\log n)\)&lt;/span&gt;。&lt;/p&gt;
&lt;h3 id="luogu-p1816"&gt;Luogu P1816 忠诚：静态区间最小值查询&lt;/h3&gt;
&lt;p&gt;题目要求支持多次查询：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;给定初始数组 &lt;span class="math"&gt;\(A[1 \dots m]\)&lt;/span&gt;，回答若干个区间 &lt;span class="math"&gt;\([a, b]\)&lt;/span&gt; 内的最小值 &lt;span class="math"&gt;\(\min_{i=a}^{b} A[i]\)&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;实现要点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个节点维护对应区间的最小值 &lt;span class="math"&gt;\(M_{L,R} = \min_{i=L}^{R} A[i]\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;不涉及任何更新操作，结构在初始化后保持不变；&lt;/li&gt;
&lt;li&gt;查询过程仅需递归访问覆盖区间，合并左右子树最小值即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;由于为静态查询问题，可选用 ST 表（稀疏表）进行预处理，查询时间降至 &lt;span class="math"&gt;\(O(1)\)&lt;/span&gt;，此处不再展开。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="luogu-p1558"&gt;Luogu P1558 色板游戏：区间赋值与状态统计&lt;/h3&gt;
&lt;p&gt;本题是典型的“染色问题”，操作包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将区间 &lt;span class="math"&gt;\([l, r]\)&lt;/span&gt; 染为颜色 &lt;span class="math"&gt;\(c\)&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;查询区间 &lt;span class="math"&gt;\([l, r]\)&lt;/span&gt; 中&lt;strong&gt;不同颜色的种类数&lt;/strong&gt;（颜色数 ≤ 30）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;实现要点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个节点维护区间颜色集合 &lt;span class="math"&gt;\(C_{L,R}\)&lt;/span&gt;，使用 30 位整数位运算记录状态（例如第 &lt;span class="math"&gt;\(k\)&lt;/span&gt; 位为 1 表示颜色 &lt;span class="math"&gt;\(k\)&lt;/span&gt; 存在）；&lt;/li&gt;
&lt;li&gt;支持区间赋值，需使用懒标记 &lt;span class="math"&gt;\(T_{L,R}\)&lt;/span&gt; 表示待覆盖的颜色值；&lt;/li&gt;
&lt;li&gt;不变式表达为：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="math"&gt;$$
  C_{L,R} = 
  \begin{cases}
    \text{bitmask of color } c &amp;amp; \text{若整段染色为 } c \\
    C_{L,M} \,|\, C_{M+1,R} &amp;amp; \text{否则}
  \end{cases}
  $$&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;查询通过统计 &lt;span class="math"&gt;\(C_{L,R}\)&lt;/span&gt; 中二进制 1 的个数来获取颜色数。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_12"&gt;小结&lt;/h2&gt;
&lt;p&gt;线段树的设计之所以高效，是因为它通过&lt;strong&gt;递归划分 + 不变式维护&lt;/strong&gt;，使得复杂的区间操作能够以对数级别的时间完成。&lt;/p&gt;
&lt;p&gt;本文从不变式角度出发，分析了线段树的构造与操作逻辑。与常见的图解类教程相比，这种方法更强调原理和形式化思维，适合希望进一步深入理解线段树本质的读者。&lt;/p&gt;
&lt;h2 id="_13"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://algo.itcharge.cn/07.Tree/03.Segment-Tree/01.Segment-Tree/"&gt;算法通关手册（LeetCode）- 线段树知识&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.luogu.com.cn/training/206"&gt;题单 - 线段树&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Blog"/><category term="算法"/><category term="线段树"/><category term="algorithm"/><category term="segment-tree"/></entry><entry><title>为什么我不建议你阅读《数据密集型应用系统设计》（之四）</title><link href="https://wizmann.top/why-not-start-with-ddia-part-4.html" rel="alternate"/><published>2025-06-11T00:00:00+08:00</published><updated>2025-06-11T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-06-11:/why-not-start-with-ddia-part-4.html</id><summary type="html">&lt;p&gt;分布式系统中有太多可能出错的场景，而系统几乎不可能“停下来检修”。这意味着，我们必须构建更加&lt;strong&gt;容错&lt;/strong&gt;的基础架构。&lt;/p&gt;
&lt;p&gt;为此 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;分布式系统中有太多可能出错的场景，而系统几乎不可能“停下来检修”。这意味着，我们必须构建更加&lt;strong&gt;容错&lt;/strong&gt;的基础架构。&lt;/p&gt;
&lt;p&gt;为此，我们需要在&lt;strong&gt;系统底层建立抽象和相应的技术保证&lt;/strong&gt;，使得上层的应用程序可以安全、稳定地依赖这些机制，无需重新实现一套复杂的机制。&lt;/p&gt;
&lt;h2 id="_1"&gt;一致性保证&lt;/h2&gt;
&lt;p&gt;在分布式系统中，一致性是一个复杂且微妙的问题。不同的业务场景，对一致性的需求不尽相同，而所能容忍的成本与代价也各异。&lt;/p&gt;
&lt;p&gt;在之前的文章中，我们探讨了&lt;strong&gt;最终一致性（Eventual Consistency）&lt;/strong&gt;这一模型。它是众多一致性模型中最宽松的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果我们停止写入系统，并等待足够长的时间（这个时间无法事先确定），最终系统中所有副本将趋于一致。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最终一致性强调的是“&lt;strong&gt;收敛性&lt;/strong&gt;”，即系统会&lt;strong&gt;最终&lt;/strong&gt;走向一致，但不保证&lt;strong&gt;当前时刻&lt;/strong&gt;的一致。&lt;/p&gt;
&lt;p&gt;之所以无法保证当前一致，是因为&lt;strong&gt;复制滞后&lt;/strong&gt;——在副本间传播写入时，网络延迟和系统异步执行都会导致各节点状态暂时不一致。而这种“暂时不一致”，并非 bug，而是架构选择。&lt;/p&gt;
&lt;p&gt;最终一致性的系统往往隐藏了更多的分布式状态和复杂边界。它不能提供类似单线程内存模型中“变量读写”的那种直观抽象，导致&lt;strong&gt;调试困难、测试成本高&lt;/strong&gt;，尤其在系统负载加剧时，容易触发一些罕见但致命的临界条件。&lt;/p&gt;
&lt;p&gt;所以，对于只提供弱一致性的数据库，开发者必须认清它的&lt;strong&gt;边界与局限&lt;/strong&gt;，不能盲目乐观。&lt;/p&gt;
&lt;p&gt;而为了解决一致性带来的混乱，分布式系统提供了一系列“协调副本状态”的抽象，比如我们接下来要讲的线性化、因果一致性、时间戳排序、全序广播等。&lt;/p&gt;
&lt;h2 id="_2"&gt;可线性化 —— 最强一致性模型&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;线性化（Linearizability）&lt;/strong&gt;，也常被称为&lt;strong&gt;强一致性&lt;/strong&gt;，是最容易被开发者理解的一致性模型：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;每一个读写操作，都可以被看作在某个全局时间点原子地生效，并且整个系统的行为符合这种时间顺序。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这意味着，从用户视角看，系统就像单线程执行的一样——&lt;strong&gt;操作是顺序的、有先后因果的，而且结果即时可见&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="_3"&gt;可线性化的依赖条件&lt;/h3&gt;
&lt;p&gt;要满足线性化，系统通常需要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;所有读操作都返回&lt;strong&gt;最近一次写入的数据&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;不同节点对操作顺序具有&lt;strong&gt;一致感知&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;有一个隐含的“&lt;strong&gt;全局时钟&lt;/strong&gt;”或其等价机制&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;显然，这并不容易。它需要精密的同步机制和&lt;strong&gt;分布式共识协议&lt;/strong&gt;来支撑。&lt;/p&gt;
&lt;h3 id="_4"&gt;线性化的代价&lt;/h3&gt;
&lt;p&gt;线性化虽然语义简单、抽象强大，但它在工程实现上代价极高：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通常依赖&lt;strong&gt;主节点选举&lt;/strong&gt;和日志复制&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络延迟&lt;/strong&gt;成为性能瓶颈&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可扩展性受限&lt;/strong&gt;（横向扩展能力弱）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;容错能力下降&lt;/strong&gt;，尤其在出现网络分区时表现脆弱&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就引出了著名的 &lt;strong&gt;CAP 定理&lt;/strong&gt;：一个分布式系统不可能同时满足&lt;strong&gt;一致性（Consistency）&lt;/strong&gt;、&lt;strong&gt;可用性（Availability）&lt;/strong&gt;和&lt;strong&gt;分区容忍性（Partition tolerance）&lt;/strong&gt;。线性化牺牲的是&lt;strong&gt;可用性&lt;/strong&gt;，以保证在发生分区时仍维持一致性。&lt;/p&gt;
&lt;h2 id="causal-consistency"&gt;因果一致性（Causal Consistency）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;因果一致性&lt;/strong&gt;是介于最终一致性与线性化之间的一种“中等强度”的模型。&lt;/p&gt;
&lt;p&gt;它的核心思想是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果操作 A 可能影响了操作 B，那么系统必须保证：任何观察到 B 的节点，也必然先观察到 A。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如，在社交平台中，Alice 发了一条状态，Bob 回复了她。这时，任何用户必须先看到 Alice 的状态，才可能看到 Bob 的评论。&lt;/p&gt;
&lt;p&gt;要实现因果一致性，系统必须追踪操作之间的因果链条。典型做法包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;向量时钟（Vector Clocks）&lt;/li&gt;
&lt;li&gt;会话上下文（Session Context）&lt;/li&gt;
&lt;li&gt;客户端因果链追踪（如 CRDT）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;相较于线性化，因果一致性在性能上更友好，但在编程模型上要求更高的注意力。&lt;/p&gt;
&lt;h2 id="_5"&gt;序列号或时间戳排序&lt;/h2&gt;
&lt;p&gt;为了协调副本之间的写入冲突，系统通常会给写操作分配一个&lt;strong&gt;逻辑时间戳&lt;/strong&gt;，常用的包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lamport 时间戳&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;递增序列号&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;物理/混合时钟&lt;/strong&gt;（如 Google&amp;rsquo;s TrueTime）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些机制的目标是为系统内所有事件建立一个“看似有序”的序列，从而为副本间的状态合并提供基础。&lt;/p&gt;
&lt;p&gt;但问题也不少：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多个节点产生相同时间戳时如何决策？&lt;/li&gt;
&lt;li&gt;如何确保时间戳在大规模集群中全局唯一？&lt;/li&gt;
&lt;li&gt;混合时钟如何处理物理时间漂移与延迟？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这类机制常用于实现因果一致性、幂等写入检测或版本冲突解决，实用但远非完美。&lt;/p&gt;
&lt;h2 id="total-order-broadcast"&gt;全序关系广播（Total Order Broadcast）&lt;/h2&gt;
&lt;p&gt;全序广播的核心目标是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;所有节点对一组消息的接收顺序必须一致。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这就像是让所有节点“看到”相同的操作日志顺序，确保系统状态演化路径一致。这对如下场景至关重要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分布式事务日志（如 Kafka、Paxos Log）&lt;/li&gt;
&lt;li&gt;数据库复制与回放&lt;/li&gt;
&lt;li&gt;状态机复制（如 Raft）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;全序广播通常需要依赖共识算法来保证顺序的一致性，因此它和一致性协议的关系非常密切。你可以将其看作是共识协议的一种应用层实现形式。&lt;/p&gt;
&lt;h2 id="consensus"&gt;分布式共识（Consensus）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;分布式共识&lt;/strong&gt;是分布式系统的核心。它的目标是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;即便在节点宕机、网络延迟、消息丢失等非理想环境中，仍然能保证一组节点就某个“唯一值”达成一致。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;常见的应用包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;主节点选举&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复制日志的一致提交&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置与元数据协调&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_6"&gt;支持容错的共识算法&lt;/h3&gt;
&lt;p&gt;目前主流的共识协议包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Paxos&lt;/strong&gt;：学术上最完整，工程上最复杂&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Raft&lt;/strong&gt;：简化版 Paxos，利于实现和理解&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zab&lt;/strong&gt;：ZooKeeper 中使用的专用协议&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它们的基本流程类似：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;各节点发起提案，包含提议值和 epoch id，其他节点进行投票。当某个提案获得多数票后，该值即被“决定”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这像一个“比大小”的游戏，epoch 越新越有可能胜出，直到系统收敛。&lt;/p&gt;
&lt;p&gt;不过必须注意：&lt;strong&gt;共识协议是为容错设计的，但并不意味着可以无视网络分区和性能代价&lt;/strong&gt;。CAP 定理再次提醒我们：一致性始终是有代价的。&lt;/p&gt;
&lt;h3 id="_7"&gt;成员与协调服务&lt;/h3&gt;
&lt;p&gt;由于共识协议实现复杂，很多系统选择将其“外包”给专门的协调服务，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ZooKeeper&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;etcd&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consul&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些服务本质上就是“稳定的共识引擎”，上层系统可以通过它们来实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分布式锁&lt;/li&gt;
&lt;li&gt;主节点选举&lt;/li&gt;
&lt;li&gt;元数据同步&lt;/li&gt;
&lt;li&gt;系统配置管理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样做的好处是：将一致性问题封装起来，提高系统的可维护性和模块边界清晰度。&lt;/p&gt;
&lt;h2 id="_8"&gt;总结&lt;/h2&gt;
&lt;p&gt;分布式系统的本质，是在&lt;strong&gt;不确定性中构造确定性&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;从最终一致性到线性化，从因果一致性到共识算法，它们本质上都是为了解决两个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多个副本之间的&lt;strong&gt;状态同步&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;在出现错误时&lt;strong&gt;如何容错恢复&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些模型和协议提供了理解系统行为的理论基础，但也往往隐藏了巨大的实现成本与工程权衡。&lt;/p&gt;
&lt;p&gt;《数据密集型应用系统设计》这本书内容详实、系统全面，但我不推荐所有人都去读它。你可以把它当作一本&lt;strong&gt;“术语手册”&lt;/strong&gt;来看，用来厘清概念和搭建知识图谱。而理论与工程实践之间的 gap，往往需要更微观、更贴近落地的视角去补足。&lt;/p&gt;
&lt;p&gt;这是本系列的最后一篇。在撰写过程中，我有意识地对原书的内容做了裁剪和重组，目的是为了让读者更快理解背后的核心思想，而不是陷入细节。&lt;/p&gt;
&lt;p&gt;感谢你的阅读，我们下一个话题见。&lt;/p&gt;</content><category term="Blog"/><category term="数据库"/><category term="数据系统"/><category term="分布式系统"/><category term="一致性协议"/><category term="分布式共识"/></entry><entry><title>Abel 求和公式在算法竞赛中的应用</title><link href="https://wizmann.top/abel-sum-dp-optimization.html" rel="alternate"/><published>2025-06-02T00:00:00+08:00</published><updated>2025-06-02T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-06-02:/abel-sum-dp-optimization.html</id><summary type="html">&lt;h2 id="leetcode-3500-minimum-cost-to-divide-array-into-subarrays"&gt;Leetcode 3500. Minimum Cost to Divide Array Into Subarrays&lt;/h2&gt;
&lt;p&gt;链接：&lt;a href="https://leetcode.com/problems/minimum-cost-to-divide-array-into-subarrays/description/"&gt;英文&lt;/a&gt; | &lt;a href="https://leetcode.cn/problems/minimum-cost-to-divide-array-into-subarrays/description/"&gt;中文&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="_1"&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定两个等长数组 &lt;code&gt;nums&lt;/code&gt; 和 &lt;code&gt;cost&lt;/code&gt;，以及一个整数 &lt;code&gt;k&lt;/code&gt;，你可以将 &lt;code&gt;nums&lt;/code&gt; 分割成若干个&lt;strong&gt;非空 …&lt;/strong&gt;&lt;/p&gt;</summary><content type="html">&lt;h2 id="leetcode-3500-minimum-cost-to-divide-array-into-subarrays"&gt;Leetcode 3500. Minimum Cost to Divide Array Into Subarrays&lt;/h2&gt;
&lt;p&gt;链接：&lt;a href="https://leetcode.com/problems/minimum-cost-to-divide-array-into-subarrays/description/"&gt;英文&lt;/a&gt; | &lt;a href="https://leetcode.cn/problems/minimum-cost-to-divide-array-into-subarrays/description/"&gt;中文&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="_1"&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定两个等长数组 &lt;code&gt;nums&lt;/code&gt; 和 &lt;code&gt;cost&lt;/code&gt;，以及一个整数 &lt;code&gt;k&lt;/code&gt;，你可以将 &lt;code&gt;nums&lt;/code&gt; 分割成若干个&lt;strong&gt;非空连续子数组&lt;/strong&gt;。第 &lt;code&gt;i&lt;/code&gt; 段子数组（编号从 1 开始）为 &lt;code&gt;nums[l..r]&lt;/code&gt;，其代价计算方式如下：&lt;/p&gt;
&lt;div class="math"&gt;$$
f(l, r, i) = \left( \sum_{j=0}^r \text{nums}[j] + k \cdot i \right) \cdot \left( \sum_{j=l}^r \text{cost}[j] \right)
$$&lt;/div&gt;
&lt;p&gt;目标是通过某种划分方式，使得总代价最小。&lt;/p&gt;
&lt;h3 id="_2"&gt;约束条件&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(1 \leq n \leq 1000\)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(1 \leq nums[i], cost[i], k \leq 1000\)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="dp"&gt;直观的解法：三重循环暴力 DP&lt;/h2&gt;
&lt;p&gt;我们定义状态：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dp[i][j]&lt;/code&gt; 表示前 &lt;code&gt;j&lt;/code&gt; 个元素分成 &lt;code&gt;i&lt;/code&gt; 段的最小总代价。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;转移方程为：&lt;/p&gt;
&lt;div class="math"&gt;$$
dp[i][r] = \min_{l &amp;lt; r} \left\{ dp[i-1][l] + f(l+1, r, i) \right\}
$$&lt;/div&gt;
&lt;p&gt;即使使用前缀和将单次 &lt;span class="math"&gt;\(f(l+1, r, i)\)&lt;/span&gt; 的计算复杂度优化到 &lt;span class="math"&gt;\(O(1)\)&lt;/span&gt;，每次仍需枚举 &lt;span class="math"&gt;\(n\)&lt;/span&gt; 次转移，总体时间复杂度仍为 &lt;span class="math"&gt;\(O(n^3)\)&lt;/span&gt;，无法通过本题。&lt;/p&gt;
&lt;h2 id="abel"&gt;Abel 求和公式优化&lt;/h2&gt;
&lt;h3 id="abel_1"&gt;Abel 求和公式简介&lt;/h3&gt;
&lt;p&gt;Abel 求和公式是一种优化形如 &lt;span class="math"&gt;\(\sum a_i b_i\)&lt;/span&gt; 的乘积和的技巧，适用于以下场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(a_i\)&lt;/span&gt; 是单调或线性变化&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(b_i\)&lt;/span&gt; 可以预处理为前缀和&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;当然，根据交换率，&lt;span class="math"&gt;\(a_i\)&lt;/span&gt; 和 &lt;span class="math"&gt;\(b_i\)&lt;/span&gt; 可以互换&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;公式如下：&lt;/p&gt;
&lt;div class="math"&gt;$$
\sum_{i=1}^n a_i b_i = B_n a_n - \sum_{k=1}^{n-1}B_k(a_{k + 1} - a_{k})
$$&lt;/div&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(B_i = \sum_{j=1}^i a_j\)&lt;/span&gt;，是从 &lt;span class="math"&gt;\(b_1\)&lt;/span&gt; 开始的前缀和；&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(B_{0} = 0\)&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_3"&gt;几何意义与解释&lt;/h3&gt;
&lt;p&gt;可以将 &lt;span class="math"&gt;\(\sum a_i b_i\)&lt;/span&gt; 理解为“宽度为 &lt;span class="math"&gt;\(a_i\)&lt;/span&gt;，高度为 &lt;span class="math"&gt;\(b_i\)&lt;/span&gt; 的矩形”所构成的总面积。Abel 求和的思想，相当于用一套更容易累加的方式来表达这些面积之和。&lt;/p&gt;
&lt;p&gt;&lt;img alt="abel" src="https://raw.githubusercontent.com/Wizmann/wizmann.github.com/refs/heads/source/content/statistics/Abel.png"&gt;&lt;br&gt;
（图源：&lt;a href="https://easymath.org/wiki/Abel_summation_formula"&gt;Easymath-wiki&lt;/a&gt;）&lt;/p&gt;
&lt;h3 id="_4"&gt;加法形式变体（对称结构）&lt;/h3&gt;
&lt;p&gt;还有一种对称的加法表达：&lt;/p&gt;
&lt;div class="math"&gt;$$
\sum_{i=1}^n a_i b_i = \sum_{i=1}^{n} (B_{n} - B_{i - 1}) \cdot (a_{i} - a_{i - 1})
$$&lt;/div&gt;
&lt;p&gt;此时，有&lt;span class="math"&gt;\(a_0 = 0\)&lt;/span&gt;和&lt;span class="math"&gt;\(B_0 = 0\)&lt;/span&gt;。&lt;/p&gt;
&lt;h2 id="leetcode-3500"&gt;在 Leetcode 3500 中的应用&lt;/h2&gt;
&lt;p&gt;我们再看代价函数：&lt;/p&gt;
&lt;div class="math"&gt;$$
f(l, r, i) = \left( \sum_{j=0}^r \text{nums}[j] + k \cdot i \right) \cdot \left( \sum_{j=l}^r \text{cost}[j] \right)
$$&lt;/div&gt;
&lt;p&gt;将其拆为两部分：&lt;/p&gt;
&lt;h3 id="_5"&gt;与数组值相关的部分：&lt;/h3&gt;
&lt;div class="math"&gt;$$
g(l, r) = \left( \sum_{j=0}^r \text{nums}[j] \right) \cdot \left( \sum_{j=l}^r \text{cost}[j] \right)
$$&lt;/div&gt;
&lt;p&gt;用前缀和即可在 &lt;span class="math"&gt;\(O(1)\)&lt;/span&gt; 时间内得到 &lt;span class="math"&gt;\(g(l, r)\)&lt;/span&gt;。&lt;/p&gt;
&lt;h3 id="i"&gt;与子数组编号 &lt;span class="math"&gt;\(i\)&lt;/span&gt; 相关的部分：&lt;/h3&gt;
&lt;div class="math"&gt;$$
h(l, r, i) = k \cdot i \cdot \left( \sum_{j=l}^r \text{cost}[j] \right)
$$&lt;/div&gt;
&lt;p&gt;这类“线性编号 × 区间和”的结构，正是 Abel 求和思想的典型应用场景。我们可以通过Abel求和将其转化为如下形式：&lt;/p&gt;
&lt;div class="math"&gt;$$
\begin{align*}
h'(l, r, i) &amp;amp;= k * \sum_{j=1}^{r}cost[j] * ((i + 1) - i) \\
&amp;amp;= k * \sum_{j=1}^{r}cost[j]
\end{align*}
$$&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;注：&lt;span class="math"&gt;\(h'\)&lt;/span&gt;函数中计算的是&lt;code&gt;cost&lt;/code&gt;数组的后辍和。并非&lt;span class="math"&gt;\(h\)&lt;/span&gt;函数中的&lt;span class="math"&gt;\((l, r)\)&lt;/span&gt;区间和。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这样一来，&lt;span class="math"&gt;\(h'(l, r, i)\)&lt;/span&gt;只与变量&lt;span class="math"&gt;\(r\)&lt;/span&gt;相关，进而减少了DP的状态空间。&lt;/p&gt;
&lt;h2 id="_6"&gt;时间复杂度优化&lt;/h2&gt;
&lt;p&gt;通过将 &lt;span class="math"&gt;\(f(l, r, i)\)&lt;/span&gt; 拆解，并借助前缀和 + Abel 求和思想，我们将原本 &lt;span class="math"&gt;\(O(n^3)\)&lt;/span&gt; 的三重循环 DP 优化为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单次状态转移：&lt;span class="math"&gt;\(O(1)\)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;空间复杂度：&lt;span class="math"&gt;\(O(n)\)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;总体复杂度：&lt;span class="math"&gt;\(O(n^2)\)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以通过本题的数据范围限制。&lt;/p&gt;
&lt;h2 id="codeforces-1175d-array-splitting"&gt;相关问题：Codeforces 1175D - Array Splitting&lt;/h2&gt;
&lt;p&gt;题目链接：&lt;a href="https://codeforces.com/contest/1175/problem/D"&gt;Codeforces 原题&lt;/a&gt; | &lt;a href="https://ideone.com/eMWXRL"&gt;解答代码&lt;/a&gt; | &lt;a href="https://codeforces.com/blog/entry/67484"&gt;官方题解&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="_7"&gt;题目描述&lt;/h3&gt;
&lt;p&gt;给定数组 &lt;span class="math"&gt;\(a = [a_1, ..., a_n]\)&lt;/span&gt; 和整数 &lt;span class="math"&gt;\(k\)&lt;/span&gt;，将其划分为 &lt;span class="math"&gt;\(k\)&lt;/span&gt; 个非空连续子数组，设每个子数组编号从 1 到 &lt;span class="math"&gt;\(k\)&lt;/span&gt; 递增，总代价函数为：&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{cost} = \sum_{i=1}^k Sub_{i} \cdot i
$$&lt;/div&gt;
&lt;p&gt;&lt;span class="math"&gt;\(Sub_{i}\)&lt;/span&gt; 为第&lt;span class="math"&gt;\(i\)&lt;/span&gt;个的子数组元素之和。&lt;/p&gt;
&lt;p&gt;你需要设计一种划分方式，使得总代价最大。&lt;/p&gt;
&lt;h3 id="_8"&gt;样例：&lt;/h3&gt;
&lt;p&gt;设 &lt;br&gt;
&lt;/p&gt;
&lt;div class="math"&gt;$$a = [1, -2, -3, 4, -5, 6, -7]$$&lt;/div&gt;
&lt;p&gt;若划分为三段：&lt;span class="math"&gt;\(([1, -2, -3], [4, -5], [6, -7])\)&lt;/span&gt;，代价为：&lt;/p&gt;
&lt;div class="math"&gt;$$
(1\cdot1 -2\cdot1 -3\cdot1) + (4\cdot2 -5\cdot2) + (6\cdot3 -7\cdot3) = -9
$$&lt;/div&gt;
&lt;h3 id="abel_2"&gt;Abel 求和视角分析&lt;/h3&gt;
&lt;p&gt;总代价可以计为：&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{cost} = \sum_{i=1}^k Sub_{i} \cdot i
$$&lt;/div&gt;
&lt;p&gt;即每段的区间和乘以其编号 &lt;span class="math"&gt;\(i\)&lt;/span&gt;：&lt;/p&gt;
&lt;div class="math"&gt;$$
\begin{align*}
f(l, r, i) &amp;amp;= i \cdot  Sub_{i} \\ 
&amp;amp;= i \cdot \left( \sum_{j=l}^r a_j \right)
\end{align*}
$$&lt;/div&gt;
&lt;p&gt;使用Abel求和公式，我们可以进行如下的转化：&lt;/p&gt;
&lt;div class="math"&gt;$$
f'(l, r, i) = ((i + 1) - i) * \sum_{j = l}^{n}a_j = \sum_{j = l}^{n}a_j
$$&lt;/div&gt;
&lt;p&gt;我们可以先将所有元素视为编号为 1 的一段：&lt;/p&gt;
&lt;div class="math"&gt;$$
\text{base} = \sum_{j=1}^n a_j
$$&lt;/div&gt;
&lt;p&gt;每新增一段，就意味着将某段的编号从 &lt;span class="math"&gt;\(i\)&lt;/span&gt; 提升到 &lt;span class="math"&gt;\(i+1\)&lt;/span&gt;，对应的提升值就是“该段和 × 增量编号”。&lt;/p&gt;
&lt;p&gt;因此，我们只需选择 &lt;span class="math"&gt;\(k-1\)&lt;/span&gt; 个切割点，使得&lt;strong&gt;后缀和最大的 &lt;span class="math"&gt;\(k-1\)&lt;/span&gt; 段被额外计入一次&lt;/strong&gt;，即可达到最大化目标。&lt;/p&gt;
&lt;h3 id="_9"&gt;实现步骤：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;枚举每个位置的后缀和（不含第一个）；&lt;/li&gt;
&lt;li&gt;取最大的 &lt;span class="math"&gt;\(k-1\)&lt;/span&gt; 个后缀和；&lt;/li&gt;
&lt;li&gt;答案为整段和 + 它们之和。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="_10"&gt;小结&lt;/h2&gt;
&lt;p&gt;Abel 求和是一种处理“数列乘编号”类结构的经典技巧，虽然起源于数学，但在很多竞赛问题中都能找到它的影子。特别是在涉及“编号 × 权重”、“位置 × 值”这种结构时，它常常提供一种结构性的优化方式。&lt;/p&gt;
&lt;p&gt;在 Leetcode 3500 中，它帮助我们把三重循环的 DP 优化为 &lt;span class="math"&gt;\(O(n^2)\)&lt;/span&gt;；在 CF1175D 中，它转化为一个“最大权重选取”问题。虽然应用方式不同，但核心思想是一样的。&lt;/p&gt;
&lt;h2 id="_11"&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://easymath.org/wiki/Abel_summation_formula"&gt;Easymath Wiki: Abel 求和公式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/problems/minimum-cost-to-divide-array-into-subarrays/description/"&gt;Leetcode 3500&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codeforces.com/contest/1175/problem/D"&gt;Codeforces 1175D&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Blog"/><category term="math"/><category term="leetcode"/><category term="codeforces"/><category term="algorithm"/><category term="dp"/></entry><entry><title>为什么我不建议你阅读《数据密集型应用系统设计》（之三）</title><link href="https://wizmann.top/why-not-start-with-ddia-part-3.html" rel="alternate"/><published>2025-06-01T00:00:00+08:00</published><updated>2025-06-01T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-06-01:/why-not-start-with-ddia-part-3.html</id><summary type="html">&lt;h2 id="_1"&gt;分布式存储系统的常见挑战&lt;/h2&gt;
&lt;h3 id="_2"&gt;“不可靠”的数据复制&lt;/h3&gt;
&lt;p&gt;在上一篇文章中，我们讨论了数据的复制机制。在理想情况下，副本间的数 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;分布式存储系统的常见挑战&lt;/h2&gt;
&lt;h3 id="_2"&gt;“不可靠”的数据复制&lt;/h3&gt;
&lt;p&gt;在上一篇文章中，我们讨论了数据的复制机制。在理想情况下，副本间的数据同步通常能在毫秒级内完成（跨地域时可能达到百毫秒级）。但实际环境远不总是理想的。由于网络抖动、链路中断、节点重启等因素，数据复制在某些情况下会出现&lt;strong&gt;秒级甚至分钟级的延迟&lt;/strong&gt;；如果遇到节点长时间下线，更可能出现&lt;strong&gt;数据副本严重不一致&lt;/strong&gt;的情况。&lt;/p&gt;
&lt;p&gt;这对复制协议提出了巨大的挑战：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果采用&lt;strong&gt;同步复制协议&lt;/strong&gt;，即每条写入都要求所有副本成功确认后才能返回成功，那么只要有一个副本故障或延迟，整个写入流程就会&lt;strong&gt;阻塞&lt;/strong&gt;，严重影响系统可用性；&lt;/li&gt;
&lt;li&gt;如果采用&lt;strong&gt;异步复制协议&lt;/strong&gt;，虽然可以提升可用性和写入吞吐量，但容易出现副本间状态不一致的情况。一些“快副本”已经处理完最新写入，而“慢副本”可能仍滞留在较旧的版本，导致相同的读请求在不同副本上返回不同结果，这种行为是&lt;strong&gt;反直觉&lt;/strong&gt;的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这类副本不一致的问题，通常需要借助 &lt;strong&gt;版本号&lt;/strong&gt;、&lt;strong&gt;向量时钟&lt;/strong&gt;、或者&lt;strong&gt;合并策略&lt;/strong&gt;来解决。但在用户可见的数据上，这类差异往往会被感知为“数据不稳定”或“系统不可靠”，尤其在多地部署、跨区域访问的系统中尤为显著。&lt;/p&gt;
&lt;h3 id="_3"&gt;“不可靠”的时钟&lt;/h3&gt;
&lt;p&gt;在分布式系统中，时钟同步是一个长期未解的“老问题”。这是因为每台机器的硬件时钟本身就存在漂移，而借助网络同步协议（如 NTP）也会不可避免地引入&lt;strong&gt;延迟抖动与误差上限&lt;/strong&gt;。虽然可以通过部署 GPS、原子钟等硬件来获取更高精度的时钟，但这会显著提高运维成本，也并不适用于所有场景。&lt;/p&gt;
&lt;p&gt;时间不可靠，会直接影响到基于时间戳的操作决策 —— 比如选择最新版本的数据、判断操作先后顺序、设定超时等。&lt;/p&gt;
&lt;p&gt;为了绕开对物理时间的强依赖，分布式系统通常会引入以下两种方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;单调逻辑时钟（如 Lamport Clock）&lt;/strong&gt;：不依赖真实时间，仅保证“事件先后”的单调性，即后来的事件时间戳总大于前一个。这在因果性判断中非常有用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;混合时钟（如 Hybrid Logical Clock）&lt;/strong&gt;：结合物理时间和逻辑时钟，在尽量保留实际时间语义的同时，兼顾可比性和单调性，是一些新型分布式数据库（如 CockroachDB）所采用的策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，也有像 Google Spanner 那样的系统使用了更激进的手段 —— 它基于 GPS 和原子钟构建了一个全局“置信时钟窗口”（TrueTime），允许系统在已知的最大时钟误差范围内进行一致性推理。这虽然代价较高，但在需要&lt;strong&gt;严格全球一致性&lt;/strong&gt;的场景中是当前最实用的路径之一。&lt;/p&gt;
&lt;h2 id="_4"&gt;分布式事务&lt;/h2&gt;
&lt;p&gt;在分布式数据系统中，最典型的应用场景是键值存储。对于这类系统，&lt;strong&gt;单次读写往往就是一个完整的业务操作&lt;/strong&gt;。系统的可靠性此时主要依赖副本机制来保障：在多数情况下，只要数据成功写入任意副本（或写入达成多数派确认），系统即可对外返回成功，后续的副本同步则交由后台异步处理。&lt;/p&gt;
&lt;p&gt;然而，随着业务复杂性提升，单点读写已不足以覆盖所有逻辑。此时，我们需要将多个相关的读写操作&lt;strong&gt;打包为一个原子性的操作单元&lt;/strong&gt; —— 这正是&lt;strong&gt;事务&lt;/strong&gt;产生的背景。&lt;/p&gt;
&lt;p&gt;事务的核心目标非常明确：&lt;strong&gt;要么全部成功，要么全部失败&lt;/strong&gt;。这大大降低了开发者的心智负担 —— 无需再为中间状态的异常处理编写大量补偿逻辑，系统也能避免因“部分提交”造成的数据污染。&lt;/p&gt;
&lt;h3 id="acid-base"&gt;分布式事务的 ACID 与 BASE&lt;/h3&gt;
&lt;p&gt;传统数据库中的事务遵循 ACID 原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A（Atomicity，原子性）&lt;/strong&gt;：事务中的所有操作必须全部完成，或全部不做；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C（Consistency，一致性）&lt;/strong&gt;：事务完成后，系统从一个一致状态转变到另一个一致状态；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I（Isolation，隔离性）&lt;/strong&gt;：并发执行的事务互不干扰；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D（Durability，持久性）&lt;/strong&gt;：一旦提交的数据不能丢失，即使系统崩溃。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然而在分布式环境下，严格遵守 ACID 通常意味着高延迟、复杂的锁管理，以及对网络中断的极度敏感。在追求高可用、横向扩展、低延迟的背景下，许多系统转而采用更宽松的 BASE 理论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Basically Available（基本可用）&lt;/strong&gt;：系统即使出现故障，也尽量保持部分功能可用；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Soft State（软状态）&lt;/strong&gt;：系统状态在一段时间内允许不一致；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Eventual Consistency（最终一致性）&lt;/strong&gt;：只要不发生新的更新，所有副本最终会趋于一致。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;BASE 并不是 ACID 的“反面”，而是为了解决分布式条件下“网络不可靠”“节点不可用”“复制延迟”等问题所做的一种实用妥协。&lt;strong&gt;ACID 更强调一致性和正确性，BASE 更强调可用性和恢复能力。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="_5"&gt;事务隔离级别：性能与一致性的权衡&lt;/h3&gt;
&lt;p&gt;在支持事务的分布式系统中，另一个核心挑战是如何处理并发读写引发的数据冲突。这决定了系统提供的&lt;strong&gt;隔离级别（Isolation Level）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;理想状态下，我们希望事务之间完全串行执行 —— 没有任何交叉。但这会带来严重的性能瓶颈。因此系统通常设计多个隔离等级，提供不同程度的并发控制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;读已提交（Read Committed）&lt;/strong&gt;&lt;br&gt;
  每个事务只能读取到其他事务“已提交”的数据。这避免了脏读，但仍可能出现“不可重复读”（同一条记录先后读取结果不同）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;快照隔离（Snapshot Isolation）&lt;/strong&gt;&lt;br&gt;
  每个事务在开始时看到的是数据库的某一时刻快照。虽然可避免脏读和不可重复读，但无法防止 &lt;strong&gt;写倾斜（Write Skew）&lt;/strong&gt; —— 多个事务读取相同状态后独立写入，结果违反了业务约束。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可重复读（Repeatable Read）&lt;/strong&gt;&lt;br&gt;
  每次读取相同记录得到的值不变，但对于范围查询仍可能遇到 &lt;strong&gt;幻读（Phantom Read）&lt;/strong&gt; —— 第二次查询返回了新插入或删除的行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;串行化（Serializable）&lt;/strong&gt;&lt;br&gt;
  最强隔离等级，要求事务执行效果等同于串行执行。能彻底消除幻读、写倾斜等问题，但开销也最大。常见实现方式有：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;基于锁的两阶段锁协议（2PL），强制事务在获取锁后完成或回滚；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;基于版本控制和冲突检测的 SSI（Serializable Snapshot Isolation），通过检测事务之间的读写依赖关系，在提交时回滚冲突事务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这一系列隔离等级背后，其实是&lt;strong&gt;一致性、并发性与可用性三者之间的动态权衡&lt;/strong&gt;。系统必须根据业务特点和性能要求，选取合适的隔离级别。&lt;/p&gt;
&lt;h2 id="_6"&gt;小结&lt;/h2&gt;
&lt;p&gt;分布式存储系统并不只是“多放几份数据”这么简单。它必须在&lt;strong&gt;不可靠的网络、失效的节点、漂移的时钟和冲突的写入&lt;/strong&gt;之间，构建起一个对用户“看起来稳定可靠”的系统。而这背后，是副本同步机制、时钟模型、事务协议与一致性等级等一系列工程权衡与设计抉择。&lt;/p&gt;
&lt;p&gt;我们无法一劳永逸地解决所有问题，只能根据具体场景选择合适的折中方案。正如你所看到的：CAP 不可兼得，ACID 与 BASE 各有利弊，串行化隔离并非银弹 —— 分布式系统的设计，从来都是一场关于“权衡”的艺术。&lt;/p&gt;
&lt;p&gt;在接下来的文章中，我们将继续探索分布式系统中的一致性定义和常见一致性模型的适用场景 —— 如果有下一篇的话。&lt;/p&gt;</content><category term="Blog"/><category term="数据库"/><category term="数据系统"/><category term="分布式系统"/><category term="分布式事务"/></entry><entry><title>可控扩容与扩展中国剩余定理 ：NoSQL 分区实践</title><link href="https://wizmann.top/controlled-partition-scaling-with-excrt.html" rel="alternate"/><published>2025-05-28T00:00:00+08:00</published><updated>2025-05-28T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-05-28:/controlled-partition-scaling-with-excrt.html</id><summary type="html">&lt;p&gt;在现代分布式数据库中，&lt;strong&gt;Hash 分区（Hash-based Partitioning）&lt;/strong&gt; 是最常用的数据分布策略之一。系统通过对 key 取 hash，再对分区数 &lt;code&gt;N&lt;/code&gt; 取模，将数据路由到 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;在现代分布式数据库中，&lt;strong&gt;Hash 分区（Hash-based Partitioning）&lt;/strong&gt; 是最常用的数据分布策略之一。系统通过对 key 取 hash，再对分区数 &lt;code&gt;N&lt;/code&gt; 取模，将数据路由到对应分区。&lt;/p&gt;
&lt;p&gt;当业务增长带来存储与吞吐瓶颈时，系统需要 &lt;strong&gt;扩容&lt;/strong&gt; —— 将原来的 &lt;code&gt;N&lt;/code&gt; 个分区扩展为更多的 &lt;code&gt;M&lt;/code&gt; 个分区。但这个过程并非总是轻松，特别是当 &lt;code&gt;N&lt;/code&gt; 与 &lt;code&gt;M&lt;/code&gt; 无明显倍数关系时，数据迁移可能代价巨大。&lt;/p&gt;
&lt;p&gt;本文提出一种数学结构驱动的新思路：&lt;strong&gt;通过构造满足一定约束的 N→M 映射，并借助扩展中国剩余定理（Extended Chinese Remainder Theorem, ExCRT），实现更可控的数据迁移方案&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="n-2n-3n"&gt;常规扩容：N → 2N 或 3N 的便利与局限&lt;/h2&gt;
&lt;p&gt;在实际工程中，最常见的扩容方式是将分区数从 &lt;code&gt;N&lt;/code&gt; 扩展为 &lt;code&gt;2N&lt;/code&gt;、&lt;code&gt;3N&lt;/code&gt; 等倍数。这种方式之所以流行，是因为它具备天然的结构优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;映射关系明确&lt;/strong&gt;：每个原始分区的数据可以均匀地映射到固定数量的新分区；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实现简洁&lt;/strong&gt;：只需在 hash 值的基础上调整模数，或者通过位移和除法即可建立新旧分区的映射；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;迁移可控&lt;/strong&gt;：通常只需部分数据迁移，许多 key 会继续留在原本映射到的区域附近。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如，从 &lt;code&gt;N = 8&lt;/code&gt; 扩容到 &lt;code&gt;M = 16&lt;/code&gt; 时，典型映射如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;new_partition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;
&lt;span class="n"&gt;old_partition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_partition&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;原分区 &lt;code&gt;0&lt;/code&gt; 中的数据只会被重新分布到新分区 &lt;code&gt;0&lt;/code&gt; 和 &lt;code&gt;1&lt;/code&gt; 中，迁移边界明确。&lt;/p&gt;
&lt;h3 id="_1"&gt;然而，倍数扩容也存在明显问题：&lt;/h3&gt;
&lt;p&gt;当 &lt;code&gt;N&lt;/code&gt; 本身已经非常大（如数百或数千分区）时，倍数扩容意味着将系统容量翻倍甚至三倍，这往往会带来 &lt;strong&gt;资源浪费&lt;/strong&gt; 和 &lt;strong&gt;分布不均衡&lt;/strong&gt; 的风险。与此同时，&lt;strong&gt;维护成本和状态空间也会成倍上升&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这引出一个更具挑战性的问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;是否有办法将 &lt;code&gt;N&lt;/code&gt; 扩展为一个比 &lt;code&gt;2N&lt;/code&gt; 更小、但又能满足容量需求的&lt;code&gt;M&lt;/code&gt;，同时&lt;strong&gt;避免无序重分布带来的高迁移成本&lt;/strong&gt;？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="excrt"&gt;一个新思路：ExCRT 限定映射构造&lt;/h2&gt;
&lt;p&gt;如果我们将分区扩容问题抽象为一个模运算系统：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;原始分区: x ≡ a₁ (mod N)
目标分区: x ≡ a₂ (mod M)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;我们的目标是：给定原始分区编号 &lt;code&gt;a₁&lt;/code&gt;，找出所有可能的目标分区编号 &lt;code&gt;a₂&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="excrt_1"&gt;利用扩展中国剩余定理（ExCRT）&lt;/h3&gt;
&lt;p&gt;将上述两个同余方程组成一个系统：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;x ≡ a₁ (mod N)
x ≡ a₂ (mod M)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;根据 ExCRT 的结论，这个系统有解当且仅当：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;a₁ ≡ a₂ (mod d)，其中 d = gcd(N, M)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;换句话说，&lt;strong&gt;只有满足 &lt;code&gt;a₂ ≡ a₁ mod d&lt;/code&gt; 的目标分区编号是合法的。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;因此，&lt;strong&gt;对于每一个原始分区 &lt;code&gt;a₁&lt;/code&gt;，其可映射的目标分区 &lt;code&gt;a₂&lt;/code&gt; 并不是全部 M 个，而是受限于这个模 d 的条件&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="_2"&gt;举例说明：有限映射如何形成&lt;/h3&gt;
&lt;p&gt;假设我们要将分区数从 &lt;code&gt;N = 12&lt;/code&gt; 扩容到 &lt;code&gt;M = 20&lt;/code&gt;，由于：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gcd(12, 20) = 4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;我们知道，每个原始分区 &lt;code&gt;a₁ ∈ [0, 11]&lt;/code&gt; 映射到的新分区 &lt;code&gt;a₂ ∈ [0, 19]&lt;/code&gt; 必须满足同余关系：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;a₂ ≡ a₁ mod 4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;例如，对于原始分区 &lt;code&gt;a₁ = 5&lt;/code&gt;，符合条件的目标分区为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;a₂ ∈ {5, 9, 13, 17}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这意味着：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;每个原始分区最多只会映射到 &lt;code&gt;M / gcd(N, M) = 5&lt;/code&gt; 个目标分区，而不是全部 &lt;code&gt;M&lt;/code&gt; 个，极大地压缩了数据迁移空间。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面是完整的映射关系示例：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;原分区 &lt;code&gt;a₁&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;合法目标分区 &lt;code&gt;a₂ ∈ [0, 20)&lt;/code&gt; 满足 &lt;code&gt;a₂ ≡ a₁ mod 4&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;{0, 4, 8, 12, 16}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;{1, 5, 9, 13, 17}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;{2, 6, 10, 14, 18}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;{3, 7, 11, 15, 19}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;{0, 4, 8, 12, 16}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;{1, 5, 9, 13, 17}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;以此类推，每个原始分区只会映射到与自身模 &lt;code&gt;d&lt;/code&gt; 同余的一组目标分区，构成了一个&lt;strong&gt;模 d 分类的稀疏映射结构&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这就是扩展中国剩余定理在扩容中的价值所在：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;不仅使映射可解，而且使映射&lt;strong&gt;受限、有结构、可控&lt;/strong&gt;，从而有效避免全连接映射带来的大规模数据迁移。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_3"&gt;映射空间的压缩优势&lt;/h2&gt;
&lt;p&gt;更进一步地，我们可以对比两种映射方式的边数量：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;映射方式&lt;/th&gt;
&lt;th&gt;映射边数量&lt;/th&gt;
&lt;th&gt;是否全连接&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;传统全连接&lt;/td&gt;
&lt;td&gt;&lt;code&gt;N × M&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;本方法（ExCRT）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;N × (M / gcd(N, M))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;换句话说，我们将可能的连接数&lt;strong&gt;压缩了一个因子 &lt;code&gt;gcd(N, M)&lt;/code&gt;&lt;/strong&gt;，极大减小了数据重分布带来的迁移成本。&lt;/p&gt;
&lt;h2 id="_4"&gt;总结与展望&lt;/h2&gt;
&lt;p&gt;本文提出了一种结合扩展中国剩余定理的 NoSQL 分区扩容方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过控制扩容目标 &lt;code&gt;M&lt;/code&gt; 与原始分区数 &lt;code&gt;N&lt;/code&gt; 的公约数；&lt;/li&gt;
&lt;li&gt;使用 ExCRT 构造原分区号与目标分区号之间的合法映射；&lt;/li&gt;
&lt;li&gt;从数学上限定了数据迁移路径，避免无序重分布；&lt;/li&gt;
&lt;li&gt;显著减少了迁移成本和系统不稳定性。&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="nosql"/><category term="hash"/><category term="partitioning"/><category term="repartitioning"/><category term="crt"/><category term="excrt"/></entry><entry><title>为什么我不建议你阅读《数据密集型应用系统设计》（之二）</title><link href="https://wizmann.top/why-not-start-with-ddia-part-2.html" rel="alternate"/><published>2025-05-26T00:00:00+08:00</published><updated>2025-05-26T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-05-26:/why-not-start-with-ddia-part-2.html</id><summary type="html">&lt;h2 id="_1"&gt;分布式数据系统：从“加机器”说起&lt;/h2&gt;
&lt;p&gt;当单台机器再也扛不住不断增长的存储和计算需求时，我们别无选择，只能走上“加机器”的 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;分布式数据系统：从“加机器”说起&lt;/h2&gt;
&lt;p&gt;当单台机器再也扛不住不断增长的存储和计算需求时，我们别无选择，只能走上“加机器”的道路——也就是将系统横向扩展成分布式架构。&lt;/p&gt;
&lt;p&gt;此时，分布式数据系统带来了三个诱人的好处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;天然的可扩展性&lt;/strong&gt;：理论上，你能加一台机器，就能加一千台机器（尽管现实里没那么美好，但你的老板深信不疑）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内置的高可用性和容错性&lt;/strong&gt;：在足够大的规模下，硬件故障不是偶发事件，而是常态。一个合格的分布式系统，必须对单点故障有足够的冗余机制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更低的延迟潜力&lt;/strong&gt;：通过将数据节点部署在离用户更近的地理位置，分布式系统能一定程度上弥补“光速有限”的物理瓶颈。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;听起来像是“分布式万岁”。但所有的馈赠都标好了价格。&lt;/p&gt;
&lt;h3 id="_2"&gt;为什么不是所有问题都能靠“加机器”解决？&lt;/h3&gt;
&lt;p&gt;在深入分布式系统的好处之前，我们先来回头看看它试图替代的是什么。&lt;/p&gt;
&lt;p&gt;所谓&lt;strong&gt;垂直扩展&lt;/strong&gt;，是指通过提升单台机器的性能来增强系统能力。这种方式包括更换更强的 CPU、内存和硬盘，也包括构建一个大型共享资源架构——比如多台服务器连接同一个共享存储，看起来像是一台“超级计算机”。&lt;/p&gt;
&lt;p&gt;这种方式的问题在于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;扩展性有限&lt;/strong&gt;：硬件资源总有极限，单点性能的提升会遇到物理和经济上的瓶颈。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;成本非线性增长&lt;/strong&gt;：更强的机器意味着更高的成本，而性能提升往往不是线性的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;部署位置受限&lt;/strong&gt;：资源集中在单点意味着天生无法提供异地容灾能力，一旦中心节点宕机，服务将全面瘫痪。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;于是我们才开始认真考虑&lt;strong&gt;无共享架构&lt;/strong&gt;（shared-nothing architecture）——也就是我们今天所说的分布式系统。&lt;/p&gt;
&lt;p&gt;在无共享架构中，每个节点都是一台独立的物理机或虚拟机，节点之间没有共享内存或磁盘，所有的协调通信都运行在以太网之上，系统的核心能力依赖于软件层面的调度、一致性与容错机制。&lt;/p&gt;
&lt;h3 id="_3"&gt;新的机遇，还是新的复杂性？&lt;/h3&gt;
&lt;p&gt;正是这种架构，让“加机器”变得可能，也让我们走上了分布式的道路。&lt;/p&gt;
&lt;p&gt;但随之而来的，不只是能力的提升，更是复杂性的爆炸。数据如何分片？事务如何保证？一致性如何维护？服务如何容灾？这些都不再是“买个更强的服务器”就能解决的问题。&lt;/p&gt;
&lt;h2 id="_4"&gt;分布式数据系统的数据复制&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;复制&lt;/strong&gt;，即在多个节点上保存相同数据的副本，以提供冗余和容错能力。如果某些节点出现故障或临时不可用，系统可以通过其它副本节点继续提供数据访问服务，从而实现高可用性。&lt;/p&gt;
&lt;p&gt;常见的数据复制策略包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;主从复制（Leader–Follower）&lt;/strong&gt;：一个主节点负责处理所有写请求，写入变更会同步或异步地复制到一个或多个从节点。读请求可以由主节点处理，也可以转移到从节点以减轻负载。该模式实现相对简单，是很多关系型数据库（如 MySQL）的默认复制机制。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;无主复制（Peer-to-Peer）&lt;/strong&gt;：所有节点地位平等，均可接收读写请求。节点之间相互同步，通过冲突检测和协调机制来维持最终一致性。该模式提高了可用性，但实现复杂，且一致性保障较弱，常用于弱一致性场景，如某些 P2P 系统或协同编辑工具。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;多主复制（Multi-Leader）&lt;/strong&gt;：系统被划分为多个逻辑片区，每个片区拥有自己的主节点与若干从节点。从节点不仅从本地主节点复制数据，也会从其它片区的主节点同步数据。该方案适用于跨数据中心部署，能显著提升写入吞吐与容灾能力，但需要更复杂的冲突解决策略。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;根据写操作传播的时机不同，复制又可分为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;同步复制&lt;/strong&gt;：写操作需要在所有副本成功（或多数副本）写入后才算完成，能保证强一致性，但可能带来较高延迟和可用性损失（如少数节点宕机会影响整体写入能力）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步复制&lt;/strong&gt;：写操作只需在主节点成功即可返回，副本稍后再同步。这样延迟低、可用性高，但在主节点失败的情况下可能出现数据丢失（即复制滞后带来的数据不一致）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_5"&gt;分布式数据系统的数据分区&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;分区&lt;/strong&gt;（也称为分片，Sharding）是将一个大型数据库拆分成多个较小的子集，每个子集由不同的节点负责存储与处理，从而实现系统的横向扩展。&lt;/p&gt;
&lt;p&gt;最常见的分区方法主要包括以下几类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;哈希分区（Hash Partitioning）&lt;/strong&gt;：对主键（或其一部分）进行哈希计算，将结果映射到不同的分区。哈希的随机性有助于实现较为均衡的负载分布，是应对高并发场景的常见选择。不过，哈希分区的一个明显缺点是无法高效支持范围查询，因为相邻的数据项在物理上通常被分配到了不同的节点上。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;范围分区（Range Partitioning）&lt;/strong&gt;：根据主键值的区间范围，将数据划分到不同分区。该方式适用于时间序列数据、按业务维度有序增长的数据等场景，能很好地支持范围查询。但其缺点在于数据分布可能不均衡，易形成“热分区”或“热点节点”，从而影响系统性能。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;一致性哈希（Consistent Hashing）&lt;/strong&gt;：这是一种结合哈希与范围思想的机制，常用于动态可变的节点环境。它将整个哈希空间组织为一个环，数据和节点都映射到该环上。通过引入虚拟节点等手段，一致性哈希能够在扩容或缩容时大幅减少需要迁移的数据量，从而保持系统的稳定性与负载均衡。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="rebalancing"&gt;分区再平衡（Rebalancing）&lt;/h3&gt;
&lt;p&gt;随着系统规模变化、负载波动或节点故障，原有的分区方式可能会失衡，导致部分节点过载。因此，我们需要动态地对分区进行“再平衡”。&lt;/p&gt;
&lt;h4 id="hash"&gt;Hash 分区的扩展&lt;/h4&gt;
&lt;p&gt;在哈希分区中，扩容通常意味着增加节点数量。一个简单但代价昂贵的方法是&lt;strong&gt;重新哈希所有数据&lt;/strong&gt;，但这会导致大量数据迁移。&lt;/p&gt;
&lt;p&gt;优化的方式之一是使用&lt;strong&gt;虚拟节点（Virtual Nodes）&lt;/strong&gt;，即将哈希空间切分为更多、更小的段，每个节点负责多个段。新增节点时，只需迁移部分虚拟节点，代价更小，平衡更容易。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;FYI: &lt;a href="./controlled-partition-scaling-with-excrt.html"&gt;这篇文章&lt;/a&gt;还讨论了对于Hash分区的一种扩展方法，以避免过量的数据迁移。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="_6"&gt;范围分区的扩展&lt;/h4&gt;
&lt;p&gt;对于范围分区，扩容通常需要&lt;strong&gt;调整区间边界&lt;/strong&gt;，即将一个负载较高的区间细分成多个更小的子区间，并将其迁移到新节点。这种方案虽然易于理解，但实际操作时需谨慎处理数据迁移期间的一致性问题。&lt;/p&gt;
&lt;h4 id="_7"&gt;请求路由&lt;/h4&gt;
&lt;p&gt;随着分区数量的增加，客户端或前端服务需要具备将请求准确路由到目标分区的能力。这通常有三种策略：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;客户端路由&lt;/strong&gt;：客户端通过哈希函数或路由表直接定位目标分区，效率高但不易变更。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;中间代理层（比如 Router 或 Coordinator）&lt;/strong&gt;：系统部署专门的请求路由组件来管理和分发请求，灵活但增加了系统复杂度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;元数据服务&lt;/strong&gt;：由一个集中的元服务组件记录所有分区状态和位置，客户端或中间层可据此查询路由路径，常见于大规模系统中（如 HBase 的 Meta Table）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="_8"&gt;小结&lt;/h2&gt;
&lt;p&gt;通过上文的内容，我们已经初步了解了分布式数据系统的核心机制：系统如何通过分区实现横向扩展，如何借助复制提升可用性与容错能力，以及如何设计合理的路由机制来协调各个节点间的请求调度。&lt;/p&gt;
&lt;p&gt;这些机制构成了大多数 NoSQL 数据库的基础架构逻辑，也解释了它们为何能够支撑起大规模、高并发的业务系统。&lt;/p&gt;
&lt;p&gt;不过，真正的挑战往往不止于此。在涉及跨节点的数据一致性、事务操作、以及如何在一致性、可用性与分区容错性之间进行权衡时，系统设计将面临更复杂的决策。&lt;/p&gt;
&lt;p&gt;这也是我们在下一篇中将继续探讨的方向 —— 希望能有下一篇。&lt;/p&gt;</content><category term="Blog"/><category term="数据库"/><category term="数据系统"/><category term="分布式系统"/><category term="数据密集型应用系统"/></entry><entry><title>为什么我不建议你阅读《数据密集型应用系统设计》（之一）</title><link href="https://wizmann.top/why-not-start-with-ddia-part-1.html" rel="alternate"/><published>2025-05-17T00:00:00+08:00</published><updated>2025-05-17T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-05-17:/why-not-start-with-ddia-part-1.html</id><summary type="html">&lt;p&gt;&lt;strong&gt;因为我是标题党。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这本书与我们常用来垫显示器的《算法导论》或《深入理解计算机系统》（如果你是大一大二的同学，可能还包 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;因为我是标题党。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这本书与我们常用来垫显示器的《算法导论》或《深入理解计算机系统》（如果你是大一大二的同学，可能还包括《算法竞赛入门经典》）并不属于同一类。它更接近《C++ Primer》或那本《算法》(Robert Sedgewick 著）——属于通识型读物。&lt;/p&gt;
&lt;p&gt;换句话说，如果你尚未掌握相关基础知识，阅读这本书的学习曲线将会异常陡峭；而一旦你已经入门，它的表达方式会让你觉得十分优雅，结构也很清晰，却又可能让你觉得“说得都对，但好像也没什么新东西”。&lt;/p&gt;
&lt;p&gt;如果你是初入数据相关系统领域的新手，我更希望你先对这本书的脉络和重点有个清晰概览，剪枝信息、化繁为简，帮助你更快建立起基础认知，从而更高效地阅读这本书，而不是在术语和细节中反复迷路。&lt;/p&gt;
&lt;h2 id="_1"&gt;什么是数据密集型系统&lt;/h2&gt;
&lt;p&gt;数据密集型系统可以理解为一个结构上的“双面体”：一方面，它需要实时地处理数据的存储与检索；另一方面，它还承担着异步处理和计算已有数据的任务。这两种模式共同支撑了系统对数据的全面利用。&lt;/p&gt;
&lt;p&gt;我们之所以称其为“数据密集型”，是因为它所处理的数据具备以下三个核心特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据是不可再生的——一旦丢失，就无法重新获取，具有唯一性与不可逆性；&lt;/li&gt;
&lt;li&gt;数据是持续增长的——系统需要不断接收新数据，数据量随着时间推移呈线性，甚至指数级上升；&lt;/li&gt;
&lt;li&gt;数据的应用是不断演进的——数据的价值和使用方式会随着业务需求和技术手段的发展而变化。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;正因为如此，设计和构建数据密集型系统时，我们必须重点关注三个目标：&lt;br&gt;
* 可靠性：防止数据丢失，保障系统在故障时能够正确恢复；&lt;br&gt;
* 可扩展性：系统能够随着数据量和访问量的增加平稳扩展；&lt;br&gt;
* 可维护性：系统结构清晰、易于理解，能够适应未来不断变化的需求和环境。&lt;/p&gt;
&lt;h2 id="_2"&gt;数据模型与数据编码&lt;/h2&gt;
&lt;h3 id="_3"&gt;数据模型&lt;/h3&gt;
&lt;p&gt;数据模型是对现实世界的结构化抽象，是我们与数据系统沟通的“语言”。不同类型的数据模型基于不同的设计假设，适用于不同的场景。&lt;/p&gt;
&lt;p&gt;常见的数据模型包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;关系模型&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;典型代表：MySQL、PostgreSQL 等传统 SQL 数据库&lt;/li&gt;
&lt;li&gt;数据以“表格”的形式组织，每张表表示一种实体或关系，每行是一条记录&lt;/li&gt;
&lt;li&gt;特点：&lt;ul&gt;
&lt;li&gt;严格的结构约束（schema）&lt;/li&gt;
&lt;li&gt;支持复杂的查询语句和事务处理&lt;/li&gt;
&lt;li&gt;数据一致性强，适合结构清晰、关系复杂的场景&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;文档模型&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;典型代表：MongoDB、Redis（部分用作文档存储）等 NoSQL 系统&lt;/li&gt;
&lt;li&gt;数据以文档形式组织（通常是 JSON 或 BSON 格式），每个文档是一条记录&lt;/li&gt;
&lt;li&gt;特点：&lt;ul&gt;
&lt;li&gt;模式灵活，不强制 schema&lt;/li&gt;
&lt;li&gt;更适合嵌套结构和非结构化数据&lt;/li&gt;
&lt;li&gt;写入与扩展性能更好，适用于快速迭代和海量数据场景&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;选择何种数据模型，本质上是对业务需求和系统约束之间做出的权衡。&lt;/p&gt;
&lt;h3 id="_4"&gt;数据编码&lt;/h3&gt;
&lt;p&gt;在内存中，我们倾向于使用链表、哈希表、树等结构进行快速访问。但在持久化存储和网络传输中，我们需要将数据编码成&lt;strong&gt;紧凑且结构化的格式&lt;/strong&gt;，以提高读写效率与兼容性。&lt;/p&gt;
&lt;p&gt;好的数据编码格式需要权衡三个核心指标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;向前兼容性：新版本的系统仍能读取旧格式的数据；&lt;/li&gt;
&lt;li&gt;向后兼容性：旧版本的系统能忽略新数据中的未知字段，正常运行；&lt;/li&gt;
&lt;li&gt;效率：编码后的数据大小与 CPU 解码开销之间取得平衡。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常见的数据编码方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;语言内置格式（如 Python 的 &lt;code&gt;pickle&lt;/code&gt;、Java 的 &lt;code&gt;Serializable&lt;/code&gt;）&lt;ul&gt;
&lt;li&gt;与语言紧耦合，移植性差&lt;/li&gt;
&lt;li&gt;不支持数据结构演化&lt;/li&gt;
&lt;li&gt;编解码效率不高，不建议用于跨系统持久化或网络传输&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;文本格式（如 CSV、XML、JSON）&lt;ul&gt;
&lt;li&gt;通用、易读、调试友好&lt;/li&gt;
&lt;li&gt;几乎被所有编程语言支持&lt;/li&gt;
&lt;li&gt;存在大量冗余（如键名重复），不适合高效存储或传输&lt;/li&gt;
&lt;li&gt;不适合嵌套结构或二进制数据&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;二进制格式（如 Protobuf、Thrift、Avro）&lt;ul&gt;
&lt;li&gt;高度紧凑，支持嵌套与复杂结构&lt;/li&gt;
&lt;li&gt;支持数据演化，兼容性好&lt;/li&gt;
&lt;li&gt;编解码性能高，但不易调试（需工具查看）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在构建数据密集型系统时，&lt;strong&gt;模型与编码的选择往往影响深远，且难以随意更改&lt;/strong&gt;，务必根据业务需求慎重选择。&lt;/p&gt;
&lt;h2 id="_5"&gt;数据检索&lt;/h2&gt;
&lt;h3 id="oltp"&gt;事务处理系统（OLTP）中的索引结构&lt;/h3&gt;
&lt;p&gt;OLTP（在线事务处理）系统主要处理高并发、实时读写请求，因此对延迟极度敏感。常见的索引结构有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;哈希表：用于快速键值对检索，结构简单，性能高；&lt;/li&gt;
&lt;li&gt;LSM-Tree：多层已排序数组结构，写入快，适合写多读少场景；&lt;/li&gt;
&lt;li&gt;B-Tree：多叉平衡排序树，适合读写混合场景，是多数数据库的默认索引类型。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="olap"&gt;数据分析系统（OLAP）中的索引结构&lt;/h3&gt;
&lt;p&gt;OLAP（在线分析处理）系统用于处理大规模离线数据任务，关注的是整体吞吐而非单次请求的响应延迟。&lt;/p&gt;
&lt;h4 id="_6"&gt;事实表与列式存储&lt;/h4&gt;
&lt;p&gt;在数据仓库中，事实表记录每一条事件数据，通常有很多列来表示不同维度。虽然逻辑上按行存储，但物理上采用列式存储更为高效：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查询只需读取必要的列，I/O更少；&lt;/li&gt;
&lt;li&gt;同一列数据分布相似，压缩率更高；&lt;/li&gt;
&lt;li&gt;列式布局更利于向量化计算和并行处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_7"&gt;小结&lt;/h2&gt;
&lt;p&gt;从模型、编码到检索，数据系统的基础构成其实围绕着一个核心问题展开：我们如何高效、可靠地组织、保存与使用数据。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据模型决定了我们如何抽象现实世界中的事物与关系；&lt;/li&gt;
&lt;li&gt;数据编码决定了我们如何在系统之间传递和持久化这些抽象；&lt;/li&gt;
&lt;li&gt;数据检索结构则决定了我们如何以尽可能低的开销获得所需信息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下一篇，我们将探讨分布式日志、复制机制和一致性协议在数据系统中的角色与实践 —— 希望能有下一篇。&lt;/p&gt;</content><category term="Blog"/><category term="数据库"/><category term="数据系统"/><category term="分布式系统"/><category term="数据密集型应用系统"/><category term="数据模型"/><category term="数据编码"/><category term="索引结构"/></entry><entry><title>3D打印解压玩具 / 3D Printed Fidget Toy</title><link href="https://wizmann.top/Press-Pad-3D-Model.html" rel="alternate"/><published>2025-04-05T00:00:00+08:00</published><updated>2025-04-05T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-04-05:/Press-Pad-3D-Model.html</id><summary type="html">&lt;p&gt;这是一款我用3D打印制作的小巧解压玩具，造型为柔和的三角形，中间布满可以按压的小圆点，简单又有趣。适合在工作或学习时用来放松，也适合小 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;这是一款我用3D打印制作的小巧解压玩具，造型为柔和的三角形，中间布满可以按压的小圆点，简单又有趣。适合在工作或学习时用来放松，也适合小朋友玩耍。&lt;/p&gt;
&lt;p&gt;我使用的是PLA材料，手感偏硬。如果用TPU等柔性材料打印，可能会更接近硅胶的感觉，但我还没有实际尝试。&lt;/p&gt;
&lt;p&gt;This is a small fidget toy I designed and 3D printed. The soft triangular shape with pressable dots makes it a fun and relaxing little tool—great for work, study breaks, or as a toy for kids.&lt;/p&gt;
&lt;p&gt;I printed it using PLA, which feels firm. Flexible materials like TPU might give a more silicone-like feel, though I haven’t tested that yet.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/statistics/Press-Pad-3D-Model/Press-Pad.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/statistics/Press-Pad-3D-Model/Press-Pad-real.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/statistics/Press-Pad-3D-Model/Press-Pad.3mf"&gt;Press-Pad.3mf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/statistics/Press-Pad-3D-Model/Press-Pad.f3d"&gt;Press-Pad.f3d&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="3D printing"/></entry><entry><title>风力涡轮机 3D 模型 / Vertical Axis Wind Turbine (VAWT) 3D Model</title><link href="https://wizmann.top/Vertical-Axis-Wind-Turbine-3D-Model.html" rel="alternate"/><published>2025-04-05T00:00:00+08:00</published><updated>2025-04-05T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-04-05:/Vertical-Axis-Wind-Turbine-3D-Model.html</id><summary type="html">&lt;p&gt;这是一款垂直轴风力涡轮机（VAWT）3D模型，外观采用螺旋扭转的叶片设计，具有极强的美感和结构对称性。它不需要支撑结构，方便 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;这是一款垂直轴风力涡轮机（VAWT）3D模型，外观采用螺旋扭转的叶片设计，具有极强的美感和结构对称性。它不需要支撑结构，方便3D打印，同时底部设计了一个标准的608轴承接口，用于展示旋转效果。需要注意的是，它并非真正的风力驱动设备，仅为一个展示用模型。&lt;/p&gt;
&lt;p&gt;本模型使用 Fusion 360 软件建模，并附带 .f3d（Fusion 360 原始文件） 和 .3mf（适用于多数切片软件的格式），方便进行修改或直接打印。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This is a vertical axis wind turbine (VAWT) 3D model, featuring a twisted helical blade design that enhances symmetry and visual appeal. It’s designed to be support-free for easy 3D printing, and includes a 608 bearing mount at the bottom to allow free spinning when assembled. Please note: this is a non-functional display model and is not powered by wind.&lt;/p&gt;
&lt;p&gt;The model was created using Fusion 360, and comes with both .f3d (Fusion 360 source file) and .3mf (widely compatible with slicer software) formats, making it easy to modify or print.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/statistics/Vertical-Axis-Wind-Turbine-3D-Model/mini风力发电机.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/statistics/Vertical-Axis-Wind-Turbine-3D-Model/mini风力发电机.3mf"&gt;mini风力发电机.3mf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/statistics/Vertical-Axis-Wind-Turbine-3D-Model/mini风力发电机.f3d"&gt;mini风力发电机.f3d&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="3D printing"/></entry><entry><title>动手实现智能指针 （上篇） - C++ for the Antiquated（之四）</title><link href="https://wizmann.top/std-smart-ptrs-cpp-for-the-antiquated-4.html" rel="alternate"/><published>2025-01-21T00:00:00+08:00</published><updated>2025-01-21T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-01-21:/std-smart-ptrs-cpp-for-the-antiquated-4.html</id><summary type="html">&lt;p&gt;智能指针（如 &lt;code&gt;std::shared_ptr&lt;/code&gt; 和 &lt;code&gt;std::weak_ptr&lt;/code&gt;）已经成为现代 C++ 编程的重要工具，尽管它们并不算是“新兴”的特性。在 C++11 标准之前，Boost 库就已经引 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;智能指针（如 &lt;code&gt;std::shared_ptr&lt;/code&gt; 和 &lt;code&gt;std::weak_ptr&lt;/code&gt;）已经成为现代 C++ 编程的重要工具，尽管它们并不算是“新兴”的特性。在 C++11 标准之前，Boost 库就已经引入了智能指针的实现，特别是 &lt;code&gt;boost::shared_ptr&lt;/code&gt; 和 &lt;code&gt;boost::weak_ptr&lt;/code&gt;，它们为 C++11 的智能指针特性奠定了基础。因此，可以说智能指针在 C++ 中的发展历程已经有很长时间，而它们的引入极大地简化了内存管理和避免了常见的内存泄漏和悬挂指针问题。&lt;/p&gt;
&lt;p&gt;本文将围绕以下主题展开讨论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C++ 智能指针的实现原理  &lt;/li&gt;
&lt;li&gt;非侵入式智能指针与侵入式智能指针的区别  &lt;/li&gt;
&lt;li&gt;利用 &lt;code&gt;atomic&lt;/code&gt; 避免多线程竞态条件&lt;/li&gt;
&lt;li&gt;如何实现侵入式版本的 &lt;code&gt;shared_ptr&lt;/code&gt; 和 &lt;code&gt;weak_ptr&lt;/code&gt;  &lt;/li&gt;
&lt;li&gt;采用 &lt;code&gt;concept&lt;/code&gt; 约束模板类型  &lt;/li&gt;
&lt;li&gt;探讨完美转发（&lt;code&gt;std::forward&amp;lt;T&amp;gt;&lt;/code&gt;）在智能指针中的应用  &lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="c"&gt;C++ 中的智能指针&lt;/h2&gt;
&lt;h3 id="stdshared_ptr"&gt;&lt;code&gt;std::shared_ptr&lt;/code&gt;的实现&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;std::shared_ptr&lt;/code&gt; 是一种智能指针，能够自动管理对象的生命周期。它通过引用计数的方式来跟踪有多少个 &lt;code&gt;shared_ptr&lt;/code&gt; 实例指向同一个对象，确保当最后一个 &lt;code&gt;shared_ptr&lt;/code&gt; 被销毁时，对象的内存能够自动释放。&lt;/p&gt;
&lt;h4 id="_1"&gt;引用计数与原子操作&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;std::shared_ptr&lt;/code&gt; 的核心机制是引用计数。每个 &lt;code&gt;shared_ptr&lt;/code&gt; 会维护一个引用计数。当多个 &lt;code&gt;shared_ptr&lt;/code&gt; 指向同一个对象时，计数器会增加；当一个 &lt;code&gt;shared_ptr&lt;/code&gt; 被销毁时，计数器会减少。如果计数器归零，表明没有任何 &lt;code&gt;shared_ptr&lt;/code&gt; 再指向该对象，这时对象会被删除。&lt;/p&gt;
&lt;p&gt;引用计数通常由一个控制块（control block）管理。控制块不仅保存引用计数，还会保存对象本身以及与对象生命周期相关的其他信息。&lt;code&gt;std::shared_ptr&lt;/code&gt; 的实现一般使用“非侵入式引用计数”（即不嵌入对象本身）。&lt;/p&gt;
&lt;p&gt;示例代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;control_block&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;control_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 增加引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 减少引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;release_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 删除对象&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 删除控制块&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;// 实际对象&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="shared_ptr"&gt;简化版 &lt;code&gt;shared_ptr&lt;/code&gt; 实现&lt;/h4&gt;
&lt;p&gt;下面是一个简化版的 &lt;code&gt;shared_ptr&lt;/code&gt; 实现示例。这个版本仍然有一些重要细节需要注意，比如原子操作和异常安全等问题，但可以帮助理解 &lt;code&gt;shared_ptr&lt;/code&gt; 的基本原理：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;my_shared_ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;control_block&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;explicit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my_shared_ptr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;control_block&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 拷贝构造函数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;my_shared_ptr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my_shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;add_ref&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 析构函数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;my_shared_ptr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;release_ref&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="stdweak_ptr"&gt;&lt;code&gt;std::weak_ptr&lt;/code&gt;的实现&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;std::weak_ptr&lt;/code&gt; 是与 &lt;code&gt;std::shared_ptr&lt;/code&gt; 配合使用的智能指针，它解决了 &lt;code&gt;shared_ptr&lt;/code&gt; 在某些场景下的循环引用问题。&lt;/p&gt;
&lt;p&gt;循环引用问题发生在两个或多个对象通过 &lt;code&gt;shared_ptr&lt;/code&gt; 相互引用时，导致引用计数永远不为零，从而引发内存泄漏。为了避免这个问题，我们引入了 &lt;code&gt;weak_ptr&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id="weak_ptr"&gt;为什么需要 &lt;code&gt;weak_ptr&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;std::weak_ptr&lt;/code&gt; 不增加引用计数，因此它不会影响对象的生命周期。当一个对象的所有 &lt;code&gt;shared_ptr&lt;/code&gt; 被销毁后，&lt;code&gt;weak_ptr&lt;/code&gt; 将变为“悬挂”状态。这与普通指针的“空悬指针”（dangling pointer）不同，空悬的 &lt;code&gt;weak_ptr&lt;/code&gt; 会返回空指针 &lt;code&gt;nullptr&lt;/code&gt;，表明该对象的生命周期已经结束。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;weak_ptr&lt;/code&gt; 提供了一种访问 &lt;code&gt;shared_ptr&lt;/code&gt; 的方式，但并不控制对象的销毁，因此它可以有效避免循环引用问题。&lt;/p&gt;
&lt;p&gt;通过 &lt;code&gt;weak_ptr&lt;/code&gt;，我们可以在不延长对象生命周期的前提下，检查对象是否仍然存在，并访问它。具体来说，&lt;code&gt;weak_ptr&lt;/code&gt; 可以通过调用 &lt;code&gt;lock()&lt;/code&gt; 方法来创建一个 &lt;code&gt;shared_ptr&lt;/code&gt;，如果对象还存在（即引用计数大于零），则返回一个有效的 &lt;code&gt;shared_ptr&lt;/code&gt;，否则返回空指针。&lt;/p&gt;
&lt;h4 id="_2"&gt;控制块的扩展&lt;/h4&gt;
&lt;p&gt;为了支持&lt;code&gt;std::weak_ptr&lt;/code&gt;， 我们需要扩展控制块的功能 ，使其能同时管理对象的引用计数（&lt;code&gt;ref_count&lt;/code&gt;）和弱引用计数（&lt;code&gt;weak_count&lt;/code&gt;），从而保持对对象的生命周期的正确管理。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;control_block&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;control_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weak_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 增加引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 增加引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 使用加载当前值，避免重复读取&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compare_exchange_weak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// 如果失败，重新加载当前值&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 如果 prev &amp;gt; 0，表示锁定成功&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 减少引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;release_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 删除对象&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;release_control_block&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 尝试删除控制块&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 增加弱引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add_weak_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;weak_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 减少弱引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;release_weak_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weak_count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 删除控制块&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 删除控制块，只有在弱引用计数为0时才删除控制块&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;release_control_block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weak_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 删除控制块&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 强引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weak_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// 弱引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;// 实际对象&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="weak_ptr_1"&gt;&lt;code&gt;weak_ptr&lt;/code&gt; 的简化版实现&lt;/h4&gt;
&lt;p&gt;下面是一个简化版的 &lt;code&gt;weak_ptr&lt;/code&gt; 实现，它与 &lt;code&gt;shared_ptr&lt;/code&gt; 共享相同的控制块。&lt;code&gt;weak_ptr&lt;/code&gt; 本身不增加引用计数，因此不会影响对象的生命周期。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;my_weak_ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;my_weak_ptr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 从 shared_ptr 构造 my_weak_ptr&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;my_weak_ptr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;add_weak_ref&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;my_weak_ptr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;release_weak_ref&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 尝试获取指向对象的 shared_ptr&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;control_block&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 控制块&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;my_shared_ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;control_block&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;my_shared_ptr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my_weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctrl_block&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bad weak ptr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="stdatomict"&gt;理解并优化&lt;code&gt;std::atomic&amp;lt;T&amp;gt;&lt;/code&gt;操作&lt;/h2&gt;
&lt;p&gt;在上面的代码示例中，我们使用了&lt;code&gt;std::atomic&amp;lt;int&amp;gt;&lt;/code&gt;作为智能指针的引用计数。与直接使用&lt;code&gt;int&lt;/code&gt;变量不同，&lt;code&gt;std::atomic&amp;lt;int&amp;gt;&lt;/code&gt;可以在多线程环境中正确地管理对同一智能指针的引用计数。&lt;/p&gt;
&lt;p&gt;然而，在上述代码中，我们仅使用了&lt;code&gt;std::atomic&amp;lt;int&amp;gt;&lt;/code&gt;的基本操作（如自增、自减和赋值等），这些操作默认使用&lt;code&gt;memory_order_seq_cst&lt;/code&gt;内存序（稍后会讨论）。在多线程编程中，&lt;code&gt;std::atomic&amp;lt;T&amp;gt;&lt;/code&gt;提供了多种内存序（memory ordering）选项，用以控制操作的可见性和执行顺序，以确保数据一致性。不同的内存序策略决定了编译器和CPU对指令的重排序程度。&lt;/p&gt;
&lt;p&gt;开发者的目标是选择合适的内存序，优化程序性能，同时确保程序的正确性。&lt;/p&gt;
&lt;h3 id="_3"&gt;内存序的核心概念&lt;/h3&gt;
&lt;p&gt;理解内存序的关键在于&lt;strong&gt;重排序&lt;/strong&gt;和&lt;strong&gt;跨线程可见性&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;重排序（Reordering）&lt;/strong&gt;&lt;br&gt;
   编译器和CPU可能会重排指令，以优化性能。例如，它们可能会提前执行某些计算，或者将存储操作推迟执行。正确使用&lt;code&gt;std::atomic&lt;/code&gt;可以防止某些关键操作被错误地重排序。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可见性（Visibility）&lt;/strong&gt;&lt;br&gt;
   在多线程环境中，一个线程对变量的修改可能不会立即被其他线程看到，或者多个线程对同一变量的操作顺序可能不确定。原子操作的内存序决定了其他线程何时能看到这些修改。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="_4"&gt;不同内存序的作用及使用场景&lt;/h3&gt;
&lt;h4 id="memory_order_relaxed"&gt;&lt;code&gt;memory_order_relaxed&lt;/code&gt;（松散顺序，最低开销）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：不保证顺序，仅保证操作是&lt;strong&gt;原子的&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;作用&lt;/strong&gt;：确保同一&lt;code&gt;std::atomic&amp;lt;T&amp;gt;&lt;/code&gt;变量的读写操作是原子的，但不提供线程间的同步，不影响可见性或顺序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：适用于&lt;strong&gt;数据竞争不影响程序正确性&lt;/strong&gt;的场景，如&lt;strong&gt;无依赖的计数&lt;/strong&gt;（统计线程数、事件计数等）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 仅保证原子性，不保证可见性&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这里，&lt;code&gt;fetch_add&lt;/code&gt;确保&lt;code&gt;counter&lt;/code&gt;自增操作不会丢失，但不同线程的修改可能会被延迟看到。&lt;/p&gt;
&lt;h4 id="memory_order_acquire"&gt;&lt;code&gt;memory_order_acquire&lt;/code&gt;（获取，防止重排序到前）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：保证&lt;strong&gt;当前线程&lt;/strong&gt;在&lt;code&gt;acquire&lt;/code&gt;之后的所有操作不会被重排序到&lt;code&gt;acquire&lt;/code&gt;之前，因此，其他线程中相同原子变量的释放操作（release operation）之前的写入对当前线程是可见的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：用于&lt;strong&gt;读取&lt;/strong&gt;共享数据，确保当前线程能够看到其他线程之前对该变量的修改。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="memory_order_release"&gt;&lt;code&gt;memory_order_release&lt;/code&gt;（释放，防止重排序到后）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：确保&lt;strong&gt;当前线程&lt;/strong&gt;在&lt;code&gt;release&lt;/code&gt;之前的所有操作不会被重排序到&lt;code&gt;release&lt;/code&gt;之后，因此，当前操作所在线程之前的写入，在其他线程施加占有操作（acquire operation）之后是可见的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：用于&lt;strong&gt;写入&lt;/strong&gt;共享数据，确保其他线程能在&lt;code&gt;acquire&lt;/code&gt;读取时看到修改。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_release&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 让消费者可以看到 data=42&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acquire&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 确保 data=42 可见&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 确保 data 的修改对本线程可见&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;store(release)&lt;/code&gt;确保&lt;code&gt;data=42&lt;/code&gt;发生在&lt;code&gt;flag=1&lt;/code&gt;之前。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;load(acquire)&lt;/code&gt;确保&lt;code&gt;flag=1&lt;/code&gt;之后，&lt;code&gt;data=42&lt;/code&gt;对消费者线程可见。&lt;/li&gt;
&lt;li&gt;通过&lt;code&gt;acquire-release&lt;/code&gt;，消费者线程能够正确看到生产者线程的&lt;code&gt;data&lt;/code&gt;修改。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="memory_order_acq_rel-"&gt;&lt;code&gt;memory_order_acq_rel&lt;/code&gt;（获取-释放，双向同步）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：结合&lt;code&gt;acquire&lt;/code&gt;和&lt;code&gt;release&lt;/code&gt;，用于&lt;strong&gt;读-改-写（Read-Modify-Write, RMW）&lt;/strong&gt;操作，确保：&lt;/li&gt;
&lt;li&gt;读取时使用&lt;code&gt;acquire&lt;/code&gt;语义，保证之前的修改对当前线程可见。&lt;/li&gt;
&lt;li&gt;写入时使用&lt;code&gt;release&lt;/code&gt;语义，保证当前修改对后续线程可见。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：用于&lt;strong&gt;读-改-写&lt;/strong&gt;（如&lt;code&gt;fetch_add()&lt;/code&gt;、&lt;code&gt;exchange()&lt;/code&gt;）操作，确保多个线程能够正确协调。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acq_rel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 读写都保证可见性&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在这里，&lt;code&gt;fetch_add&lt;/code&gt;同时读取旧值并写入新值：&lt;br&gt;
- 读取时使用&lt;code&gt;acquire&lt;/code&gt;语义，确保它能看到其他线程的修改。&lt;br&gt;
- 写入时使用&lt;code&gt;release&lt;/code&gt;语义，确保它的修改能被其他线程看到。&lt;/p&gt;
&lt;h4 id="memory_order_seq_cst"&gt;&lt;code&gt;memory_order_seq_cst&lt;/code&gt;（顺序一致性，最严格）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：所有使用&lt;code&gt;memory_order_seq_cst&lt;/code&gt;的原子操作在&lt;strong&gt;所有线程看来&lt;/strong&gt;都是按照相同的顺序执行的，即全局一致的时序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：&lt;/li&gt;
&lt;li&gt;需要严格同步的场景，如&lt;strong&gt;锁&lt;/strong&gt;、&lt;strong&gt;同步变量&lt;/strong&gt;、&lt;strong&gt;临界区保护&lt;/strong&gt;等。&lt;/li&gt;
&lt;li&gt;适用于&lt;strong&gt;多线程交互复杂&lt;/strong&gt;、难以管理依赖关系的情况。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;保证&lt;/strong&gt;：&lt;br&gt;
- &lt;code&gt;seq_cst&lt;/code&gt;确保所有操作严格按照全局统一顺序执行，避免乱序问题。&lt;/p&gt;
&lt;h3 id="_5"&gt;直观比喻&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;relaxed&lt;/code&gt;：随意写笔记，但不保证别人能看到。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;acquire&lt;/code&gt;：&lt;strong&gt;进门检查公告栏&lt;/strong&gt;，确保看到之前的通知。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;release&lt;/code&gt;：&lt;strong&gt;离开时更新公告栏&lt;/strong&gt;，让后来的人看到。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;acq_rel&lt;/code&gt;：&lt;strong&gt;进门看公告 + 走前更新公告&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;seq_cst&lt;/code&gt;：&lt;strong&gt;所有人按同样顺序写、看公告&lt;/strong&gt;，保证一致性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;根据不同场景合理选择内存序，可以提高并发程序的正确性和性能。&lt;/p&gt;
&lt;h3 id="_6"&gt;优化控制块中的原子变量&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;atomic&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;control_block&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;control_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weak_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 增加引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 尝试增加强引用计数（仅当对象仍然存活时）&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acquire&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compare_exchange_weak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acquire&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 成功锁定&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 对象已被释放&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 释放强引用&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;release_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acq_rel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 删除对象&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;release_control_block&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 尝试删除控制块&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 增加弱引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add_weak_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;weak_count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 释放弱引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;release_weak_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weak_count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acq_rel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 删除控制块&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 删除控制块，仅当弱引用计数也归零时&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;release_control_block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weak_count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memory_order_acq_rel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 删除控制块&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 强引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weak_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// 弱引用计数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;// 实际对象&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_7"&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://zhuanlan.zhihu.com/p/532215950"&gt;C++内存管理：shared_ptr/weak_ptr源码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cnblogs.com/Solstice/archive/2010/02/10/dtor_meets_threads.html"&gt;当析构函数遇到多线程 ── C++ 中线程安全的对象回调&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://liam.page/2021/12/11/memory-order-cpp-02/"&gt;程序员的自我修养（⑫）：C++ 的内存顺序&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="cpp"/><category term="modern cpp"/></entry><entry><title>std::visit实现运行时多态 - C++ for the Antiquated（之三）</title><link href="https://wizmann.top/std-visit-polymorphism-cpp-for-the-antiquated-3.html" rel="alternate"/><published>2025-01-04T00:00:00+08:00</published><updated>2025-01-04T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-01-04:/std-visit-polymorphism-cpp-for-the-antiquated-3.html</id><summary type="html">&lt;p&gt;在传统的 &lt;strong&gt;C++&lt;/strong&gt; 中，&lt;strong&gt;运行时多态&lt;/strong&gt; 通常依赖于 &lt;strong&gt;“接口 - 虚函数”&lt;/strong&gt; 机制，通过抽象类、具体类与对象的设计来实现。这种多态方式通常被称 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;在传统的 &lt;strong&gt;C++&lt;/strong&gt; 中，&lt;strong&gt;运行时多态&lt;/strong&gt; 通常依赖于 &lt;strong&gt;“接口 - 虚函数”&lt;/strong&gt; 机制，通过抽象类、具体类与对象的设计来实现。这种多态方式通常被称为 &lt;strong&gt;子类型多态&lt;/strong&gt;（&lt;em&gt;Subtype Polymorphism&lt;/em&gt;）。&lt;/p&gt;
&lt;p&gt;在之前的文章中，我们介绍了现代 C++ 引入的 &lt;code&gt;std::variant&lt;/code&gt; —— 一种类型安全的联合体，以及如何借助 &lt;code&gt;std::visit&lt;/code&gt; 在类型安全的前提下，动态地访问联合体中的不同类型，并执行相应的逻辑。这种多态方式被称为 &lt;strong&gt;临时多态&lt;/strong&gt;（&lt;em&gt;Ad-hoc Polymorphism&lt;/em&gt;）。&lt;/p&gt;
&lt;p&gt;除此之外，还有一种被称为 &lt;strong&gt;参数化多态&lt;/strong&gt;（&lt;em&gt;Parametric Polymorphism&lt;/em&gt;），即我们熟知的 &lt;strong&gt;C++ 模板&lt;/strong&gt;。它允许我们编写与类型无关的代码，提供更强的泛型编程能力。由于本篇文章的重点并不在此，我们暂且不展开。&lt;/p&gt;
&lt;p&gt;在本篇文章中，我们将重点对比 &lt;strong&gt;子类型多态&lt;/strong&gt; 和 &lt;strong&gt;临时多态&lt;/strong&gt; 的优劣，分析它们在实际场景中的应用与权衡，希望能更好地理解和选择合适的多态机制。&lt;/p&gt;
&lt;h2 id="_1"&gt;&lt;strong&gt;临时多态的实现原理&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;临时多态&lt;/strong&gt;（&lt;em&gt;Ad-hoc Polymorphism&lt;/em&gt;）与 &lt;strong&gt;子类型多态&lt;/strong&gt;（&lt;em&gt;Subtype Polymorphism&lt;/em&gt;）在实现原理上有一定的相似性：它们都依赖于在类型中引入额外的信息来决定不同类型应执行的函数逻辑。  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;子类型多态&lt;/strong&gt;：依赖于&lt;strong&gt;虚表（vtable）&lt;/strong&gt; 和 &lt;strong&gt;虚指针（vptr）&lt;/strong&gt;，通过运行时的动态分派来确定调用哪个派生类的成员函数。  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;临时多态&lt;/strong&gt;：依赖一个 &lt;strong&gt;枚举值（enum）&lt;/strong&gt; 来表示类型信息，通过显式的 &lt;code&gt;switch-case&lt;/code&gt; 或 &lt;code&gt;if-else&lt;/code&gt; 语句来选择不同的逻辑分支。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="stdvisit"&gt;&lt;strong&gt;简单示例：模拟 std::visit&lt;/strong&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;这里只使用了传统C++的实现，关于&lt;code&gt;std::visit&lt;/code&gt;的更详细的解读，可以参考本系列的“动手实现std::visit”一文。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cassert&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;EType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;TYPE_Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;TYPE_Float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;TYPE_String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MyVariant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;EType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;MyVisitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyVariant&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;TYPE_Int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Int: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;TYPE_Float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Float: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;TYPE_String&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;String: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown type!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.14f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MyVariant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;TYPE_Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MyVariant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;TYPE_Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MyVariant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;TYPE_String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MyVisitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MyVisitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MyVisitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_2"&gt;&lt;strong&gt;原理解析&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;EType 枚举&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;定义了一个枚举类型 &lt;code&gt;EType&lt;/code&gt;，用于标识 &lt;code&gt;MyVariant&lt;/code&gt; 当前存储的具体类型。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MyVariant 结构体&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt; 字段保存当前对象的类型信息。  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;obj&lt;/code&gt; 字段是一个通用指针，指向实际存储的数据对象。  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MyVisitor 函数&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;通过 &lt;code&gt;switch-case&lt;/code&gt; 语句，基于 &lt;code&gt;type&lt;/code&gt; 字段选择不同的分支逻辑来访问和打印不同类型的数据。  &lt;/li&gt;
&lt;li&gt;如果遇到未知类型，程序会触发 &lt;code&gt;assert&lt;/code&gt; 以防止未定义行为。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="_3"&gt;&lt;strong&gt;性能优化思考&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;在实际应用中，&lt;code&gt;switch-case&lt;/code&gt; 语句可能随着类型数量的增加而导致性能开销。可以通过二分查找（Binary Search）方法进行优化，减少 &lt;code&gt;switch-case&lt;/code&gt; 的分支深度。&lt;/p&gt;
&lt;h2 id="_4"&gt;临时多态的性能分析&lt;/h2&gt;
&lt;p&gt;虚函数常因其较低的性能而受到批评。为了更好地了解这一点，我们将对比使用虚函数实现的“子类型多态”和通过 &lt;code&gt;std::visit&lt;/code&gt; 实现的“临时多态”在性能上的差异。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用虚函数实现的&lt;a href="https://gist.github.com/Wizmann/df65af6d214c3b4ae296363839477b94"&gt;代码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;std::visit&lt;/code&gt; + &lt;code&gt;std::variant&amp;lt;object&amp;gt;&lt;/code&gt; 实现的&lt;a href="https://gist.github.com/Wizmann/f1494312a8e0cf30b97e9d8580fa9d6d"&gt;代码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;std::visit&lt;/code&gt; + &lt;code&gt;std::variant&amp;lt;ptr&amp;gt;&lt;/code&gt; 实现的&lt;a href="https://gist.github.com/Wizmann/a25708bcd732df8f6e3d158f7105b6c9"&gt;代码&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;结果如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# 使用g++ --std=c++17 -O2编译运行&lt;/span&gt;

&lt;span class="c1"&gt;# 使用虚函数实现&lt;/span&gt;
&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Creation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;55.53&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;
&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;6.99&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;

&lt;span class="c1"&gt;# 使用std::visit + std::variant&amp;lt;object&amp;gt;实现&lt;/span&gt;
&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Creation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;26.88&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;
&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5.93&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;

&lt;span class="c1"&gt;# 使用std::visit + std::variant&amp;lt;ptr&amp;gt;实现&lt;/span&gt;
&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Creation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;52.15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;
&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;6.05&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_5"&gt;结果分析&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;内存管理开销：&lt;br&gt;
    使用虚函数的子类型多态实现通常需要动态申请和释放内存，从而引入了额外的内存管理开销。而使用基于 &lt;code&gt;std::variant&amp;lt;object&amp;gt;&lt;/code&gt;的临时多态可以一次性分配所有内存，虽然可能存在一定程度的内存浪费，但避免了频繁的动态内存管理。&lt;/li&gt;
&lt;li&gt;性能接近，&lt;code&gt;std::visit&lt;/code&gt; 略优：&lt;br&gt;
    虽然虚函数和 &lt;code&gt;std::visit&lt;/code&gt; 的性能差距不大，但 &lt;code&gt;std::visit&lt;/code&gt; 略微优于虚函数。两者都引入了额外的开销以实现多态。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="vistor"&gt;通过临时多态实现Vistor模式&lt;/h2&gt;
&lt;p&gt;Visitor模式是一种行为设计模式，用于将数据结构的操作与数据结构本身分离。它通常通过“子类型多态”来实现，其中每个具体类型的对象都接受一个访问者（Visitor）并对其进行相应的处理。使用虚函数和继承是实现这一模式的一种方式，但有时我们可以用更轻量的方式来实现，比如通过临时多态结合 &lt;code&gt;std::variant&lt;/code&gt; 和 &lt;code&gt;std::visit&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="visitor"&gt;使用虚函数实现Visitor模式&lt;/h3&gt;
&lt;p&gt;我们首先来看一个传统的通过子类型多态实现Visitor模式的例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;IVisitor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;IResource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IVisitor&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;IVisitor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IResource&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MyResource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IResource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IVisitor&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MyVisitor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IVisitor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IResource&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// 处理资源&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这种实现方式虽然能很好地分离数据和操作，但它也有一些不足之处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每次调用 &lt;code&gt;visit&lt;/code&gt; 都需要通过虚函数来间接调用方法，这会引入额外的性能开销。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visitor&lt;/code&gt; 无法在 &lt;code&gt;visit&lt;/code&gt; 时直接获取资源对象的类型信息，通常需要额外传递类型信息或者让资源类暴露更多的接口。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="stdvisit-visitor"&gt;使用 &lt;code&gt;std::visit&lt;/code&gt; 实现Visitor模式&lt;/h3&gt;
&lt;p&gt;通过 &lt;code&gt;std::visit&lt;/code&gt; 和 &lt;code&gt;std::variant&lt;/code&gt;，我们可以显式地通过类型信息来处理每种资源类型，避免了虚函数调用的开销，同时使得代码更加简洁和类型安全。下面是一个通过临时多态实现Visitor模式的例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResourceUnion&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResourceA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResourceB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResourceC&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResourceUnion&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;([](&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;decay_t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;decltype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_same_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResourceA&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// 处理类型为 ResourceA 的资源&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_same_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResourceB&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// 处理类型为 ResourceB 的资源&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_same_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResourceC&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// 处理类型为 ResourceC 的资源&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;static_assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;always_false_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unhandled type!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_6"&gt;优点与分析&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;类型安全&lt;/strong&gt;：&lt;br&gt;
   使用 &lt;code&gt;std::visit&lt;/code&gt; 时，编译器可以根据类型推断并为每种类型生成不同的代码路径，从而避免了运行时错误和类型错误，提升了类型安全性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;性能&lt;/strong&gt;：&lt;br&gt;
   由于不再依赖虚函数，&lt;code&gt;std::visit&lt;/code&gt; 能避免每次调用 &lt;code&gt;visit&lt;/code&gt; 时的虚函数开销，从而提高了性能。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;简洁性&lt;/strong&gt;：&lt;br&gt;
   通过 &lt;code&gt;std::variant&lt;/code&gt; 和 &lt;code&gt;std::visit&lt;/code&gt;，代码更加简洁且不需要繁琐的继承结构。每个资源类型只需关注其自身的实现，而无需处理不同访问者的逻辑。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;扩展性&lt;/strong&gt;：&lt;br&gt;
   如果要新增资源类型，只需在 &lt;code&gt;std::variant&lt;/code&gt; 中添加新类型，并在 &lt;code&gt;std::visit&lt;/code&gt; 的 lambda 表达式中添加对应的分支，避免了修改现有代码的风险。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="_7"&gt;临时多态的优点与缺点&lt;/h2&gt;
&lt;h3 id="_8"&gt;优点：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;类型安全&lt;/strong&gt;：&lt;code&gt;std::variant&lt;/code&gt; 与 &lt;code&gt;std::visit&lt;/code&gt; 确保了类型安全，避免了许多传统多态机制中的错误。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能优化&lt;/strong&gt;：相较于虚函数，&lt;code&gt;std::visit&lt;/code&gt; 通过类型折叠和编译时分支优化，通常表现出更好的性能，尤其在没有动态内存管理时。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自由组织功能函数&lt;/strong&gt;：你可以灵活地将功能函数组织在一个地方，而无需修改每个具体类型。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="_9"&gt;缺点：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;职责分散&lt;/strong&gt;：每个类型的行为都可能分散到多个&lt;code&gt;visit&lt;/code&gt;函数中，导致代码难以维护。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高耦合风险&lt;/strong&gt;：当新增类型时，所有访问逻辑需要修改，可能带来较高的耦合度，尤其在类型较多时。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="_10"&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;C++20高级编程（罗能） —— 1.6 运行时多态&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiyi.org/polymorphism-in-java.html"&gt;深入理解面向对象中的多态&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://refactoringguru.cn/design-patterns/visitor/cpp/example"&gt;C++ 访问者模式讲解和代码示例&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="cpp"/><category term="modern cpp"/></entry><entry><title>动手实现std::visit - C++ for the Antiquated（之二）</title><link href="https://wizmann.top/std-visit-cpp-for-the-antiquated-2.html" rel="alternate"/><published>2025-01-01T00:00:00+08:00</published><updated>2025-01-01T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2025-01-01:/std-visit-cpp-for-the-antiquated-2.html</id><summary type="html">&lt;h2 id="stdvariant-stdvisit"&gt;std::variant 与 std::visit&lt;/h2&gt;
&lt;h3 id="stdvariant"&gt;std::variant&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;std::variant&lt;/code&gt; 是 C++17 引入的类型安全的联合体（type-safe union），可以在多个预定义类型中存储任意一个值。与传统的 &lt;code&gt;union&lt;/code&gt; 不同 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="stdvariant-stdvisit"&gt;std::variant 与 std::visit&lt;/h2&gt;
&lt;h3 id="stdvariant"&gt;std::variant&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;std::variant&lt;/code&gt; 是 C++17 引入的类型安全的联合体（type-safe union），可以在多个预定义类型中存储任意一个值。与传统的 &lt;code&gt;union&lt;/code&gt; 不同，&lt;code&gt;std::variant&lt;/code&gt; 能够在运行时安全地检查当前存储的类型，避免未定义行为。&lt;/p&gt;
&lt;p&gt;其核心特点如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;类型安全：访问值时进行类型检查，防止类型错误。&lt;/li&gt;
&lt;li&gt;固定类型集合：存储类型在编译时确定。&lt;/li&gt;
&lt;li&gt;异常安全：在赋值失败时会进入无效状态（std::monostate）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="stdvisit"&gt;std::visit&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;std::visit&lt;/code&gt; 是一个访问器函数，用于访问 &lt;code&gt;std::variant&lt;/code&gt; 中当前存储的值。它通过一个可调用对象（如 Lambda 表达式）来处理存储的值，从而实现编译时多态。&lt;/p&gt;
&lt;p&gt;其核心特点如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;统一访问接口：无论存储的是哪种类型，都可以通过同一个函数进行访问。&lt;/li&gt;
&lt;li&gt;类型安全：确保所有可能的类型都被正确处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_1"&gt;代码示例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;variant&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;type_traits&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kr"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;always_false_v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mf"&gt;3.14f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;foobar&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;([](&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;decay_t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;decltype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_same_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;int: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_same_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;float: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_same_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;std::string: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;static_assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;always_false_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unhandled type!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_2"&gt;代码分析&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;std::variant&amp;lt;int, float, std::string&amp;gt;&lt;/code&gt;&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这是一个类型安全的联合体，可以存储 &lt;code&gt;int&lt;/code&gt;、&lt;code&gt;float&lt;/code&gt; 或 &lt;code&gt;std::string&lt;/code&gt; 中的任意一种类型。  &lt;/li&gt;
&lt;li&gt;将多个 &lt;code&gt;std::variant&lt;/code&gt; 存储在 &lt;code&gt;std::vector&lt;/code&gt; 中，形成一个统一的容器。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;std::visit&lt;/code&gt;&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;std::visit&lt;/code&gt; 访问每个 &lt;code&gt;std::variant&lt;/code&gt; 元素。  &lt;/li&gt;
&lt;li&gt;传入一个&lt;strong&gt;泛型 Lambda 表达式&lt;/strong&gt;，通过 &lt;code&gt;if constexpr&lt;/code&gt; 在编译时分发到不同的分支，处理不同类型的值。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;if constexpr&lt;/code&gt; 与 &lt;code&gt;std::is_same_v&lt;/code&gt;&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;std::is_same_v&lt;/code&gt; 判断存储的实际类型。  &lt;/li&gt;
&lt;li&gt;根据类型进行不同的输出操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;类型安全&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果添加一个未处理的类型，编译器会在 &lt;code&gt;static_assert&lt;/code&gt; 中报错，提醒开发者补充处理逻辑。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="cstdvisit"&gt;使用传统C++实现std::visit&lt;/h2&gt;
&lt;h3 id="stdvariant_1"&gt;实现std::variant&lt;/h3&gt;
&lt;p&gt;在传统 C++ 中，我们只有简单的 &lt;code&gt;union&lt;/code&gt; 来实现“联合体”语义。然而，&lt;code&gt;union&lt;/code&gt; 存在一些局限性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无法存储非平凡类型（例如 &lt;code&gt;std::string&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;无法跟踪当前存储的类型。&lt;/li&gt;
&lt;li&gt;无法进行类型安全检查。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而 &lt;code&gt;std::variant&lt;/code&gt; 通过类型索引和类型匹配来提供类型安全，支持多种类型的存储与访问。&lt;/p&gt;
&lt;h3 id="stdvisit_1"&gt;实现 std::visit&lt;/h3&gt;
&lt;p&gt;实现 &lt;code&gt;std::visit&lt;/code&gt; 需要使用一个可调用对象（例如 Visitor）来访问 &lt;code&gt;std::variant&lt;/code&gt; 中的值。具体来说，它在编译时根据实际类型匹配相应的 &lt;code&gt;operator()&lt;/code&gt; 方法。&lt;/p&gt;
&lt;p&gt;示例代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;variant&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;type_traits&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Visitor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;int: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;float: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;114.514f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 获取当前类型的索引&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 输出: 1 (float 的索引)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 获取当前存储的值&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 输出: 114.514&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bad_variant_access&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;what&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 类型不匹配，抛出异常&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 使用 Visitor 访问值&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Visitor&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 输出: 1 (float 类型返回 1)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_3"&gt;实现的核心要点&lt;/h3&gt;
&lt;p&gt;实现 &lt;code&gt;std::visit&lt;/code&gt; 的关键在于以下几个方面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;类型索引 (&lt;code&gt;index()&lt;/code&gt;)&lt;/strong&gt;&lt;br&gt;
    根据传入的 &lt;code&gt;std::variant&lt;/code&gt; 参数类型，确定其在类型集合中的索引。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;类型访问 (&lt;code&gt;std::get&amp;lt;T&amp;gt;&lt;/code&gt;)&lt;/strong&gt;&lt;br&gt;
    根据传入的模板类型 &lt;code&gt;T&lt;/code&gt;，获取存储的值。如果类型不匹配，抛出异常，确保类型安全。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;类型分派 (&lt;code&gt;std::visit&lt;/code&gt;)&lt;/strong&gt;&lt;br&gt;
    根据当前存储的类型，调用 &lt;code&gt;Visitor&lt;/code&gt; 中对应的 &lt;code&gt;operator()&lt;/code&gt; 方法。可以通过 &lt;code&gt;switch-case&lt;/code&gt; 或模板匹配来实现类型分发。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="0-"&gt;代码实现0 - 基本框架&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MyVariant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MyVariant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// TODO&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 用于存储“联合体”的数据&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Storage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;aligned_union_t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="1-index"&gt;代码实现1 - index()函数&lt;/h3&gt;
&lt;p&gt;我们使用经典的模板递归来查找类型对应的索引。同时，利用 &lt;code&gt;constexpr&lt;/code&gt; 来简化编译时计算的过程。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Types&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TupleElement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tuple_element&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Types&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TypeIndex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;First&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TypeIndex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;First&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_same&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;First&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypeIndex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TypeIndex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TypeIndex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;containsType&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TypeIndex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;通过上述代码，我们实现了在编译期确定传入类型对应的类型索引。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyVariant&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TargetType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;decay_t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static_assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;containsType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TargetType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Type not supported&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TargetType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;typeIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getTypeIndex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TargetType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="2-get"&gt;代码实现2 - &lt;code&gt;get()&lt;/code&gt; 函数&lt;/h3&gt;
&lt;p&gt;我们实现了一个函数 &lt;code&gt;MyVariant::get()&lt;/code&gt;，通过检查 &lt;code&gt;typeIndex&lt;/code&gt; 来确保获取的类型与存储类型一致。&lt;/p&gt;
&lt;p&gt;我们也能可以通过&lt;code&gt;MyGet&lt;/code&gt;函数模拟&lt;code&gt;std::get&amp;lt;T&amp;gt;&lt;/code&gt;函数的行为。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MyVariant&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyVariant&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyVariant&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TargetType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;decay_t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypeIndex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;typeIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;runtime_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Wrong type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;reinterpret_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TargetType&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="3-visit"&gt;代码实现3 - &lt;code&gt;visit&lt;/code&gt;函数&lt;/h3&gt;
&lt;p&gt;接下来是 &lt;code&gt;visit()&lt;/code&gt; 函数的实现。它通过递归方式依次访问 &lt;code&gt;std::variant&lt;/code&gt; 中的每种类型，并调用与之对应的处理函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Types&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TupleElement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tuple_element&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TVisitor&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyVariant&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TVisitor&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FirstType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TupleElement&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RetT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;decltype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;declval&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FirstType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visitImpl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RetT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TVisitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TVisitor&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;RetT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TVisitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;First&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;RetT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyVariant&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;visitImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TVisitor&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getTypeIndex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;First&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;typeIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;First&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// 递归访问剩余的类型&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visitImpl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RetT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TVisitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TVisitor&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;RetT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TVisitor&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;RetT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyVariant&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Ts&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;visitImpl&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="n"&gt;maybe_unused&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="n"&gt;TVisitor&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visitor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 基础情况：所有类型都已检查，未找到匹配的类型&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;runtime_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Wrong type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_4"&gt;总结&lt;/h2&gt;
&lt;p&gt;在本文中，我们实现了一个简单版的 &lt;code&gt;std::variant&lt;/code&gt; 和 &lt;code&gt;std::visit&lt;/code&gt;，通过传统 C++ 实现了类型安全的联合体数据结构。我们依次通过以下步骤构建了这一系统：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;MyVariant&lt;/code&gt; 类的基本框架&lt;/strong&gt;：通过联合体 (&lt;code&gt;union&lt;/code&gt;) 存储不同类型的数据，并使用模板构造函数动态设置值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;类型索引 (&lt;code&gt;index()&lt;/code&gt;) 的实现&lt;/strong&gt;：使用模板递归技术结合 &lt;code&gt;constexpr&lt;/code&gt; 来实现类型的编译时索引查找，从而在运行时根据类型索引来访问对应的值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;get()&lt;/code&gt; 函数&lt;/strong&gt;：实现了获取存储值的函数，并通过类型检查确保类型安全。如果访问了错误类型的数据，则抛出异常。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;visit()&lt;/code&gt; 函数&lt;/strong&gt;：实现了一个可扩展的访问机制，使得不同类型的值可以通过同一个 &lt;code&gt;Visitor&lt;/code&gt; 被访问和处理。通过递归的方式，系统能够动态地访问不同类型的值，并调用相应的处理函数。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过这些实现，我们成功模拟了 C++ 标准库中的 &lt;code&gt;std::variant&lt;/code&gt; 和 &lt;code&gt;std::visit&lt;/code&gt; 功能。同时，通过对比可以看出，现代 C++ 提供了更强大的模板元编程能力。利用这些特性，我们能够使用更直观的语法，在编译期间实现高效且类型安全的联合体访问，从而提供一种灵活、类型安全的方式来处理多类型数据。&lt;/p&gt;</content><category term="Blog"/><category term="cpp"/><category term="modern cpp"/></entry><entry><title>constexpr详解 - C++ for the Antiquated（之一）</title><link href="https://wizmann.top/constexpr-cpp-for-the-antiquated-1.html" rel="alternate"/><published>2024-12-28T00:00:00+08:00</published><updated>2024-12-28T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2024-12-28:/constexpr-cpp-for-the-antiquated-1.html</id><summary type="html">&lt;p&gt;在这篇文章中，我们将深入讨论 C++ 中的常量表达式（&lt;code&gt;constexpr&lt;/code&gt;）及其与传统的&lt;code&gt;const&lt;/code&gt;常量的区别，并结合实际代码示例进行说明。同时，我 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;在这篇文章中，我们将深入讨论 C++ 中的常量表达式（&lt;code&gt;constexpr&lt;/code&gt;）及其与传统的&lt;code&gt;const&lt;/code&gt;常量的区别，并结合实际代码示例进行说明。同时，我们还会探讨&lt;code&gt;constexpr&lt;/code&gt;函数在模板编程中的应用，以及 C++11 之后对常量表达式的优化与扩展。&lt;/p&gt;
&lt;h2 id="constexpr"&gt;常量表达式（constexpr）&lt;/h2&gt;
&lt;p&gt;在 C++ 中，&lt;code&gt;const&lt;/code&gt; 关键字通常用于修饰变量、引用和指针，使得它们在运行时不能被修改。需要注意的是，&lt;code&gt;const&lt;/code&gt; 并没有区分编译期常量和运行时常量，它只是保证了这些变量在运行时不可修改。&lt;/p&gt;
&lt;p&gt;例如，使用 &lt;code&gt;const&lt;/code&gt; 声明的变量在运行时其值是固定的，但并不意味着它们在编译时已知。&lt;/p&gt;
&lt;p&gt;下面是传统 C++ 中 &lt;code&gt;const&lt;/code&gt; 关键字的一些常见用法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#define CONSTANT_1 114514  &lt;/span&gt;&lt;span class="c1"&gt;// 宏也是一种常量&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;helloworld1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;helloworld&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// const 字符串&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 常量值&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 运行时计算&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arr_pow_of_2&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 数组初始化&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在上述代码中，虽然 const 修饰的变量在程序运行期间不能修改，但它们的值是在运行时计算的。因此，我们无法在编译时将它们视为常量。所以，&lt;code&gt;const&lt;/code&gt; 变量也可以有内存地址，并且在某些情况下可以使用 &lt;code&gt;const_cast&lt;/code&gt; 强行进行修改。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cmath&amp;gt;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;MakeChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MakeChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 输出：2&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="constexpr_1"&gt;引入 constexpr&lt;/h3&gt;
&lt;p&gt;C++11 引入了 &lt;code&gt;constexpr&lt;/code&gt;，它的字面意思是 &lt;code&gt;constant expression&lt;/code&gt;（常量表达式），用于在编译时计算常量值。与 &lt;code&gt;const&lt;/code&gt; 不同，&lt;code&gt;constexpr&lt;/code&gt; 确保一个变量或者函数的值是在编译时已知的，编译器会在编译时对其进行求值。&lt;/p&gt;
&lt;p&gt;通过使用 &lt;code&gt;constexpr&lt;/code&gt;，我们可以定义编译时常量，并且 &lt;code&gt;constexpr&lt;/code&gt; 函数在某些情况下也能够在编译期计算结果。&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;constexpr&lt;/code&gt; 重写上述代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;helloworld1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;helloworld&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 编译期计算&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 编译期计算&lt;/span&gt;

&lt;span class="c1"&gt;// 编译期初始化数组&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arr_pow_of_2&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_1"&gt;常量表达式函数&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;constexpr&lt;/code&gt; 不仅可以修饰变量，还可以修饰函数。&lt;code&gt;constexpr&lt;/code&gt; 函数的特性是，若输入的参数是编译时常量，那么它的返回值也是一个编译时常量。&lt;/p&gt;
&lt;p&gt;以下是一个计算 Fibonacci 数列的示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1L&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 编译时常量&lt;/span&gt;

&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 在编译期计算 Fibonacci 数列&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;123456&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在这段代码中，&lt;code&gt;fib&lt;/code&gt; 函数被标记为 &lt;code&gt;constexpr&lt;/code&gt;，因此当传入常量参数时，编译器会在编译期间计算出 Fibonacci 数列的第 &lt;code&gt;123456&lt;/code&gt; 项。需要注意的是，&lt;code&gt;constexpr&lt;/code&gt; 函数的计算存在一些限制：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;递归深度限制&lt;/strong&gt;：constexpr 函数的递归深度通常受到编译器的限制，如果递归过深，编译器可能会产生错误或警告。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算效率&lt;/strong&gt;：尽管常量表达式函数可以在编译期计算，但对于复杂的运算，可能会增加编译时间，因为编译器需要进行更多的计算。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="constexpr-vs"&gt;constexpr vs 模板元编程&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;constexpr&lt;/code&gt; 函数的使用在某种程度上简化了模板元编程。传统的模板元编程可以实现与 &lt;code&gt;constexpr&lt;/code&gt; 类似的功能，但代码结构通常更加复杂。下面是使用模板元编程计算 Fibonacci 数列的代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1999&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Fibonacci&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Fibonacci&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fibonacci&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Fibonacci&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Fibonacci&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Fibonacci(40): &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fibonacci&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在这个模板元编程示例中，Fibonacci 结构体使用递归模板计算 Fibonacci 数列的第 N 项。这与 &lt;code&gt;constexpr&lt;/code&gt; 函数类似，但模板元编程的语法更加繁琐。&lt;code&gt;constexpr&lt;/code&gt; 的优势在于它能够写出更加接近正常逻辑代码的形式，并且具有更强的表达能力&lt;/p&gt;
&lt;h3 id="c14"&gt;C++14 对常量表达式函数的增强&lt;/h3&gt;
&lt;p&gt;在 C++14 中，常量表达式函数得到了进一步的增强。具体增强包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;支持局部变量&lt;/strong&gt;：&lt;code&gt;constexpr&lt;/code&gt;  函数可以声明和初始化局部变量，但不能声明未初始化的变量、&lt;code&gt;static&lt;/code&gt; 或 &lt;code&gt;thread_local&lt;/code&gt; 变量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持 if 和 switch 语句&lt;/strong&gt;：&lt;code&gt;constexpr&lt;/code&gt; 函数可以使用 &lt;code&gt;if&lt;/code&gt; 和 &lt;code&gt;switch&lt;/code&gt; 语句来控制流程，但不能使用 &lt;code&gt;got&lt;/code&gt;o。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持循环语句&lt;/strong&gt;：&lt;code&gt;constexpr&lt;/code&gt; 函数支持所有类型的循环语句，包括 &lt;code&gt;for&lt;/code&gt;、&lt;code&gt;while&lt;/code&gt; 和 &lt;code&gt;do-while&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;修改生命周期&lt;/strong&gt;：在 constexpr 函数内部，可以修改局部变量和非常量引用参数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值可以是 void&lt;/strong&gt;：&lt;code&gt;constexpr&lt;/code&gt; 函数可以声明返回类型为 &lt;code&gt;void&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_2"&gt;常量表达式与模板函数&lt;/h2&gt;
&lt;p&gt;在 C++11 引入 &lt;code&gt;constexpr&lt;/code&gt; 后，建议在所有需要常量语义的场景中使用 &lt;code&gt;constexpr&lt;/code&gt;。&lt;code&gt;constexpr&lt;/code&gt; 变量和函数作为编译时常量，在模板函数中具有广泛的应用场景，能够显著提升程序的效率和可读性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;square2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;// 计算常量的平方&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;square2_0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;// 计算浮点数的平方&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%lu&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;%.04lf&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;square2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;square2_0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// 输出结果&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;模板函数 &lt;code&gt;square&lt;/code&gt; 使用了 &lt;code&gt;constexpr&lt;/code&gt;，确保在编译时就可以计算结果。对于不同类型的参数（如整数、浮点数），模板会自动进行实例化。&lt;/p&gt;
&lt;p&gt;如果模板参数不是编译期常量，&lt;code&gt;constexpr&lt;/code&gt; 将不会在编译期执行，但函数本身仍然是有效的。&lt;/p&gt;
&lt;h2 id="constexpr_2"&gt;constexpr 函数中的动态内存分配&lt;/h2&gt;
&lt;p&gt;在 C++20 中，&lt;code&gt;constexpr&lt;/code&gt; 函数得到了进一步增强，支持在编译期进行动态内存分配，但仍然存在一些限制。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;std::array&lt;/code&gt; 的所有数据都存储在栈上，而不是堆上。严格的说，&lt;code&gt;std::array&lt;/code&gt;不涉及动态内存分配。所以&lt;code&gt;std::array&lt;/code&gt;可以在&lt;code&gt;constexpr&lt;/code&gt;函数中被初始化、修改并返回。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maxstep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maxstep&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Collatz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maxstep&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Collatz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;而对于&lt;code&gt;std::string&lt;/code&gt;或者&lt;code&gt;std::vector&lt;/code&gt;这种 需要在堆上分配内存的数据结构，我们则不可以在constexpr函数中直接返回。但是可以在constexpr函数中则用其进行计算。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;CountPrimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CountPrimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="constexpr-virtual"&gt;constexpr virtual 函数&lt;/h2&gt;
&lt;p&gt;在 C++20 中，&lt;code&gt;constexpr&lt;/code&gt; 函数可以与 &lt;code&gt;virtual&lt;/code&gt; 关键字结合使用，实现在编译期进行多态求值。&lt;/p&gt;
&lt;p&gt;虚函数的 constexpr 限制：constexpr 虚函数只能在编译期求值，前提是其被调用的具体对象类型是确定的。&lt;/p&gt;
&lt;p&gt;在 constexpr 上下文中调用 virtual 函数时，调用将绑定到具体派生类的实现。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 虚拟 constexpr 函数&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Derived1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Derived2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Calc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Derived1&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// constexpr 中分配内存&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Derived2&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 调用虚函数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 必须释放内存&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Calc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 在编译期计算&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_3"&gt;常量表达式用于模板函数的类型判断&lt;/h2&gt;
&lt;p&gt;在 C++17 中引入的 &lt;code&gt;if constexpr&lt;/code&gt; 提供了一种更加简洁和可读的方式来进行模板元编程的类型判断。根据类型特性，在编译期选择不同的分支路径。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cmath&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;type_traits&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_integral_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 整数类型直接比较&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_floating_point_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fabs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1e-3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 浮点数进行误差比较&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;static_assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_arithmetic_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_pointer_v&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;not supported&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;boolalpha&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0000001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.000002&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0000001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.000002&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在传统C++中，我们常用&lt;code&gt;std::enable_if&lt;/code&gt;来实现类似的功能。但是很明显，语法会显得过于笨重。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;type_traits&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cmath&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// 整数类型&lt;/span&gt;
&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;enable_if&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_integral&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;
&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 浮点类型&lt;/span&gt;
&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;enable_if&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_floating_point&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;
&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;fabs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1e-3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 其他类型&lt;/span&gt;
&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;enable_if&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_integral&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_floating_point&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;
&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;static_assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_arithmetic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_pointer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;not supported&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="kr"&gt;true&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="kr"&gt;false&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="c1"&gt;// 整数&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0000001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.000002&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="kr"&gt;true&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="kr"&gt;false&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// 浮点&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="consteval"&gt;使用&lt;code&gt;consteval&lt;/code&gt;强制使用编译期求值&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;consteval&lt;/code&gt; 是在 C++20 中引入的关键字，用于声明立即函数（immediate function）。立即函数要求在编译时进行求值，不能在运行时调用。&lt;br&gt;
如果调用一个&lt;code&gt;consteval&lt;/code&gt;。如果调用 &lt;code&gt;consteval&lt;/code&gt; 函数时无法在编译期计算，编译器将报错。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;constexpr&lt;/code&gt; 函数在某些情况下可能会退化为运行时调用，&lt;code&gt;consteval&lt;/code&gt; 可以避免这种情况。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// consteval 强制要求在编译时进行计算&lt;/span&gt;
&lt;span class="k"&gt;consteval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// OK：在编译时计算&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Factorial of 5 is: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// int runtime = 5;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// std::cout &amp;lt;&amp;lt; &amp;quot;Factorial of runtime: &amp;quot; &amp;lt;&amp;lt; factorial(runtime) &amp;lt;&amp;lt; std::endl;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 错误：factorial 必须在编译时调用&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="constinit"&gt;使用&lt;code&gt;constinit&lt;/code&gt;显式要求编译时初始化&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;constinit&lt;/code&gt; 关键字用于显式要求全局或静态变量在编译期完成初始化。&lt;br&gt;
如果变量无法在编译时初始化，编译器将报错。&lt;br&gt;
&lt;code&gt;constinit&lt;/code&gt; 不能用于局部变量。&lt;/p&gt;
&lt;p&gt;与 &lt;code&gt;constexpr&lt;/code&gt; 不同，&lt;code&gt;constinit&lt;/code&gt; 变量可以在运行时被修改。&lt;br&gt;
线程安全性：在多线程环境中，&lt;code&gt;constinit&lt;/code&gt; 确保变量在编译期初始化，避免线程安全问题。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// 编译时初始化&lt;/span&gt;
&lt;span class="n"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;constinit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 错误：constinit 变量不能依赖运行时初始化&lt;/span&gt;
&lt;span class="c1"&gt;// constinit int another = global;&lt;/span&gt;

&lt;span class="kr"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 允许在运行时修改&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 错误：constinit 变量不是常量，不能用作数组大小&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// std::array&amp;lt;int, global&amp;gt; arr;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Global value: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_4"&gt;总结&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;constexpr&lt;/code&gt;在多数情况下可以替代&lt;code&gt;const&lt;/code&gt;以表达“编译期常量”的语义，可用于函数、变量、类等场景。constexpr 支持在编译期和运行期进行求值，但在某些情况下可能会退化为运行期求值。&lt;/li&gt;
&lt;li&gt;常量表达式函数 提供了一种更清晰的编译期计算方式，能够在一定程度上取代复杂且晦涩的模板元编程。随着 C++ 标准的演进，&lt;code&gt;constexpr&lt;/code&gt; 函数逐步支持了更复杂的语法和逻辑，例如条件语句、循环语句和局部变量。但对于极端复杂的计算场景，编译期计算可能导致显著的编译时间开销。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;constexpr&lt;/code&gt;可以在模板函数中用于类型判断，通过&lt;code&gt;if constexpr&lt;/code&gt;语法有效地取代&lt;code&gt;std::enable_if&lt;/code&gt;，从而简化模板编程，提高代码的可读性和可维护性。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;constexpr&lt;/code&gt;函数的隐式退化风险：在某些场景下，&lt;code&gt;constexpr&lt;/code&gt; 函数可能在运行时执行。若需要严格保证仅在编译期求值，可以使用 &lt;code&gt;consteval&lt;/code&gt; 来强制进行编译期求值，避免不必要的运行时开销。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;constinit&lt;/code&gt;提供了一种显式要求变量在编译时完成初始化的机制，适用于非&lt;code&gt;constexpr&lt;/code&gt;变量。这在全局和静态变量的初始化中尤为有用，同时也保证了多线程环境下的初始化安全性。&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="cpp"/><category term="modern cpp"/></entry><entry><title>CPU缓存一致性与内存一致性（第二部分-内存一致性）</title><link href="https://wizmann.top/cache-coherence-and-memory-order-2.html" rel="alternate"/><published>2024-09-01T00:24:00+08:00</published><updated>2024-09-01T00:24:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2024-09-01:/cache-coherence-and-memory-order-2.html</id><summary type="html">&lt;h2 id="_1"&gt;缓存一致性与内存一致性&lt;/h2&gt;
&lt;p&gt;缓存一致性和内存一致性是多处理器系统中的两个不同概念，它们解决的是不同类型的内存 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;缓存一致性与内存一致性&lt;/h2&gt;
&lt;p&gt;缓存一致性和内存一致性是多处理器系统中的两个不同概念，它们解决的是不同类型的内存访问问题。&lt;/p&gt;
&lt;p&gt;缓存一致性协议（如 MESI 协议）用于解决多个处理器对相同内存位置进行访问和修改时的数据一致性问题。它确保各处理器的缓存中针对同一内存地址的副本保持一致，避免因缓存不同步而导致的数据错误。&lt;/p&gt;
&lt;p&gt;而内存一致性关注的是处理器对多个不同内存地址的访问顺序问题。当不同处理器的内存访问顺序与程序代码中的预期顺序不一致时，就会引发内存一致性问题。它要求各处理器按照一定的规则访问内存，以保持程序逻辑的正确性。&lt;/p&gt;
&lt;p&gt;简而言之，缓存一致性解决的是同一内存位置的数据同步问题，而内存一致性则涉及多个内存位置的访问顺序问题。&lt;/p&gt;
&lt;h2 id="_2"&gt;内存乱序访问产生的原因&lt;/h2&gt;
&lt;p&gt;内存乱序访问的原因可以从两个方面来理解：程序顺序（Program Order, PO）和内存顺序（Memory Order, MO）。程序顺序是指程序代码中编写的内存访问序列，反映了程序员预期的指令执行顺序。按照程序顺序，指令应该依次被执行，以确保程序的逻辑正确性。然而，在实际执行中，系统中可能存在一种不同的顺序，即内存顺序。&lt;/p&gt;
&lt;p&gt;内存顺序是指系统中所有处理器对内存操作达成一致的访问顺序。由于现代计算机系统通常由多个处理器共同操作共享内存，为了提高整体性能，这些处理器可能会对内存操作进行重排序，从而产生与程序顺序不一致的内存顺序。&lt;/p&gt;
&lt;p&gt;这种内存乱序访问的现象主要是为了优化程序执行效率，通常发生在两个阶段：编译阶段和执行阶段。在编译阶段，编译器会对代码进行优化，这可能会导致指令的重排序，以提高执行效率。在执行阶段，多个 CPU 之间的交互也会引起内存访问顺序的不一致。&lt;/p&gt;
&lt;p&gt;在单处理器系统中，CPU 对指令的乱序执行和重排对于程序员来说是透明的，即程序的执行结果与顺序执行的结果是一致的。然而，在多处理器系统中，不同的处理器（或称为观察者）可能会观察到不同的内存执行顺序，这与指令的实际执行顺序不完全一致，从而导致潜在的同步问题和数据不一致性。&lt;/p&gt;
&lt;h2 id="_3"&gt;几种常见的一致性模型&lt;/h2&gt;
&lt;p&gt;在多处理器系统中，内存一致性模型决定了不同处理器之间如何观察和执行内存操作的顺序。以下介绍几种常见的一致性模型：&lt;/p&gt;
&lt;h3 id="sequential-consistency-sc"&gt;顺序一致性模型（Sequential Consistency, SC）&lt;/h3&gt;
&lt;p&gt;顺序一致性模型的概念最早由 Leslie Lamport 在 1979 年的论文《如何构建正确执行多处理程序的多处理计算机》中提出。按照他的定义：&lt;/p&gt;
&lt;p&gt;任何执行的结果都与所有处理器的操作按照某种顺序依次执行的结果相同，并且每个处理器的操作在这个顺序中出现的顺序与其程序中指定的顺序一致。满足这一条件的多处理器被称为顺序一致性系统。&lt;/p&gt;
&lt;p&gt;顺序一致性模型保证了每个加载（Load）和存储（Store）指令按照程序中指定的严格顺序执行，确保了“读-&amp;gt;读”、“读-&amp;gt;写”、“写-&amp;gt;写”以及“写-&amp;gt;读”四种操作的顺序。这种模型提供了最强的内存一致性保证，但代价是较低的执行效率，因为它不允许任何形式的指令重排序。&lt;/p&gt;
&lt;h3 id="processor-consistency-pc"&gt;处理器一致性模型（Processor Consistency, PC)&lt;/h3&gt;
&lt;p&gt;处理器一致性模型是顺序一致性模型的弱化版本，它放宽了对“写-&amp;gt;读”操作顺序的要求。该模型允许处理器在读取时从存储缓冲区（Store Buffer）中获取一个尚未写入缓存的值，即使这个值还没有被其他处理器看到。x86-64 实现的全序写（Total Store Ordering, TSO）模型就是处理器一致性的一种。TSO 允许一定程度的乱序执行，提高了系统的性能，同时仍然提供了较强的一致性保证。&lt;/p&gt;
&lt;h3 id="weak-consistency-wc"&gt;弱一致性模型（Weak Consistency, WC）&lt;/h3&gt;
&lt;p&gt;弱一致性模型进一步弱化了处理器一致性模型的要求，放宽了对“读-&amp;gt;读”、“读-&amp;gt;写”、“写-&amp;gt;写”以及“写-&amp;gt;读”四种操作顺序的约束。为了确保程序执行的正确性，程序员需要在合适的地方显式添加同步操作。在这种模型中，多处理器系统的内存访问满足以下三个条件时称为弱一致性内存访问：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对全局同步变量的访问是顺序一致的&lt;/li&gt;
&lt;li&gt;在一个同步操作（如内存屏障指令）执行之前，所有先前的数据访问必须完成；&lt;/li&gt;
&lt;li&gt;在一个正常的数据访问（如数据访问指令）执行之前，所有先前的同步操作（如内存屏障指令）必须完成。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="release-consistency-rc"&gt;释放一致性模型（Release Consistency, RC）&lt;/h3&gt;
&lt;p&gt;释放一致性模型是在弱一致性模型的基础上引入了“获取”（acquire）和“释放”（release）屏障原语，用于简化共享数据的互斥访问。&lt;/p&gt;
&lt;p&gt;在该模型中，“获取”屏障原语后面的读写操作不能被重排到该屏障之前，“释放”屏障原语前面的读写操作不能被重排到该屏障之后。这种机制能够更高效地管理多处理器系统中的共享数据访问，提高并行性能。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/38b192183bdefe1e658707d505a5263f12e4ba34/wizmann-pic/image_1724584827296_0.png"&gt;&lt;/p&gt;
&lt;p&gt;这些内存一致性模型提供了从严格到宽松的不同选择，适应不同的应用需求和性能要求。选择合适的一致性模型对多处理器系统的设计和优化至关重要。&lt;/p&gt;
&lt;h2 id="_4"&gt;四种内存乱序&lt;/h2&gt;
&lt;p&gt;在多处理器系统中，为了优化性能，处理器可能会对内存操作进行不同类型的乱序执行。这种乱序行为包括四种主要类型，每一种都会以不同的方式影响多线程程序的正确性和一致性。&lt;/p&gt;
&lt;h3 id="loadload"&gt;LoadLoad 乱序&lt;/h3&gt;
&lt;p&gt;LoadLoad 乱序指的是后续的加载（读取）操作可以在先前的加载操作完成之前开始，或者两个加载操作的完成顺序与它们的发起顺序不同。这意味着处理器可能会优先执行后发起的加载操作。这种乱序优化可能有助于提高程序的执行速度，但如果未加以控制，可能会导致某些线程读取到不一致的数据。&lt;/p&gt;
&lt;h3 id="loadstore"&gt;LoadStore 乱序&lt;/h3&gt;
&lt;p&gt;LoadStore 乱序表示一个存储（写入）操作可以在之前发起的加载操作完成之前开始执行，或者写操作可能“超越”读操作。尽管这种优化可以提高处理器的性能，但在多线程程序中可能导致意外的行为。例如，一个线程可能会看到数据被写入之前的状态，导致逻辑错误或数据不一致。&lt;/p&gt;
&lt;h3 id="storeload"&gt;StoreLoad 乱序&lt;/h3&gt;
&lt;p&gt;StoreLoad 乱序是四种乱序类型中对编程模型影响最大的一种。它允许一个加载操作在之前的存储操作完成之前开始，或者读取操作可能看到写操作的结果，即使这个写操作在程序中的顺序上应该发生在读操作之后。这种乱序执行可能导致一个线程读取到另一个线程的“旧”值，而不是最新写入的值，从而引发数据同步问题。&lt;/p&gt;
&lt;h3 id="storestore"&gt;StoreStore 乱序&lt;/h3&gt;
&lt;p&gt;StoreStore 乱序涉及两个连续的存储操作，其中后一个存储操作可以在第一个操作完成之前开始，或者它们的完成顺序与它们被发起的顺序不同。这意味着，后一个写操作的结果可能在前一个写操作的结果对其他处理器可见之前就已经被观察到，从而造成数据顺序的不一致。&lt;/p&gt;
&lt;h3 id="_5"&gt;管理内存乱序的重要性&lt;/h3&gt;
&lt;p&gt;正确管理这些乱序行为对于并发编程至关重要，特别是在设计无锁数据结构和编写多线程程序时。如果不加以控制，这些乱序可能导致数据不一致、难以重现的错误和程序崩溃。为了避免这些问题，现代处理器和编程语言提供了各种内存屏障（Memory Barriers）或内存顺序（Memory Order）指令，确保在关键的程序点上强制执行所需的内存操作顺序。这些机制帮助程序员在优化性能的同时，维护数据的一致性和正确性。&lt;/p&gt;
&lt;h2 id="litmus-x86-tso"&gt;使用Litmus工具分析内存乱序 - 以x86-TSO为例&lt;/h2&gt;
&lt;p&gt;在并发编程中，理解和验证内存模型的行为对于确保程序的正确性至关重要。以 x86 Total Store Order (x86-TSO) 为例，我们可以使用 Litmus 测试工具来分析内存乱序现象，并了解如何通过内存屏障来避免这种情况。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Litmus工具可以在&lt;a href="https://developer.arm.com/herd7"&gt;这里&lt;/a&gt;在线试用，也可以安装到本地环境&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="x86-total-store-order-x86-tso"&gt;x86 Total Store Order (x86-TSO)&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/24-09-01/1725159498577_mem-tso_1723970692408_0.png"&gt;&lt;/p&gt;
&lt;p&gt;在 x86 架构中，Store Buffer（存储缓冲区）用于暂时存放处理器的写操作，而不立即将其写入主存。这种机制提高了处理器的性能，因为它允许处理器在写操作尚未完成时继续执行后续指令。然而，Store Buffer 也导致了某些内存操作的可见性问题，特别是在多处理器环境中。&lt;/p&gt;
&lt;p&gt;x86 Total Store Order (x86-TSO) 模型的特性正是由这种 Store Buffer 机制决定的。由于写操作在 Store Buffer 中暂存，x86-TSO 模型保证了一些关键特性，同时也做出了一些基于性能的妥协：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;写操作顺序一致性：所有写操作按照程序的顺序执行，并对所有处理器可见，即写操作在 Store Buffer 刷新到主存之前，不会被其他处理器看到。&lt;/li&gt;
&lt;li&gt;读操作的自我可见性：处理器可以立即看到自己在 Store Buffer 中的最新写入，即本处理器的读操作可以从 Store Buffer 中读取未提交到主存的值。&lt;/li&gt;
&lt;li&gt;防止某些重排序：为了避免因 Store Buffer 导致的读写乱序，x86-TSO 禁止写操作与其后的读操作重排序，确保读写顺序一致。&lt;/li&gt;
&lt;li&gt;允许部分读操作重排序：为了进一步提升性能，处理器允许一些读操作的重排序，但仍然遵循严格的规则以保证程序的正确性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="litmus-x86-storeload"&gt;使用 Litmus 验证 x86 的 StoreLoad 乱序&lt;/h3&gt;
&lt;p&gt;我们可以使用 Litmus 工具来验证在 x86-TSO 内存模型下的 StoreLoad 乱序行为。以下是一个示例代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;X86&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SB&lt;/span&gt;
&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;P0&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;P1&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;MOV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;MOV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EAX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EAX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="ow"&gt;exists&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="n"&gt;EAX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="n"&gt;EAX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在执行该代码后，Litmus 会生成四种可能的结果，分别对应不同的执行顺序。&lt;/p&gt;
&lt;h4 id="1"&gt;结果1&lt;/h4&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/24-09-01/1725159921512_graph3_1725095884015_0.png"&gt;&lt;/p&gt;
&lt;p&gt;在结果1中，程序按照严格的顺序执行，每个处理器的内存操作顺序与程序中的顺序一致。&lt;/p&gt;
&lt;p&gt;图中，po（Program Order）表示程序顺序，rf（Reads-From）表示每个读操作从哪个写操作中读取的值。由于内存操作按照预期顺序执行，这种情况没有进一步的乱序行为，因此不需要进一步分析&lt;/p&gt;
&lt;h4 id="23"&gt;结果2/结果3&lt;/h4&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/24-09-01/1725160079968_graph1_1725098202554_0.png"&gt;&lt;br&gt;
&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/24-09-01/1725160089725_graph2_1725098310293_0.png"&gt;&lt;/p&gt;
&lt;p&gt;结果2和结果3是对称的，表示在执行过程中，内存的读取发生了“乱序”，即读取操作被重排到了写入操作之前。在 Litmus 中，这种情况被标记为 fr（From-Read），表示一个写操作覆盖了一个读操作所读取的值，即这个写操作发生在读操作之后。这种“写读”操作的乱序可能是由于执行顺序的不同，也可能是内存模型的顺序造成的。&lt;/p&gt;
&lt;h4 id="4"&gt;结果4&lt;/h4&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/24-09-01/1725160171251_graph0_1725099005660_0.png"&gt;&lt;/p&gt;
&lt;p&gt;结果4表示两个线程各自都发生了 fr，即每个线程的读操作都被重排到了写操作之前。这种情况展示了最复杂的乱序行为，其中两个线程的读操作分别“超越”了各自的写操作。&lt;/p&gt;
&lt;h3 id="mfence"&gt;使用内存屏障（MFENCE）指令避免内存乱序&lt;/h3&gt;
&lt;p&gt;为了避免这种乱序情况，可以使用 MFENCE（Memory Fence） 指令。在 x86 架构中，MFENCE 是一种强制内存屏障，确保所有在 MFENCE 之前的内存操作（无论是读还是写）在所有 MFENCE 之后的内存操作之前完成。这意味着在同一线程内，MFENCE 保证了内存操作的顺序性：MFENCE 之前的操作对其他线程可见后，才可以执行 MFENCE 之后的操作。&lt;/p&gt;
&lt;p&gt;我们可以将 Litmus 代码修改如下，以插入 MFENCE 指令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;X86&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SB&lt;/span&gt;
&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;P0&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;P1&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;MOV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;MFENCE&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MFENCE&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;MOV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EAX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EAX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="ow"&gt;exists&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="n"&gt;EAX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="n"&gt;EAX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在加入内存屏障后，我们看到结果1到结果3依然会出现，但结果4因 MFENCE 的存在而被避免。通过 MFENCE 确保了内存操作的顺序性，从而防止了某些类型的内存乱序，保证了多线程程序的正确性和一致性。&lt;/p&gt;
&lt;h2 id="_6"&gt;接下来&amp;hellip;&lt;/h2&gt;
&lt;p&gt;下一篇文章中，我们会介绍C++的内存顺序模型，并且分析更复杂的内存乱序问题&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://colobu.com/2021/06/30/hwmm/"&gt;硬件内存模型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://book.douban.com/subject/36240082/"&gt;RISC-V体系结构编程与实践&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.microsoft.com/en-us/research/publication/make-multiprocessor-computer-correctly-executes-multiprocess-programs/"&gt;How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dl.acm.org/doi/10.1145/285930.285991"&gt;Memory access buffering in multiprocessors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cl.cam.ac.uk/~pes20/weakmemory/tacas11.pdf"&gt;Litmus: Running Tests Against Hardware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.arm.com/herd7"&gt;Herd7 Simulator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/0voice/dpdk_engineer_manual/blob/main/%E5%A4%A7%E4%BC%9APPT/NA%202021-Memory%20Model%20Simulation%20Tool%20-%20Herd7.pdf"&gt;Memory Model Simulation Tool - Herd7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/how-to-use-the-memory-model-tool#intuitively"&gt;A working example of how to use the herd7 Memory Model Tool&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="alert alert-info" role="alert"&gt;本文大（划掉）部分内容由ChatGPT4生成&lt;/div&gt;</content><category term="Blog"/><category term="cpp"/><category term="memory-barrier"/><category term="multithread"/><category term="litmus"/><category term="herd7"/></entry><entry><title>利用凸组合求解最优值（AtCoder abc356_g Freestyle 题解）</title><link href="https://wizmann.top/AtCoder-abc356g-solution.html" rel="alternate"/><published>2024-06-15T00:00:00+08:00</published><updated>2024-06-15T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2024-06-15:/AtCoder-abc356g-solution.html</id><summary type="html">&lt;ul&gt;
&lt;li&gt;
&lt;h2 id="_1"&gt;题目大意&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;我们已经学会了 &lt;strong&gt;N&lt;/strong&gt; 种不同的游泳技术。对于每种技术 &lt;span class="math"&gt;\(i\)&lt;/span&gt; ，每秒前进 &lt;span class="math"&gt;\(A_{i}\)&lt;/span&gt; 米，并消耗 &lt;span class="math"&gt;\(B_{i}\)&lt;/span&gt; 单位的体力。注意，我们可以 …&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;script type='text/javascript'&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;
&lt;h2 id="_1"&gt;题目大意&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;我们已经学会了 &lt;strong&gt;N&lt;/strong&gt; 种不同的游泳技术。对于每种技术 &lt;span class="math"&gt;\(i\)&lt;/span&gt; ，每秒前进 &lt;span class="math"&gt;\(A_{i}\)&lt;/span&gt; 米，并消耗 &lt;span class="math"&gt;\(B_{i}\)&lt;/span&gt; 单位的体力。注意，我们可以任意调整每种技术的使用时长 &lt;span class="math"&gt;\(t_i\)&lt;/span&gt; ，其中 &lt;span class="math"&gt;\(t_i\)&lt;/span&gt; 是一个实数&lt;/li&gt;
&lt;li&gt;现在，我们面临 &lt;span class="math"&gt;\(Q\)&lt;/span&gt; 次询问，每次询问指定距离终点的距离 &lt;span class="math"&gt;\(C_j\)&lt;/span&gt; 和体力限制 &lt;span class="math"&gt;\(D_j\)&lt;/span&gt; 。我们需要确定是否在体力限制下到达终点。如果可以，求出所需的最短时间。&lt;/li&gt;
&lt;li&gt;（符号使用与原题略有差异）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据规模&lt;/strong&gt;：&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(1 &amp;lt;= N, Q &amp;lt;= 2 \times 10^5\)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(1 &amp;lt;= A_i, B_i, C_j, D_j &amp;lt;= 10^9\)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_2"&gt;题目分析&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;鉴于数据规模庞大，并且时间 &lt;span class="math"&gt;\(t_i\)&lt;/span&gt; 是实数，传统的动态规划方法不适用。在处理每次询问时，我们需要同时考虑距离、体力和时间三个变量。一个有效的方法是转化这些变量为单位时间内的距离（即速度）和单位时间内的体力消耗。如果单位时间内的距离大于单位时间内的体力消耗，那么理论上我们可以到达终点。接下来的目标是在所有可能的情况中找到最大的速度，作为最终答案。&lt;br&gt;
  以两种游泳技术（N=2）为例进行具体分析。假设在总游泳时间中，技术1和技术2的使用时间比例分别为 &lt;span class="math"&gt;\(p\)&lt;/span&gt; 和 &lt;span class="math"&gt;\(1-p\)&lt;/span&gt; （其中 &lt;span class="math"&gt;\(0 \leq p \leq 1\)&lt;/span&gt; ）。在这种情况下，每秒前进距离为 &lt;span class="math"&gt;\(A_1 \cdot p + A_2 \cdot (1 - p)\)&lt;/span&gt; ，体力消耗为 &lt;span class="math"&gt;\(B_1 \cdot p + B_2 \cdot (1 - p)\)&lt;/span&gt; 。&lt;br&gt;
  从几何角度看，组合这两种游泳技术的速度与体力消耗 &lt;span class="math"&gt;\((A_x, B_x)\)&lt;/span&gt; 为 &lt;span class="math"&gt;\((A_1, B_1) \cdot p\)&lt;/span&gt; 和 &lt;span class="math"&gt;\((A_2, B_2) \cdot (1 - p)\)&lt;/span&gt; 的向量和，其可能的取值位于以 &lt;span class="math"&gt;\((A_1, B_1)\)&lt;/span&gt; 和 &lt;span class="math"&gt;\((A_2, B_2)\)&lt;/span&gt; 为端点的线段上的任意一点。&lt;br&gt;
  对于具体询问 &lt;span class="math"&gt;\((C_i, D_i)\)&lt;/span&gt; ，为了确保“在到达终点之前不能耗尽体力”，我们需要找到的点必须位于斜率为 &lt;span class="math"&gt;\(D_i/C_i\)&lt;/span&gt; 的射线与x轴之间的夹角内。通过这种方式，我们可以确定是否有可能在给定的体力限制下完成指定的距离，并找到速度最快的点。  &lt;/li&gt;
&lt;li&gt;&lt;img alt="下载_1718003803558_0.png" src="https://raw.githubusercontent.com/Wizmann/assets/965294986c47c3153fe9cd4e831748903ba224ef/wizmann-pic/24-06-15/%E4%B8%8B%E8%BD%BD_1718003803558_0.png"&gt;&lt;/li&gt;
&lt;li&gt;对于多种游泳技术的组合，情况会更复杂一些。我们将所有游泳技术视为一组向量 &lt;span class="math"&gt;\((A_1, B_1), (A_2, B_2), \ldots, (A_n, B_n)\)&lt;/span&gt; 和一组对应的权重 &lt;span class="math"&gt;\(p_1, p_2, \ldots, p_n\)&lt;/span&gt; ，其中 &lt;span class="math"&gt;\(\sum_{i=1}^n p_i = 1\)&lt;/span&gt; 并且每个 &lt;span class="math"&gt;\(p_i \geq 0\)&lt;/span&gt; ，那么这些向量的加权和 &lt;span class="math"&gt;\(\sum_{i=1}^n p_i (A_i, B_i)\)&lt;/span&gt; 定义了一个在二维空间中的凸多边形，称为这些向量的凸包。&lt;/li&gt;
&lt;li&gt;我们可以用稍微详细一点的数学来解释这一过程：&lt;ul&gt;
&lt;li&gt;
&lt;h3 id="_3"&gt;向量的线性组合&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;首先，定义向量 &lt;span class="math"&gt;\(\mathbf{v}_1, \mathbf{v}_2, \ldots, \mathbf{v}_n\)&lt;/span&gt; 在二维空间中的位置。每个向量 &lt;span class="math"&gt;\(\mathbf{v}_i\)&lt;/span&gt; 可以表示为从原点到点 &lt;span class="math"&gt;\((x_i, y_i)\)&lt;/span&gt; 的箭头。&lt;br&gt;
  当我们考虑这些向量的线性组合时： &lt;span class="math"&gt;\(\sum_{i=1}^n \lambda_i \mathbf{v}_i\)&lt;/span&gt;&lt;br&gt;
  其中，每个 &lt;span class="math"&gt;\(\lambda_i\)&lt;/span&gt; 是一个实数系数，我们实际上在描述一个新向量，这个向量是通过在每个原向量上“拉伸”或“压缩”（取决于 &lt;span class="math"&gt;\(\lambda_i\)&lt;/span&gt; 的正负和大小），然后将结果相加得到的。这种线性组合在几何上定义了一个点的集合。  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_4"&gt;凸组合与凸多边形&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;当这些系数 &lt;span class="math"&gt;\(\lambda_i\)&lt;/span&gt; 都非负且和为1（即 &lt;span class="math"&gt;\(\lambda_i \geq 0\)&lt;/span&gt; 且 &lt;span class="math"&gt;\(\sum_{i=1}^n \lambda_i = 1\)&lt;/span&gt; ），我们称这样的线性组合为&lt;strong&gt;凸组合&lt;/strong&gt;。凸组合具有重要的几何特性：它定义的点一定位于这些向量端点所形成的凸多边形内部或边界上。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_5"&gt;凸多边形的形成&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;边界的构成&lt;/strong&gt;：如果你只考虑两个向量 &lt;span class="math"&gt;\(\mathbf{v}_1\)&lt;/span&gt; 和 &lt;span class="math"&gt;\(\mathbf{v}_2\)&lt;/span&gt; ，那么它们的凸组合会形成一条连接两点 &lt;span class="math"&gt;\((x_1, y_1)\)&lt;/span&gt; 和 &lt;span class="math"&gt;\((x_2, y_2)\)&lt;/span&gt; 的线段。这条线段是直线，因为所有的组合点都直接通过两点间的直线路径互相连结。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;扩展到多个向量&lt;/strong&gt;：当你有三个或更多向量时，通过考虑任意两个向量的所有凸组合（即所有可能的线段），然后再将这些线段的结果进行组合，最终你将覆盖一个多边形区域。这个区域是由最外围的向量点定义的，这些点在几何上构成了凸多边形的顶点。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;数学描述&lt;/strong&gt;：在数学上，这个区域可以看作是所有可能的 &lt;span class="math"&gt;\(\lambda_i\)&lt;/span&gt; 值（符合凸组合条件）下的 &lt;span class="math"&gt;\(\sum_{i=1}^n \lambda_i \mathbf{v}_i\)&lt;/span&gt; 的集合。由于每个 &lt;span class="math"&gt;\(\lambda_i\)&lt;/span&gt; 都保证非负且和为1，凸多边形的任意内部或边界点都可以通过这样的组合表示，且不会有任何点“凸出”于这个定义的多边形之外，这正是凸性质的体现。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;类似于仅涉及两个点的简单情况，为了解决问题，我们需要找到凸多边形内与 &lt;span class="math"&gt;\(x\)&lt;/span&gt; 轴之间斜率为 &lt;span class="math"&gt;\(D_i/C_i\)&lt;/span&gt; 的射线包围的区域（即凸包中的深色部分）。我们进一步需要找出该部分中在 &lt;span class="math"&gt;\(x\)&lt;/span&gt; 轴上取得最大值的点。&lt;/li&gt;
&lt;li&gt;&lt;img alt="geogebra-export.png" src="https://raw.githubusercontent.com/Wizmann/assets/965294986c47c3153fe9cd4e831748903ba224ef/wizmann-pic/24-06-15/geogebra-export_1718034870873_0.png"&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="-"&gt;代码实现 - 并不高效&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id="_6"&gt;实现步骤&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;求出所有 &lt;span class="math"&gt;\((A_i, B_i)\)&lt;/span&gt; 点所构成的凸包&lt;/li&gt;
&lt;li&gt;对于每一个查询Q，从零点画出斜率为 &lt;span class="math"&gt;\(D_i / C_i\)&lt;/span&gt; 的射线&lt;/li&gt;
&lt;li&gt;如果凸包位于射线的“上方”，则没有满足条件的情况，返回-1&lt;/li&gt;
&lt;li&gt;如果凸包位于射线的“下方”或与射线相交，则需要找到凸包在射线“下方” &lt;span class="math"&gt;\(B_i\)&lt;/span&gt; 值最大的点。意味着这个组合可以成功到达终点，并且平均速度最快&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_7"&gt;复杂度分析&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;对于每一次查询，我们都要遍历凸包的所有边（即“凸包壳”）与射线的交点。时间复杂度 &lt;span class="math"&gt;\(O(n)\)&lt;/span&gt; 。&lt;/li&gt;
&lt;li&gt;对于所有查询，时间复杂度为 &lt;span class="math"&gt;\(O(q * n)\)&lt;/span&gt; ，明显是会超时的。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_8"&gt;优化的可能性&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;易知，并不是凸包的所有部分都能得出最优解。与原点连线斜率越小的点，其“性价比”越高，即在消耗更少的体力的同时，可以游更远的距离。&lt;br&gt;
  同时，如果凸包内部的某一个点满足条件，则总有位于凸包壳上面的另一个点与它更优。同样，如果凸包壳上有两个点的斜率相同，那么 &lt;span class="math"&gt;\(B_i\)&lt;/span&gt; 值更大的点是更优的。&lt;br&gt;
  所以优化的目标在于找到一系列凸包壳，使其可以只保留最优解所在的边，并且排除所有非最优的情况。&lt;br&gt;
  我们可以从“性价比”最好的点开始，因为对于一个查询，如果所需要的“性价比”高于我们所有的选项，那么一定没有解。&lt;br&gt;
  然后我们逆时针遍历所有点，直到找到 &lt;span class="math"&gt;\(B_i\)&lt;/span&gt; 值最大的点，因为对于一个查询，在满足“性价比”的情况下，这是我们能给出的，消耗时间最小的答案。  &lt;/li&gt;
&lt;li&gt;
&lt;h3 id="1"&gt;实现方案1:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;我们可以使用凸包算法，找到凸包壳，按照上文所述的方法，找到斜率最小（所谓“性价比最高”）的点，然后逆时针遍历到 &lt;span class="math"&gt;\(B_i\)&lt;/span&gt; 最大的点。这些点必然以斜率从小到大排序。&lt;br&gt;
  对于一个查询 &lt;span class="math"&gt;\((C_i, D_i)\)&lt;/span&gt; ，我们将其视为斜率为 &lt;span class="math"&gt;\(D_i / C_i\)&lt;/span&gt; 的射线。我们使用二分法，找到与该射线相交的凸包壳边。再通过联立方程方法找到其交点 &lt;span class="math"&gt;\((A_x, B_x)\)&lt;/span&gt; ，其中 &lt;span class="math"&gt;\(A_x\)&lt;/span&gt; 即为满足查询条件的最大游泳速度。  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="2"&gt;实现方案2：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;方案2与方案1类似，只是在查找凸包的时候，加入点 &lt;span class="math"&gt;\((0, 0)\)&lt;/span&gt; 与点 &lt;span class="math"&gt;\((max(A_i), INF)\)&lt;/span&gt; 。如下图所示，加入这两个点之后，非最优解的点都被包含在了凸包（蓝色）内部。我们在找到凸包之后，将加入的点删除，并按方案1的方法排序。后续再进行二分，以及求交点等操作。&lt;/li&gt;
&lt;li&gt;&lt;img alt="image.png" src="https://raw.githubusercontent.com/Wizmann/assets/965294986c47c3153fe9cd4e831748903ba224ef/wizmann-pic/24-06-15/image_1718464319087_0.png"&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_9"&gt;代码实现&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://atcoder.jp/contests/abc356/submissions/54463383"&gt;我写的&lt;/a&gt; （抄了别人的凸包算法）&lt;/li&gt;
&lt;li&gt;&lt;a href="https://atcoder.jp/contests/abc356/editorial/10145"&gt;官方题解&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_10"&gt;感悟&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;别调计算几何，会变的不幸（&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Blog"/><category term="AtCoder"/><category term="Solution"/><category term="Computational geometry"/><category term="geometry"/></entry><entry><title>实现一个无锁消息队列（续与勘误）</title><link href="https://wizmann.top/implement-non-blocking-queue-2.html" rel="alternate"/><published>2024-04-14T00:00:00+08:00</published><updated>2024-04-14T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2024-04-14:/implement-non-blocking-queue-2.html</id><summary type="html">&lt;ul&gt;
&lt;li&gt;本文内容主要参考自&lt;a href="https://people.cs.pitt.edu/~jacklange/teaching/cs2510-f17/implementing_lock_free.pdf"&gt;Implementing Lock-Free Queue&lt;/a&gt;一文（以下简称“原论文”）&lt;/li&gt;
&lt;li&gt;是对&lt;a href="https://wizmann.top/implement-non-blocking-queue.html"&gt;实现一个无锁消息队列&lt;/a&gt;一文的内容进行补充&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="tldr"&gt;TL；DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;尽管&lt;a href="https://wizmann.top/implement-non-blocking-queue.html"&gt;实现一个 …&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;本文内容主要参考自&lt;a href="https://people.cs.pitt.edu/~jacklange/teaching/cs2510-f17/implementing_lock_free.pdf"&gt;Implementing Lock-Free Queue&lt;/a&gt;一文（以下简称“原论文”）&lt;/li&gt;
&lt;li&gt;是对&lt;a href="https://wizmann.top/implement-non-blocking-queue.html"&gt;实现一个无锁消息队列&lt;/a&gt;一文的内容进行补充&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="tldr"&gt;TL；DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;尽管&lt;a href="https://wizmann.top/implement-non-blocking-queue.html"&gt;实现一个无锁消息队列&lt;/a&gt;一文中的实现是正确的，但是忽略了“非阻塞性”&lt;ul&gt;
&lt;li&gt;例如，当任一插入操作被阻塞，则其它插入操作均会陷入忙等待&lt;/li&gt;
&lt;li&gt;此实现与&lt;a href="https://dl.acm.org/doi/pdf/10.5555/110382.110466"&gt;A simple and correct shared-queue algorithm using Compare-and-Swap&lt;/a&gt;的实现基本一致&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;对于一个支持并发的数据结构，理应同时具备非阻塞性和无等待性&lt;ul&gt;
&lt;li&gt;非阻塞性（non-blocking）：无论是由于CPU调度或其他外部因素，数据结构的操作不能被中断或延迟&lt;/li&gt;
&lt;li&gt;无等待性（wait-free)：保证没有任何线程会遭受饥饿状态&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;前一篇博文对其它实现的质疑，主要在于ABA问题，但这个问题是Compare&amp;amp;Swap所特有的，需要特定的实现来规避&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_1"&gt;理论基础&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;我们的目标是实现一个支持并发enqueue/deque的队列&lt;/li&gt;
&lt;li&gt;对于这样的数据结构，有两个重要的特性&lt;ul&gt;
&lt;li&gt;非阻塞性（non-blocking）&lt;ul&gt;
&lt;li&gt;对于每一个执行线程，所有的操作将会在有限的次数内完成&lt;/li&gt;
&lt;li&gt;无论本线程或其它线程在执行过程中因其它原因（如CPU调度）执行过缓，或者被中断&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;无等待性（wait-free)&lt;ul&gt;
&lt;li&gt;没有线程会饥饿&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;基于锁的数据结构不符合上述特性，因为持有锁的线程可能会无限期地阻塞所有操作&lt;/li&gt;
&lt;li&gt;“线性一致性”(Linearizability) —— 更强的正确性&lt;ul&gt;
&lt;li&gt;非并发操作应当按照它们的逻辑顺序执行，以保证操作的正确性，而并发操作则可以按任意顺序进行&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Fetch&amp;amp;Add&amp;rdquo; 与 &amp;ldquo;Compare&amp;amp;Swap&amp;rdquo;&lt;ul&gt;
&lt;li&gt;常用的原子操作，这里不做赘述&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_2"&gt;基于链表的无锁队列实现&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;略，参考原论文与&lt;a href="https://coolshell.cn/articles/8239.html"&gt;无锁队列的实现&lt;/a&gt;一文&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_3"&gt;基于数组的无锁队列实现&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;略，参考原论文与&lt;a href="https://coolshell.cn/articles/8239.html"&gt;无锁队列的实现&lt;/a&gt;一文&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="aba"&gt;ABA问题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Compare&amp;amp;Swap操作确保了值修改的原子性。指针作为值的一种，代表着某个内存地址，但Compare&amp;amp;Swap对指针的操作无法保证其指向的内存内容不被修改&lt;/li&gt;
&lt;li&gt;考虑到可能释放旧内存后再申请新内存，这两块内存虽逻辑不同却可能拥有同一地址，这对Compare&amp;amp;Swap操作造成了困扰&lt;/li&gt;
&lt;li&gt;解决方案是为指针加入引用计数（ref count），以确保内存在可访问时不会被释放或重用&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_4"&gt;性能对比&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;上面我们已经提到，&lt;a href="https://dl.acm.org/doi/pdf/10.5555/110382.110466"&gt;A simple and correct shared-queue algorithm using Compare-and-Swap&lt;/a&gt;一文中的方法缺少了“非阻塞性”，，但其性能与原论文中的实现十分接近&lt;/li&gt;
&lt;li&gt;但是在原理上，“非阻塞性”实现可以避免意外的线程停止或延迟&lt;/li&gt;
&lt;li&gt;疑问：是否会在P99级别的Latency上才会体现出明显的差异？&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_5"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://people.cs.pitt.edu/~jacklange/teaching/cs2510-f17/implementing_lock_free.pdf"&gt;Implementing Lock-Free Queue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dl.acm.org/doi/pdf/10.5555/110382.110466"&gt;A simple and correct shared-queue algorithm using Compare-and-Swap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cs.nyu.edu/~wies/teaching/cso-fa19/class27_concurrency.pdf"&gt;Concurrency – Correctness of Concurrent Objects&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_6"&gt;后续&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf"&gt;Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zhuanlan.zhihu.com/p/690872647"&gt;C++ 单生产者&amp;amp;单消费者 无锁队列&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=K3P_Lmq6pw0&amp;amp;ab_channel=CppCon"&gt;Single Producer Single Consumer Lock-free FIFO From the Ground Up - Charles Frasch - CppCon 2023&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="alert alert-info" role="alert"&gt;本文大（划掉）部分内容由ChatGPT4生成&lt;/div&gt;</content><category term="Blog"/><category term="multi-thread"/><category term="cas"/><category term="cmpxchg"/><category term="non-blocking"/><category term="wait-free"/></entry><entry><title>CPU缓存一致性与内存一致性（第一部分-MESI协议）</title><link href="https://wizmann.top/cache-coherence-and-memory-order.html" rel="alternate"/><published>2024-03-18T23:21:35+08:00</published><updated>2024-03-18T23:21:35+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2024-03-18:/cache-coherence-and-memory-order.html</id><summary type="html">&lt;p&gt;在对称多处理系统（Symmetric Multiprocessing, SMP）中，一个变量（或内存位置）可以同时存在于多个CPU的缓存行中。为了提供完美的用户级抽象，任何对一个或多 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;在对称多处理系统（Symmetric Multiprocessing, SMP）中，一个变量（或内存位置）可以同时存在于多个CPU的缓存行中。为了提供完美的用户级抽象，任何对一个或多个变量的修改都应该被强制同步，以确保其它CPU的缓存得到更新。&lt;br&gt;
然而，在实现上，由于CPU之间通常通过总线互联，它们不能同时对多个缓存进行写操作。&lt;/p&gt;
&lt;h3 id="_1"&gt;缓存一致性&lt;/h3&gt;
&lt;p&gt;缓存一致性是指在一个多处理器系统中，确保当某个处理器修改了存储在共享资源（如主内存或缓存中的数据）时，其他处理器能够访问到最新的数据版本，从而保证数据的一致性。&lt;/p&gt;
&lt;p&gt;为了达到这一目标，缓存一致性机制必须处理两个主要问题：写传播（Write Propagation）和事务串行化（Transaction Serialization）。&lt;/p&gt;
&lt;p&gt;写传播确保一个处理器核心的写操作能被传播并被其他处理器核心所见。而事务串行化则确保所有处理器核心的写操作按照一定的顺序执行，对所有处理器核心而言这个顺序是一致的。这两个机制共同工作，确保了即使多个CPU可能并发地修改同一份数据，它们也能看到一致的数据视图。&lt;/p&gt;
&lt;h3 id="mesi"&gt;MESI协议&lt;/h3&gt;
&lt;p&gt;为了实现缓存一致性，多种协议和机制被设计出来，其中MESI协议是最广泛使用的一种机制。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;实际上，AMD处理器使用的是MOESI协议，Intel处理器使用的是MESIF协议。这两种协议都是MESI协议的变种。这里不展开讨论。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;MESI 协议通过定义缓存行的四种状态——修改（Modified）、独占（Exclusive）、共享（Shared）和无效（Invalid），管理多个处理器缓存之间的一致性。状态之间的转换受到缓存协议控制，以确保数据的一致性和同步。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;独占（Exclusive, E）：缓存行仅存在于当前缓存中，并且是干净的（即缓存数据与主存数据一致）。当其他缓存尝试读取该数据时，状态转变为共享；当前缓存写入数据时，转变为已修改状态&lt;/li&gt;
&lt;li&gt;共享（Shared, S）：缓存行同时存在于其他缓存中，并且是干净的。该缓存行可以在任意时刻被抛弃&lt;/li&gt;
&lt;li&gt;已修改（Modified, M）：缓存行的数据是“脏”的（即与主存的值不同）。如果其他 CPU 核心需要读取这块数据，该缓存行必须先回写到主存，然后状态转变为共享&lt;/li&gt;
&lt;li&gt;无效（Invalid, I）：表示该缓存行无效，即为空。上文提到的缓存策略会优先填充无效行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简单来说，MESI的设计目标在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;防止多个处理器核心同时对共享数据进行修改。任何需要修改共享数据的核心都会先发出RFO（Read For Ownership）请求来获取该缓存块的所有权，并使其他处理器核心中的相应缓存块变为无效。&lt;/li&gt;
&lt;li&gt;通过推迟写回操作来减少对内存的频繁修改，确保只有在必要时才将缓存中的更改写回内存。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="mesi_1"&gt;MESI 的状态转移&lt;/h3&gt;
&lt;p&gt;MESI 协议的状态转移如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/24-03-31/1711876193915_Diagrama_MESI.gif"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从无效（I）到独占（E）：当 CPU 需要写入一个缓存行而该行当前状态为无效时，如果其他 CPU 缓存中没有该缓存行的副本，该行状态变为独占。这表明当前 CPU 缓存中的数据是最新的，且没有其他副本存在&lt;/li&gt;
&lt;li&gt;从无效（I）到共享（S）：当 CPU 需要读取一个缓存行而该行当前状态为无效时，如果其他 CPU 缓存中存在该缓存行的副本，则该行状态变为共享&lt;/li&gt;
&lt;li&gt;从共享（S）到独占（E）：当一个 CPU 想要写入一个处于共享状态的缓存行时，必须首先获取其他所有 CPU 上该缓存行的独占访问权，如果成功，该缓存行状态变为独占&lt;/li&gt;
&lt;li&gt;从独占（E）到修改（M）：当 CPU 对处于独占状态的缓存行进行写操作时，该缓存行状态变为修改。这表示数据已被当前 CPU 修改，且与主存不同步&lt;/li&gt;
&lt;li&gt;从修改（M）到共享（S）：当其他 CPU 请求读取处于修改状态的缓存行时，当前 CPU 必须将该缓存行的数据写回主存，并将缓存行状态改为共享，以便其他 CPU 可以读取最新数。&lt;/li&gt;
&lt;li&gt;从任何状态到无效（I）：当 CPU 接收到其他 CPU 发出的无效化请求时，如果当前 CPU 缓存中有该缓存行的副本，不论它处于何种状态，都必须将其标记为无效。这通常发生在其他 CPU 想要写入同一缓存行的情况下&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;可以使用这个&lt;a href="https://www.scss.tcd.ie/Jeremy.Jones/VivioJS/caches/MESI.htm"&gt;简单的模拟器&lt;/a&gt;来模拟MESI协议的工作状态&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="mesi_2"&gt;MESI的优化&lt;/h3&gt;
&lt;p&gt;随着多核处理器的普及和系统复杂度的增加，MESI协议面临着性能瓶颈和效率问题。因此，为了提高系统性能和缩短响应时间，对MESI协议的优化变得非常必要。&lt;/p&gt;
&lt;h4 id="store-buffer"&gt;写缓冲区（Store Buffer）机制&lt;/h4&gt;
&lt;p&gt;在进行写入操作时，一个CPU核心（例如核心1）首先需要广播一个读取为了写入（Read For Ownership，RFO）请求，以获得对应数据的独占访问权。在等待其他核心响应此请求并发送回确认信号（ACK）期间，核心1原本需要空闲等待，这无疑是对CPU资源的一种浪费。&lt;/p&gt;
&lt;p&gt;为了提高效率，现代CPU设计了“写缓冲区”机制。通过这种机制，当核心1发出RFO请求并将写入操作放入写缓冲区后，它可以立即继续执行其他任务，而不需要等待ACK的到来。一旦收到ACK，CPU再从写缓冲区中取出写入操作，实际写入到缓存中。这样不仅优化了CPU的工作流程，还提升了处理器的整体效能。&lt;/p&gt;
&lt;h4 id="invalidation-queue"&gt;失效队列（Invalidation Queue）&lt;/h4&gt;
&lt;p&gt;为了解决核心在忙碌时无法及时响应RFO请求的问题，现代CPU引入了“失效队列”机制。收到的RFO请求被放入失效队列，并立即发送回ACK，待核心完成手头上的任务后，再处理失效队列中的请求。这种设计有效地缩短了等待时间，加速了数据同步过程。&lt;/p&gt;
&lt;h3 id="mesi_3"&gt;MESI的潜在问题&lt;/h3&gt;
&lt;h4 id="false-sharing"&gt;False Sharing&lt;/h4&gt;
&lt;p&gt;由于CPU以64B的Cache Line为最小单位从内存中加载数据，可能会出现这样的问题：&lt;/p&gt;
&lt;p&gt;假设变量a和b位于同一个Cache Line中，当前CPU0和CPU1都将这个Cache Line加载到Cache，CPU0只修改变量a，CPU1只读取变量b。当CPU0修改a时，CPU1的Cache Line会变为Invalid状态，即使CPU1并没有修改b，这会导致CPU1从内存或其它核心重新加载Cache Line中的所有变量，影响性能。这就是False Sharing。&lt;/p&gt;
&lt;p&gt;解决False Sharing的常用方法是进行字节填充，在a和b之间填充无意义的变量，使一个变量单独占用一个Cache Line。&lt;/p&gt;
&lt;h4 id="rmw"&gt;RMW操作&lt;/h4&gt;
&lt;p&gt;在并发编程中，读-改-写（RMW）操作，如比较并交换（CAS）和原子加（ADD），需作为单一的原子操作执行以避免数据竞争。&lt;/p&gt;
&lt;p&gt;尽管MESI缓存一致性协议确保了处理器核心间缓存行状态的一致性，它并不解决操作的原子性问题。在RMW操作中，由于从读取到写回的时间窗口内可能发生其他处理器的干预修改，可能导致数据竞争和状态不一致。&lt;/p&gt;
&lt;p&gt;在为此，&lt;code&gt;LOCK&lt;/code&gt;指令被用来确保RMW操作的原子性，通过锁定操作涉及的缓存行，防止在操作完成前被其他处理器访问，从而有效地解决了数据竞争问题，保障了操作的安全性和数据的一致性。&lt;/p&gt;
&lt;h4 id="store-buffer_1"&gt;写缓冲区（Store Buffer）优化带来的潜在问题&lt;/h4&gt;
&lt;p&gt;写缓冲区带来的最主要的问题是与其他核心的数据一致性问题。由于写操作被延迟执行，其他核心可能在这段时间内读取到了旧的数据值，从而导致数据不一致的问题。此外，写缓冲区可能导致内存顺序的问题，即编写的程序逻辑与实际执行逻辑不符。&lt;/p&gt;
&lt;h4 id="invalidation-queue_1"&gt;失效队列（Invalidation Queue）带来的潜在问题&lt;/h4&gt;
&lt;p&gt;失效队列提高了响应速度，但它也可能引入新的问题。失效队列允许CPU核心在确认接收到失效请求后，延迟处理这些请求。这种延迟可能导致数据在不同核心间的一致性问题，即一个核心可能会在短时间内继续使用已经失效的数据，而这段时间内其他核心已经修改了这部分数据。&lt;/p&gt;
&lt;h2 id="_2"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://zh.wikipedia.org/wiki/MESI%E5%8D%8F%E8%AE%AE"&gt;MESI协议&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/LeoYang90/Golang-Internal-Notes/blob/master/Go%20%E5%86%85%E5%AD%98%E4%B8%80%E8%87%B4%E6%80%A7%E6%A8%A1%E5%9E%8B.md#go-%E5%86%85%E5%AD%98%E4%B8%80%E8%87%B4%E6%80%A7%E6%A8%A1%E5%9E%8B"&gt;Go 内存一致性模型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juejin.cn/post/7158395475362578462"&gt;12 张图看懂 CPU 缓存一致性与 MESI 协议，真的一致吗？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wudaijun.com/2019/04/cache-coherence-and-memory-consistency/"&gt;Cache一致性和内存一致性&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.chongsheng.art/post/golang/cpu-cache-memory-barrier/"&gt;CPU缓存架构到内存屏障&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="alert alert-info" role="alert"&gt;本文大（划掉）部分内容由ChatGPT4生成&lt;/div&gt;</content><category term="Blog"/><category term="cpp"/><category term="memory-barrier"/><category term="multithread"/><category term="thread"/><category term="MESI"/></entry><entry><title>[tl;dr] 论文阅读：Borg - Large-scale cluster management at Google</title><link href="https://wizmann.top/tl-dr-borg.html" rel="alternate"/><published>2023-12-27T00:00:00+08:00</published><updated>2023-12-27T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2023-12-27:/tl-dr-borg.html</id><summary type="html">&lt;ul&gt;
&lt;li&gt;
&lt;h2 id="_1"&gt;系统概览&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Borg是谷歌开发的一种高效的集群管理系统，旨在优化资源利用率和提高系统的可靠性及可用性&lt;ul&gt;
&lt;li&gt;隐藏资源管理细节与故障处理，允许用户专注于应用程 …&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;
&lt;h2 id="_1"&gt;系统概览&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Borg是谷歌开发的一种高效的集群管理系统，旨在优化资源利用率和提高系统的可靠性及可用性&lt;ul&gt;
&lt;li&gt;隐藏资源管理细节与故障处理，允许用户专注于应用程序的开发&lt;/li&gt;
&lt;li&gt;保证非常高的可靠性和可用性，以支持用户应用程序的高可靠性和高可用性&lt;/li&gt;
&lt;li&gt;支持运行来自众多应用的数十万个作业，并高效运行于数以万计的机器上&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_2"&gt;用户视角&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;用户通过定义&lt;em&gt;job&lt;/em&gt;和&lt;em&gt;task&lt;/em&gt;与Borg进行交互&lt;ul&gt;
&lt;li&gt;一个&lt;em&gt;job&lt;/em&gt;由运行相同程序的一个或多个&lt;em&gt;task&lt;/em&gt;组成&lt;/li&gt;
&lt;li&gt;每一个&lt;em&gt;job&lt;/em&gt;运行于一个&lt;em&gt;Borg cell&lt;/em&gt;（单元）之中，&lt;em&gt;cell&lt;/em&gt;是一组机器的集合，是Borg管理的基本单元&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Borg的工作负载&lt;ul&gt;
&lt;li&gt;长期运行的时延敏感型服务&lt;/li&gt;
&lt;li&gt;批处理作业&lt;/li&gt;
&lt;li&gt;运行在实体机上，避免VM的虚拟化开销&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Allocs&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;预留给一项或多项任务的一组资源&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Alloc&lt;/em&gt;可以将不同 &lt;em&gt;jobs&lt;/em&gt; 的 &lt;em&gt;tasks&lt;/em&gt; 聚集到同一台机器上&lt;/li&gt;
&lt;li&gt;如果一个 &lt;em&gt;alloc&lt;/em&gt; 必须重新分配到另外一台主机，属于它的 &lt;em&gt;task(s)&lt;/em&gt; 也会同它一起重新被调度&lt;/li&gt;
&lt;li&gt;一旦创建一个 &lt;em&gt;alloc&lt;/em&gt; 集合，就可以提交一个或多个 jobs 运行其中&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;命名服务和监控&lt;ul&gt;
&lt;li&gt;Borg包含一个稳定的 &lt;em&gt;Borg命名服务&lt;/em&gt; (BNS)，包括 cell 名，job 名和 task id&lt;/li&gt;
&lt;li&gt;Borg将 &lt;em&gt;task&lt;/em&gt; 的主机名和端口写入 Chubby，用于 RPC 系统查找 task endpoint&lt;/li&gt;
&lt;li&gt;Borg还会将 &lt;em&gt;job&lt;/em&gt; size与其运行状态写入Chubby，便于load balancer平衡流量&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="borg"&gt;Borg的架构&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Borgmaster&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;主管理进程&lt;ul&gt;
&lt;li&gt;逻辑上的“单点”，有5个在线备份，使用Paxos选举master&lt;/li&gt;
&lt;li&gt;状态存储在内存中，并且备份在高可靠性的Paxos存储中&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;调度进程&lt;ul&gt;
&lt;li&gt;可行性检查&lt;ul&gt;
&lt;li&gt;用于找到满足任务约束、具备足够可用资源的一组机器&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;打分（scoring）&lt;ul&gt;
&lt;li&gt;在“可行机器”中根据用户偏好，为机器打分&lt;/li&gt;
&lt;li&gt;打分策略&lt;ul&gt;
&lt;li&gt;worst fit（E-PVN的变种）会将任务分散到不同的机器上&lt;ul&gt;
&lt;li&gt;有余量应对流量的尖峰&lt;/li&gt;
&lt;li&gt;会导致资源的碎片化，阻碍大型&lt;em&gt;task&lt;/em&gt;的部署&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;best fit，会尽量“紧凑”的使用机器，以减少资源碎片&lt;ul&gt;
&lt;li&gt;便于大型&lt;em&gt;task&lt;/em&gt;的部署&lt;/li&gt;
&lt;li&gt;错误的资源估计会被“惩罚”，尤其影响突发的负载&lt;/li&gt;
&lt;li&gt;影响利于富裕计算资源的batch jobs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;混合模型，尽量减少“受困资源”，即因为其它资源被完全占用而无法分配出去的资源&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;优化&lt;ul&gt;
&lt;li&gt;启动时间优化&lt;ul&gt;
&lt;li&gt;中位数启动时间为25s，80%用于安装相关依赖&lt;/li&gt;
&lt;li&gt;将相关&lt;em&gt;task&lt;/em&gt;优先分配到拥有相关依赖的机器上&lt;/li&gt;
&lt;li&gt;使用 &lt;em&gt;tree-like&lt;/em&gt; 或 &lt;em&gt;torrent-like&lt;/em&gt; 机制，并发的分发相关依赖&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;计算开销优化&lt;ul&gt;
&lt;li&gt;使得Borg能管理更多的机器&lt;/li&gt;
&lt;li&gt;打分缓存：将可行性检查和打分结果缓存&lt;/li&gt;
&lt;li&gt;等价类：同一 &lt;em&gt;job&lt;/em&gt; 中的 &lt;em&gt;task&lt;/em&gt; 通常具有类似的约束，因此可以将多个任务视为一个等价类&lt;/li&gt;
&lt;li&gt;松弛随机化：计算所有机器的可行性和得分代价太高，可以随机取样一批机器，然后选择其中一个“足够好”的机器&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Borglet&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Borglet&lt;/em&gt; 是运行在每台机器上的本地代理，管理本地的任务和资源&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Borgmaster&lt;/em&gt; 会周期性地向每一个Borglet拉取当前状态，易于控制通信速度，避免“恢复风暴”&lt;/li&gt;
&lt;li&gt;为了性能可扩展性，每个Borgmaster副本会运行无状态的 &lt;em&gt;link shard&lt;/em&gt; 去处理与部分Borglet通信&lt;ul&gt;
&lt;li&gt;当 &lt;em&gt;Borgmaster&lt;/em&gt; 重新选举时，&lt;em&gt;link shard&lt;/em&gt; 会重新划分分区&lt;/li&gt;
&lt;li&gt;&lt;em&gt;link shard&lt;/em&gt; 会聚合和压缩信息，仅仅向被Borgmaster报告状态的更新，以此减少更新负载&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;如果 &lt;em&gt;Borglet&lt;/em&gt; 多轮没有响应资源查询，则会被标记为down。运行其上的任务会被重新调度到其他机器。如果恢复通信，则 &lt;em&gt;Borgmaster&lt;/em&gt; 会通知 &lt;em&gt;Borglet&lt;/em&gt; 杀死已经重新调度的任务，以此保证任务的唯一性&lt;/li&gt;
&lt;li&gt;Borglet与Borgmaster失去联系时，仍会继续处理相关任务。以应对 &lt;em&gt;Borgmaster&lt;/em&gt; 的暂时失效&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_3"&gt;可靠性&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;自动重新调度器被驱逐的任务&lt;/li&gt;
&lt;li&gt;将任务分散到不同的失败域中&lt;/li&gt;
&lt;li&gt;限制一个作业中同时失败任务的个数和中断率&lt;/li&gt;
&lt;li&gt;使用声明式的期望状态表示和幂等的变更操作，以便无害地重新提交请求&lt;/li&gt;
&lt;li&gt;对于机器级别的失效，限制其重新调度的速率，因为难以区分大规模机器故障和网络分区&lt;/li&gt;
&lt;li&gt;避免重试引发错误的&amp;lt;任务-机器&amp;gt;匹配对&lt;/li&gt;
&lt;li&gt;关键数据持久化，写入磁盘&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_4"&gt;资源利用和效率&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;评估方法&lt;ul&gt;
&lt;li&gt;&lt;em&gt;cell compaction&lt;/em&gt;：通过移除机器来找出给定工作负载能适应的最小的单元大小，然后反复从头开始重新打包工作负载，以确保不会因错误的配置而陷入困境&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;“单元共享”：在同一台机器上运行生产任务和非生产任务，以优化资源使用&lt;ul&gt;
&lt;li&gt;实验表明，共享资源会影响实际的CPU计算性能&lt;/li&gt;
&lt;li&gt;但是在节约成本的巨大优势上面，CPU性能的退化是可以容忍的&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;“大型单元”：允许超大型计算任务，减少任务的碎片化&lt;/li&gt;
&lt;li&gt;细粒度资源请求&lt;ul&gt;
&lt;li&gt;以千分之一的CPU核，和内存、磁盘的字节数为资源请求的最小单元&lt;/li&gt;
&lt;li&gt;相比预设资源分配（套餐），可以避免额外的资源开销&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;资源回收&lt;ul&gt;
&lt;li&gt;对于可以容忍低质量资源的工作（例如批处理作业），Borg会评估任务将使用的资源，并回收空闲资源&lt;/li&gt;
&lt;li&gt;最初的预留值与其资源请求一致，然后300秒之后，会慢慢降低到实际使用率外加一个安全边缘&lt;/li&gt;
&lt;li&gt;如果利用率超过资源预留值，预留值会快速增长。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_5"&gt;隔离与安全性：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;安全隔离&lt;ul&gt;
&lt;li&gt;使用Linux chroot jail在共享同一台机器的任务之间确保安全性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;性能隔离&lt;ul&gt;
&lt;li&gt;基于cgroup的资源容器，允许详细的资源核算并执行限制，防止任务相互干扰，确保稳定和可预测的性能&lt;/li&gt;
&lt;li&gt;使用&lt;em&gt;appclass&lt;/em&gt;，尽可能保证延迟敏感服务的资源使用&lt;/li&gt;
&lt;li&gt;区分&lt;em&gt;可压缩资源&lt;/em&gt; 和 &lt;em&gt;不可压缩资源&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;可压缩资源（compressiable） - CPU%和Disk IO，可以暂时限流&lt;/li&gt;
&lt;li&gt;不可压缩资源（non-compressible） - 内存、磁盘占用，需要清除优先级低的线程&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;内核的CPU调度器，允许根据每个资源容器的负载状况来动态决定是否要驱逐低优先级任务，同时避免多个高优先级任务在一个cpu上争抢&lt;ul&gt;
&lt;li&gt;仍在尝试cpu调度时更好的考虑线程亲和、NUMA亲和等策略&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_6"&gt;经验教训：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id="_7"&gt;负面经验&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Job&lt;/em&gt;作为&lt;em&gt;Task&lt;/em&gt;的唯一分组机制的局限性&lt;ul&gt;
&lt;li&gt;缺乏将整个多&lt;em&gt;Job&lt;/em&gt;服务作为单一实体进行管理，或引用服务相关&lt;em&gt;Job&lt;/em&gt;（如Canary与Prod滚动更新）的方式&lt;/li&gt;
&lt;li&gt;用户会在&lt;em&gt;Job&lt;/em&gt;名称中编入拓扑，并构建外部管理工具来解析这些名称，这导致了滚动更新和作业调整大小等问题的不灵活语义&lt;/li&gt;
&lt;li&gt;Kubernetes通过使用标签组织其调度单元（Pods），提供了更多灵活性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;单个IP地址带来的复杂性&lt;ul&gt;
&lt;li&gt;同一台机器上的所有任务共享该机器的单个IP地址和端口空间&lt;/li&gt;
&lt;li&gt;导致端口也成为一种资源，在调度时候需要被考虑&lt;/li&gt;
&lt;li&gt;Kubernetes采用了更友好的方法，每个Pod和服务都获取自己的IP地址，从而简化了这些复杂性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;偏向于高级用户&lt;ul&gt;
&lt;li&gt;Borg提供了一整套面向“高级用户”的功能，允许他们细致调整程序运行方式&lt;/li&gt;
&lt;li&gt;这种API的丰富性使得对于“普通”用户更加困难，并限制了其演变&lt;/li&gt;
&lt;li&gt;Google构建了自动化工具，对于允许“失败”的应用程序，通过实验来探测适当配置&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_8"&gt;积极经验&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Allocs是有用的&lt;ul&gt;
&lt;li&gt;Kubernetes中的Alloc等效物是Pod，它是一个资源包，用于一个或多个容器，总是被调度到同一台机器上并可以共享资源&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;集群管理不仅是任务管理&lt;ul&gt;
&lt;li&gt;尽管Borg的主要角色是管理任务和机器的生命周期，但运行在Borg上的应用程序从许多其他集群服务中受益，包括命名和负载均衡&lt;/li&gt;
&lt;li&gt;Kubernetes使用服务抽象支持命名和负载均衡，服务有一个名称和一组由标签选择器定义的动态Pods。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;自省至关重要&lt;ul&gt;
&lt;li&gt;尽管Borg几乎总是“运行良好”，但当出现问题时，找到根本原因可能具有挑战性&lt;/li&gt;
&lt;li&gt;Borg的重要设计决策之一是向所有用户展示调试信息&lt;/li&gt;
&lt;li&gt;Kubernetes旨在复制Borg的许多内省技术，例如，它配备了cAdvisor等工具进行资源监控和基于Elasticsearch/Kibana和Fluentd的日志聚合&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;主控节点是分布式系统的核心&lt;ul&gt;
&lt;li&gt;Borgmaster最初被设计为一个单体系统，但随着时间的推移，它变得更像是一个内核，位于协作管理用户作业的一系列服务的中心&lt;/li&gt;
&lt;li&gt;Kubernetes架构更进一步，它有一个核心的API服务器，仅负责处理请求和操纵底层状态对象，集群管理逻辑被构建为小型可组合的微服务，这些服务是这个API服务器的客户端​​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://research.google/pubs/large-scale-cluster-management-at-google-with-borg/"&gt;论文&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="alert alert-info" role="alert"&gt;本文部分内容由ChatGPT4生成&lt;/div&gt;</content><category term="Blog"/><category term="Borg"/><category term="Distributed System"/><category term="Kubernetes"/><category term="Google"/></entry><entry><title>[TL;DR] 论文阅读：Autopilot - 自动化数据中心管理</title><link href="https://wizmann.top/tl-dr-autopilot-automatic-data-center-management.html" rel="alternate"/><published>2023-12-22T23:32:00+08:00</published><updated>2023-12-22T23:32:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2023-12-22:/tl-dr-autopilot-automatic-data-center-management.html</id><summary type="html">&lt;ul&gt;
&lt;li&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Autopilot是微软用来自动化运营大规模网络服务的基础架构&lt;/li&gt;
&lt;li&gt;其设计核心是Device Manager，一个基于Paxos的强一致性分布式状态机，用来保存整个系统的“实际真相”（ground truth），并且根据整个系统的状态确定下一步的行动 …&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Autopilot是微软用来自动化运营大规模网络服务的基础架构&lt;/li&gt;
&lt;li&gt;其设计核心是Device Manager，一个基于Paxos的强一致性分布式状态机，用来保存整个系统的“实际真相”（ground truth），并且根据整个系统的状态确定下一步的行动&lt;/li&gt;
&lt;li&gt;其它子模块通过与Device Manager通信，在“最终一致性”模型下获取系统信息并执行命令，确保更新可能不是即时的，但最终会在系统中传播&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_1"&gt;概述：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;微软运营大规模网络服务，需要可靠的数据中心自动管理​​&lt;/li&gt;
&lt;li&gt;为了降低数据中心的运营和资本支出而设计​​&lt;/li&gt;
&lt;li&gt;负责自动化软件配置和部署、系统监控，以及执行修复操作来处理软件和硬件的故障&lt;/li&gt;
&lt;li&gt;微观的策略则交由各个应用程序来确定。例如，确定哪些计算机应运行哪些软件，或者精确地定义和检测需要修复的故障&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_2"&gt;设计原则：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;基于大规模“商品级计算机系统”的经济性和不可靠性，Autopilot采用容错和简化设计​​&lt;/li&gt;
&lt;li&gt;容错设计：非拜占庭式故障模型，解决数据中心的控制环境问题&lt;ul&gt;
&lt;li&gt;“非拜占庭式故障模型”假设系统中的错误不是恶意或欺诈性的。在这种模型中，系统的故障被认为是由于一些常规原因，如硬件故障、软件缺陷或网络问题&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;简化设计：&lt;ul&gt;
&lt;li&gt;强调简单性和容错性&lt;/li&gt;
&lt;li&gt;在构建大型的可靠、可维护系统时，常常选择简单设计而非更高效或看似更优雅但更复杂的解决案。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_3"&gt;系统概览：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Autopilot分为多个组件&lt;ul&gt;
&lt;li&gt;&lt;img alt="image.png" src="https://github.com/Wizmann/assets/blob/master/wizmann-pic/image_1703238379499_0.png?raw=true"&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;平衡弱一致性和强一致性之间的抉择&lt;ul&gt;
&lt;li&gt;弱一致性：增强可用性&lt;/li&gt;
&lt;li&gt;强一致性：简化设计&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Device Manager - 状态和逻辑管理&lt;ul&gt;
&lt;li&gt;所有关于系统应处于的“实际真相”（ground truth）状态以及更新这一状态的逻辑，都保存在一个称为 Device Manager 的强一致性状态机中，通常分布在5至10台计算机上&lt;/li&gt;
&lt;li&gt;使用 Paxos 算法实现副本间的一致性，同时通过批处理更新以平衡延迟和吞吐量&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Device Manager与“卫星服务”&lt;ul&gt;
&lt;li&gt;“卫星服务”在发现 Device Manager 状态需要时，惰性地向自身或其客户端的同步信息&lt;/li&gt;
&lt;li&gt;如果“卫星服务”发现集群中的故障或不一致，它不会尝试纠正，而是将问题报告给 Device Manager&lt;ul&gt;
&lt;li&gt;Autopilot会综合这些信息做出下一步决定&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;当 Device Manager 更新其状态时，会通知“卫星服务”。“卫星服务”也会通过心跳信息尝试拉取最新的状态。简化设计的同时，并且保证最终一致性/正确性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_4"&gt;底层服务：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用稳定的Windows Server操作系统镜像，包含Autopilot配置文件和服务​​&lt;/li&gt;
&lt;li&gt;配置服务（Provisioning）包括DHCP和网络引导，不断扫描网络中新接入的计算机​​&lt;ul&gt;
&lt;li&gt;通过Device Manager提供的信息来决定需要运行的操作系统及二进制程序&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;应用部署&lt;ul&gt;
&lt;li&gt;定义不同机器类型，存储不同配置文件和应用二进制文件​​&lt;/li&gt;
&lt;li&gt;部署新代码时，以Scale unit为单位更新/回滚各机器类型的配置​​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_5"&gt;自动修复服务&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用最小化的故障检测和恢复模型，以节点或交换机为单位，不处理特定进程的错误&lt;ul&gt;
&lt;li&gt;只包括Reboot / ReImage / Replace 三种操作&lt;/li&gt;
&lt;li&gt;Autopilot无需对错误归因，也不需要相关的错误处理逻辑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;用看门狗进行故障报告​​，检测特定的属性，并上报给Device Manager&lt;/li&gt;
&lt;li&gt;Device Manager作为一个集中式程序，控制机器的自动修复，并且控制同时进行修复机器的数量&lt;/li&gt;
&lt;li&gt;&lt;img alt="image.png" src="https://github.com/Wizmann/assets/blob/master/wizmann-pic/image_1703254394216_0.png?raw=true"&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_6"&gt;监控服务：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;记录性能计数器和日志，收集服务形成分布式集合和聚合树​​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="-indexserving"&gt;案例研究 - IndexServing：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;介绍Windows Live Search如何与Autopilot交互，保持高可用性​​&lt;/li&gt;
&lt;li&gt;对于需要高可用性和低延迟的面向客户服务的应用程序，需要在基础的 Autopilot 组件之上增加定制的容错层&lt;ul&gt;
&lt;li&gt;使用Load balancer和定制的监控服务来探测失效的或者慢速的节点，并且将结论上报到Autopilot&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_7"&gt;经验与教训：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;对于关键的配置文件，进行checksum检查是必须的&lt;ul&gt;
&lt;li&gt;避免人工失误（例如部署因Debug而临时修改的配置）或者其它意外问题&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;网络是不可靠的&lt;ul&gt;
&lt;li&gt;TCP/IP的checksum非常弱，所以需要应用层面的额外检查&lt;/li&gt;
&lt;li&gt;网络硬件经常翻转数据流中的bit位，导致大量的重试或者未被网络层检测到的数据错误&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;一些节点偶尔会运行的异常慢，但是并不会停止工作。这种问题与“失败停止错误”一样需要被及时检测到&lt;/li&gt;
&lt;li&gt;节流与负荷削减对于自动化系统非常重要&lt;ul&gt;
&lt;li&gt;失效检测模块需要有效的区分节点失效与节点过载的区别&lt;/li&gt;
&lt;li&gt;简单的移除节点可能会导致级联式的失效，进而使整个系统失效&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.semanticscholar.org/paper/Autopilot%3A-automatic-data-center-management-Isard/a531d33efc600a8770316db71dc06a7599f9547a"&gt;论文&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="alert alert-info" role="alert"&gt;本文大（划掉）部分内容由ChatGPT4生成&lt;/div&gt;</content><category term="Blog"/><category term="Autopilot"/><category term="Data Center"/><category term="Data Center Management"/></entry><entry><title>使用 SPIN/Promela 对多线程 Concurrent FIFO Queue 进行建模与验证</title><link href="https://wizmann.top/SPIN-Promela-Concurrent-Queue-1.html" rel="alternate"/><published>2023-12-17T00:00:00+08:00</published><updated>2023-12-17T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2023-12-17:/SPIN-Promela-Concurrent-Queue-1.html</id><summary type="html">&lt;h2 id="_1"&gt;引言&lt;/h2&gt;
&lt;p&gt;并发编程中设计和验证多线程数据结构是一项极大的挑战，即使是实现一个简单的数据结构（见&lt;a href="/implement-non-blocking-queue.html"&gt;《实现一个无锁消息 …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;引言&lt;/h2&gt;
&lt;p&gt;并发编程中设计和验证多线程数据结构是一项极大的挑战，即使是实现一个简单的数据结构（见&lt;a href="/implement-non-blocking-queue.html"&gt;《实现一个无锁消息队列》&lt;/a&gt;一文），都需要不少的脑力、讨论与实践才可以尽可能保证其正确性。&lt;/p&gt;
&lt;p&gt;本文尝试使用 SPIN/Promela 对多线程环境下的 Concurrent FIFO Queue 的一种实现进行建模与验证。&lt;/p&gt;
&lt;h2 id="concurrent-fifo-queue"&gt;Concurrent FIFO Queue 的设计&lt;/h2&gt;
&lt;p&gt;为了保证多线程操作的正确性，我们采用了以下关键设计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dummy Head 和 Dummy Tail 节点：引入这两个节点简化了队列操作逻辑，降低并发中的复杂性&lt;/li&gt;
&lt;li&gt;Dummy Tail Data 指针作为“锁”：这个方法确保多个线程不会同时操作尾节点，降低了对锁的依赖&lt;/li&gt;
&lt;li&gt;利用指针赋值的原子性：通过这种方式，减少了锁的使用，提高了效率&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="spinpromela"&gt;SPIN/Promela 建模中的考虑因素&lt;/h2&gt;
&lt;p&gt;在使用 SPIN/Promela 建模时，我们面临了几个挑战：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;静态内存管理：SPIN/Promela 缺乏动态内存操作，因此我们实现了一个极简的手动管理的静态内存堆栈。&lt;/li&gt;
&lt;li&gt;减少状态空间：队列的长度可以是无限的，这也就意味着无限的状态空间。因此，我们将队列的最大长度设为3，以减少状态的穷举空间。&lt;/li&gt;
&lt;li&gt;模拟CAS操作：由于缺少CAS指令，我们使用 do 循环和 atomic 块来模拟，同时开启 weak fairness 避免无限循环。（见&lt;a href="/simple-cas-model-in-spin-promela.html"&gt;《在SPIN/Promela中模拟CAS》&lt;/a&gt;一文）&lt;/li&gt;
&lt;li&gt;LTL表达式的使用：使用 LTL 表达式来穷举检查所有可能的程序状态，包括边缘情况。&lt;ul&gt;
&lt;li&gt;LTL表达式偶尔会有一些”反直觉“的情况出现&lt;/li&gt;
&lt;li&gt;例如在程序验证路径中，虽然理论上队列大小可以为0~3当中的任意数。但是也存在一种可能，即队列大小可以在2和3之间反复变化。如果我们声明“&lt;strong&gt;永远&lt;/strong&gt; &lt;strong&gt;最终&lt;/strong&gt; 一定存在 queue size==1” 的表达式会失败，因为队列大小在这种“人造场景”下永远不会为1。&lt;/li&gt;
&lt;li&gt;这种情况要求我们非常精确地设计 LTL 表达式&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;代码与断言的结合：因为 LTL 表达式的表达能力有限，需要结合代码中的 assert 语句来进行更全面的验证&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_2"&gt;代码示例&lt;/h2&gt;
&lt;p&gt;下面是我们用于建模和验证 Concurrent FIFO Queue 的 Promela 代码示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#define MAX_CAPACITY 3&lt;/span&gt;
&lt;span class="cp"&gt;#define NUM_NODES MAX_CAPACITY + 2&lt;/span&gt;
&lt;span class="cp"&gt;#define EMPTY -1&lt;/span&gt;
&lt;span class="cp"&gt;#define INVALID_PTR -1&lt;/span&gt;

&lt;span class="cp"&gt;#define QUEUE_NOT_FULL (memptr &amp;gt; 0)&lt;/span&gt;
&lt;span class="cp"&gt;#define QUEUE_NOT_EMPTY (memptr &amp;lt; MAX_CAPACITY)&lt;/span&gt;
&lt;span class="cp"&gt;#define QUEUE_IS_EMPTY (memptr == MAX_CAPACITY)&lt;/span&gt;
&lt;span class="cp"&gt;#define QUEUE_IS_FULL (memptr == 0)&lt;/span&gt;

&lt;span class="cp"&gt;#define HEAD 0&lt;/span&gt;

&lt;span class="kd"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueueNode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// 1 dummy head + 1 dummy tail + #(data nodes)&lt;/span&gt;
&lt;span class="n"&gt;QueueNode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NUM_NODES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// data nodes + dummy tail&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAX_CAPACITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_CAPACITY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;NUM_NODES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EMPTY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;MAX_CAPACITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAX_CAPACITY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;atomic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="ow"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="ow"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;update_queue_size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;d_step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;od&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// remove HEAD&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_CAPACITY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workerId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;atomic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;cur1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;memptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;memptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;memptr&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EMPTY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;skip&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// CAS&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;atomic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EMPTY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;workerId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;update_queue_size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;od&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;skip&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dequeue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workerId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nxt2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;cur2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nxt2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;cur2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nxt2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;atomic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;update_queue_size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nxt2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nxt2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EMPTY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;update_queue_size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;od&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;d_step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EMPTY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAX_CAPACITY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;memptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;memptr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;memptr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;memptr&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;skip&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;proctype&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;workerId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QUEUE_NOT_FULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QUEUE_NOT_EMPTY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dequeue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;od&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;ltl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;valid_first_node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INVALID_PTR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NUM_NODES&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;ltl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;not_always_empty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QUEUE_IS_EMPTY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;QUEUE_NOT_EMPTY&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;ltl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;not_always_full&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QUEUE_IS_FULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;QUEUE_NOT_FULL&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;ltl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size_change_by_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_3"&gt;讨论&lt;/h2&gt;
&lt;h3 id="_4"&gt;混合编程的可能性&lt;/h3&gt;
&lt;p&gt;我们是否可以通过 Promela 与 C/C++ 的混合编程来解决模型中的一些困难？这种方法或许能提供更加灵活的解决方案，但代价又是什么呢？&lt;/p&gt;
&lt;h3 id="ltl"&gt;LTL语句的合理性&lt;/h3&gt;
&lt;p&gt;在多线程环境下验证数据结构的正确性始终是一项艰巨的任务。对于代码中使用的LTL语句，是否需要继续完善以保证其在更多（甚至所有）场景下的正确性?&lt;/p&gt;
&lt;h3 id="_5"&gt;对于其他实现的验证&lt;/h3&gt;
&lt;p&gt;在&lt;a href="/implement-non-blocking-queue.html"&gt;《实现一个无锁消息队列》&lt;/a&gt;一文中，涉及了更多的多线程队列模型，后续会对其进行验证。&lt;/p&gt;
&lt;div class="alert alert-info" role="alert"&gt;本文大（划掉）部分内容由ChatGPT4生成&lt;/div&gt;</content><category term="Blog"/><category term="SPIN"/><category term="Promela"/><category term="SPIN/Promela"/><category term="多线程"/><category term="multi-thread"/><category term="Queue"/><category term="FIFO"/></entry><entry><title>在SPIN/Promela中模拟CAS（Compare-and-Swap）</title><link href="https://wizmann.top/simple-cas-model-in-spin-promela.html" rel="alternate"/><published>2023-12-15T00:00:00+08:00</published><updated>2023-12-15T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2023-12-15:/simple-cas-model-in-spin-promela.html</id><summary type="html">&lt;p&gt;CAS（Compare-And-Swap）是一种在多线程编程中常用的数据同步方法，它通过比较和交换操作来保证数据的一致性。然而，在SPIN/Promela中没有直接的CAS对应实现。&lt;/p&gt;
&lt;p&gt;让我们来看 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;CAS（Compare-And-Swap）是一种在多线程编程中常用的数据同步方法，它通过比较和交换操作来保证数据的一致性。然而，在SPIN/Promela中没有直接的CAS对应实现。&lt;/p&gt;
&lt;p&gt;让我们来看一个例子。考虑以下Promela代码，它模拟了两个工作线程 worker0 和 worker1 使用CAS机制交替修改共享变量 x 的场景：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;proctype&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worker0&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;atomic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;od&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;proctype&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worker1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;atomic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;od&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;atomic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="ow"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worker0&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="ow"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worker1&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;ltl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;not_always_0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;从直观上理解，LTL表达式 not_always_0 应该被满足，因为 worker0 和 worker1 应该会交替执行，从而在未来的某个时刻使 x == 1 成立。&lt;/p&gt;
&lt;p&gt;然而，在SPIN的实际运行中，我们可能会遇到一个问题：如果 worker0 在任何点停止执行，worker1 就会陷入死循环，这种情况被称为“饥饿”（starvation）。&lt;/p&gt;
&lt;p&gt;为了解决这一问题，我们可以在SPIN中使用 -f 选项来保证弱公平性（weak fairness）。弱公平性意味着，如果一个可执行的动作在无限长的执行序列中有无限次的执行机会，那么它最终必须得到执行。这确保了即使一个动作暂时无法执行，它最终也会有机会执行。&lt;/p&gt;
&lt;p&gt;在这个模型中，应用弱公平性可以确保 worker0 和 worker1 最终都有机会交替执行。这使得模型能够模拟现实的多线程CPU执行场景，从而验证了LTL属性 not_always_0 的正确性。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;详细命令&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;spin&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;simple-cas.pml
./pan&lt;span class="w"&gt; &lt;/span&gt;-m10000&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;-f
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;参考链接&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spinroot.com/spin/Man/Quick.html"&gt;Concise Promela Reference &amp;gt; Executing a Promela system&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="alert alert-info" role="alert"&gt;本文大（划掉）部分内容由ChatGPT4生成&lt;/div&gt;</content><category term="Blog"/><category term="SPIN"/><category term="Promela"/><category term="SPIN/Promela"/><category term="CAS"/><category term="Compare-and-Swap"/><category term="多线程"/></entry><entry><title>[tl;dr] 论文阅读：Rarest First and Choke Algorithms Are Enough</title><link href="https://wizmann.top/tl-dr-Rarest-First-and-Choke-Algorithms-Are-Enough.html" rel="alternate"/><published>2023-12-08T00:00:00+08:00</published><updated>2023-12-08T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2023-12-08:/tl-dr-Rarest-First-and-Choke-Algorithms-Are-Enough.html</id><summary type="html">&lt;ul&gt;
&lt;li&gt;
&lt;h2 id="_1"&gt;基本概念&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Peer&lt;/strong&gt;：BitTorrent P2P下载的参与者&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leecher&lt;/strong&gt;：“吸血者”，仍在下载过程中的peer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seeder&lt;/strong&gt;：做种者，下载完成后还在继续做种的peer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Piece&lt;/strong&gt;：Piece是文件的数据单元。当文件被分享时，它被分割 …&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;
&lt;h2 id="_1"&gt;基本概念&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Peer&lt;/strong&gt;：BitTorrent P2P下载的参与者&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leecher&lt;/strong&gt;：“吸血者”，仍在下载过程中的peer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seeder&lt;/strong&gt;：做种者，下载完成后还在继续做种的peer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Piece&lt;/strong&gt;：Piece是文件的数据单元。当文件被分享时，它被分割成多个大小相等的片段，称为&amp;rdquo;pieces&amp;rdquo;。这些pieces是peer间传输的基本单位&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="rarest-first-algorithm"&gt;&amp;ldquo;最稀有优先算法&amp;rdquo;（Rarest First Algorithm）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;最稀有优先算法&amp;rdquo;（Rarest First Algorithm）是BitTorrent协议中的一个关键策略，用于决定哪些数据块（piece）首先被下载和分享。这个算法的核心目标是优化整个网络中数据的分布，确保更快的下载速度和更高的效率。&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_2"&gt;基本原理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据块的稀有度&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;在BitTorrent网络中，文件被分割成许多小的数据块。&lt;ul&gt;
&lt;li&gt;“最稀有优先”算法的目的是优先下载那些网络中数量最少的数据块。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;选择下载的块&lt;/strong&gt;：&lt;ul&gt;
&lt;li&gt;当一个peer加入Torrent网络，并开始下载文件时，它首先会从所有连接的peer那里获取有关哪些数据块是稀有的信息。&lt;ul&gt;
&lt;li&gt;然后，它优先请求下载那些最稀有的数据块。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态调整&lt;/strong&gt;：&lt;ul&gt;
&lt;li&gt;随着下载的进行，每个peer会不断更新和重新评估网络中每个数据块的稀有度，并相应地调整其下载优先级。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_3"&gt;算法的重要性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;提高效率&lt;/strong&gt;：通过优先下载最稀有的块，这个算法帮助加快了文件的整体下载速度。一旦最稀有的块被更多peer获取，它们就更容易被进一步分享和分发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;防止瓶颈&lt;/strong&gt;：如果没有这个算法，某些数据块可能会变得很难获得，导致下载过程在接近完成时放慢，这被称为“最后一块问题”（Last Piece Problem）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;促进平等分享&lt;/strong&gt;：这种方法鼓励peer分享它们拥有的稀有块，从而提高了整个网络中的合作和资源共享。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_4"&gt;实际应用&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在BitTorrent网络中，这个算法对于确保高效的数据分发至关重要。它不仅提高了单个用户的下载速度，而且还提高了整个网络的效率，确保了资源在用户之间的均衡分配。通过这种方式，BitTorrent网络能够有效地避免瓶颈和提高数据的可用性，即使在面对大量用户的情况下也是如此。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_5"&gt;结论&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;最稀有优先算法是BitTorrent网络高效运行的关键组成部分。它通过智能地选择下载和分享网络中最稀有的数据块，提高了资源的整体分布和可用性，确保了快速、平衡的文件共享。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="choking-algorithm"&gt;&amp;ldquo;窒息算法&amp;rdquo;（Choking Algorithm）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;窒息算法&amp;rdquo;（Choking Algorithm）是BitTorrent协议中的一个关键组成部分，用于管理多个peer之间的数据传输。这个算法帮助优化带宽的使用，确保网络中的资源被高效合理地分配。其核心目的是促进peer间的合作和数据的快速分发。&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_6"&gt;窒息算法的基本原理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;选择和窒息（Choking and Unchoking）&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;在BitTorrent网络中，每个peer同时维护着一组“窒息”（choked）和“未窒息”（unchoked）的peer名单。&lt;ul&gt;
&lt;li&gt;被“窒息”的peer无法从窒息方接收文件数据，而“未窒息”的peer可以进行数据交换。&lt;/li&gt;
&lt;li&gt;这种状态是动态的，peer根据算法定期更新它们的窒息/未窒息peer名单。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;利益驱动的决策&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;算法核心是“利益驱动”（tit-for-tat）策略，即peer更倾向于向那些能给它提供数据的peer提供数据。&lt;ul&gt;
&lt;li&gt;这种方法鼓励peer分享数据，因为分享越多，获得数据的机会也越大。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优化器&lt;/strong&gt;：&lt;ul&gt;
&lt;li&gt;除了基于交换数据的量来决定窒息状态外，大多数BitTorrent客户端还实现了一个“优化器”（Optimizer），用于探索新的peer。&lt;ul&gt;
&lt;li&gt;通常，这是通过定期“未窒息”一个随机选择的peer来实现的，即使它在过去的数据交换中表现不佳或没有数据交换。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;窒息周期&lt;/strong&gt;：&lt;ul&gt;
&lt;li&gt;peer定期评估其连接，并根据从其他peer接收到的数据速率来更新其窒息/未窒息名单&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_7"&gt;窒息算法的重要性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;合作促进&lt;/strong&gt;：通过奖励那些分享资源的peer，窒息算法鼓励合作，提高了网络中的资源共享效率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;防止自私行为&lt;/strong&gt;：算法减少了自私peer（只下载不上传的）的优势，因为这些peer不太可能被其他peer“未窒息”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络拥塞控制&lt;/strong&gt;：它帮助控制网络拥塞，通过限制peer的连接数量和数据传输，优化带宽使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_8"&gt;结论&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;窒息算法是BitTorrent协议高效性的关键，它通过一种简单但有效的方式来鼓励数据共享和合作，保证了整个网络的健康和高效运行。通过这种动态的窒息/未窒息机制，BitTorrent网络能够有效地管理带宽和连接，确保资源在网络中的快速且公平的分配。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2 id="_9"&gt;为什么说“已经足够了”&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;因为这是一门实验科学&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="rarest-first-algorithm_1"&gt;&amp;ldquo;最稀有优先算法&amp;rdquo;（Rarest First Algorithm）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id="_10"&gt;种子的熵&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;描述了种子中各个数据块在所有peer间的分布情况&lt;/li&gt;
&lt;li&gt;高熵意味着数据块在所有peer中分布得很均匀，peer之间更有可能拥有彼此尚未下载的块&lt;/li&gt;
&lt;li&gt;高熵的种子通常意味着更高的数据交换效率&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="ideal-entrophy"&gt;理想熵（Ideal Entrophy）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;是指网络中的数据块（pieces）在所有leechers之间均匀分布&lt;/li&gt;
&lt;li&gt;每个leechers都持有一些其他leechers需要的数据块，从而确保了网络中的每个leechers都对其他leechers感兴趣。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="transient-state"&gt;冷启动（Transient State）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;当种子刚开始传播时的动态，优先传播稀有块，提高下载效率&lt;/li&gt;
&lt;li&gt;Rarest First Algorithm解决了种子的冷启动问题，确保了最不常见的块被优先传播，提高了整个网络的下载效率&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="steady-state"&gt;稳定态（Steady State）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;网络中的大部分块已经被比较均匀地传播。最稀有优先算法在这一阶段继续确保数据块的多样性，从而减少了任何特定块成为瓶颈的可能性&lt;/li&gt;
&lt;li&gt;算法鼓励peer间的有效合作，因为每个peer都可能持有其他peer需要的稀有块&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="last-pieces-problem"&gt;“最后一块”问题（Last Pieces Problem）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;下载接近完成时，某些块变得非常稀有，从而延缓整个下载过程&lt;/li&gt;
&lt;li&gt;算法确保即使在下载的后期，所有参与的peer仍然有激励去交换彼此之间缺少的块&lt;/li&gt;
&lt;li&gt;避免了下载末期的稀有块瓶颈&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="choking-algorithm_1"&gt;&amp;ldquo;窒息算法&amp;rdquo;（Choking Algorithm）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id="tit-for-tat-fairness"&gt;“对等原则”（Tit-for-tat Fairness）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;如果A从B下载的数据少于B从A下载的数据，A会拒绝继续与B分享数据&lt;/li&gt;
&lt;li&gt;用来保证公平性，杜绝free rider&lt;/li&gt;
&lt;li&gt;在动态或非对称网络环境中可能效率低下&lt;/li&gt;
&lt;li&gt;会导致网络空闲资源的浪费&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_11"&gt;旧版窒息算法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;旧版窒息算法只考虑了peer之间的下载速度，而不是它们的上传贡献&lt;ul&gt;
&lt;li&gt;少量上传速度快的leecher会占据大量带宽，不利于种子熵的增加&lt;/li&gt;
&lt;li&gt;下载速度快的free riders得到了比实际贡献更多的回报&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;基于更宏观的性能指标（如整体上传贡献）的策略能够更好地适应这些变化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id="_12"&gt;新版窒息算法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;上传速度快的leecher一定比上传速度慢的leecher获得更多的下载速度，保证了近似的对等原则&lt;/li&gt;
&lt;li&gt;对于seed（做种者）而言，应该对每个leecher提供相同的服务时间。保证了网络中的公平性和效率&lt;/li&gt;
&lt;li&gt;因为文件块可以被更平均的分配给了其它peer，在冷启动时的弹性更强，对于free riders的抵抗性也更强&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Link&lt;ul&gt;
&lt;li&gt;&lt;a href="http://conferences.sigcomm.org/imc/2006/papers/p20-legout.pdf"&gt;Rarest First and Choke Algorithms Are Enough&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="alert alert-info" role="alert"&gt;本文部分内容由ChatGPT4生成&lt;/div&gt;</content><category term="Blog"/><category term="BitTorrent"/><category term="Distributed System"/></entry><entry><title>A2B Game Solutions</title><link href="https://wizmann.top/A2B.html" rel="alternate"/><published>2021-11-18T00:00:00+08:00</published><updated>2021-11-18T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2021-11-18:/A2B.html</id><summary type="html">&lt;p&gt;A2B is a &amp;ldquo;zach-like&amp;rdquo; programming game, which let you to use a very simple &amp;ldquo;programming language&amp;rdquo; to solve different problems for strings.&lt;/p&gt;
&lt;p&gt;Personally, I highly recommand this game along with &amp;ldquo;Shenzhen IO&amp;rdquo; and &amp;ldquo;Factorio&amp;rdquo; as an beginner tutorial for anyone who wants to be a software engineer.&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/1720850/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;
&lt;iframe src="https://store.steampowered.com/widget/504210/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;
&lt;iframe src="https://store.steampowered.com/widget/427520/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;h2 id="spoiler-alert"&gt;Spoiler Alert&lt;/h2&gt;
&lt;p&gt;** The …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A2B is a &amp;ldquo;zach-like&amp;rdquo; programming game, which let you to use a very simple &amp;ldquo;programming language&amp;rdquo; to solve different problems for strings.&lt;/p&gt;
&lt;p&gt;Personally, I highly recommand this game along with &amp;ldquo;Shenzhen IO&amp;rdquo; and &amp;ldquo;Factorio&amp;rdquo; as an beginner tutorial for anyone who wants to be a software engineer.&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/1720850/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;
&lt;iframe src="https://store.steampowered.com/widget/504210/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;
&lt;iframe src="https://store.steampowered.com/widget/427520/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;h2 id="spoiler-alert"&gt;Spoiler Alert&lt;/h2&gt;
&lt;p&gt;** The following article includes huge spoilers for A=B Game. **&lt;/p&gt;
&lt;p&gt;If you have a different solution or a better solution. Feel free to share it with a comment.&lt;/p&gt;
&lt;h2 id="cpt1-ab"&gt;Cpt1. A=B&lt;/h2&gt;
&lt;h3 id="1-1-a-to-b"&gt;1-1. A to B&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;a=b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="1-2-uppercase"&gt;1-2. Uppercase&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;a=A
b=B
c=C
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="1-3-singleton"&gt;1-3. Singleton&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;aa=a
bb=b
cc=c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="1-4-singleton-2"&gt;1-4. Singleton 2&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;aaa=aa
aa=
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;For all substring which has more than &lt;code&gt;n&lt;/code&gt; &amp;lsquo;a&amp;rsquo;s, replace them with &lt;code&gt;n-1&lt;/code&gt; &amp;lsquo;a&amp;rsquo;s.&lt;/li&gt;
&lt;li&gt;For all &amp;ldquo;aa&amp;rdquo;s, remove them.&lt;/li&gt;
&lt;li&gt;For all singleton &amp;ldquo;a&amp;rdquo;s, keep it as-is.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="1-5-sort"&gt;1-5. Sort&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ba=ab
ca=ac
cb=bc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Bubble sort.&lt;/p&gt;
&lt;h3 id="1-6-compare"&gt;1-6. Compare&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ba=ab
ab=
aa=a
bb=b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Firstly, sort the string. Make it to &amp;ldquo;aaaa&amp;hellip;aabbb&amp;hellip;bb&amp;rdquo; pattern.&lt;/li&gt;
&lt;li&gt;If there&amp;rsquo;s an &amp;ldquo;ab&amp;rdquo; substring in the middle, remove it. &lt;/li&gt;
&lt;li&gt;After that, there will be only &amp;ldquo;a&amp;rdquo; or &amp;ldquo;b&amp;rdquo; in the string. &lt;/li&gt;
&lt;li&gt;Remove the redundant characters to make the answer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cpt2-keyword"&gt;Cpt2. Keyword&lt;/h2&gt;
&lt;h3 id="2-1-hello-world"&gt;2-1. Hello World&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;helloworld&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="2-2-aaa"&gt;2-2. AAA&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;aaa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;
&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="2-3-exactly-three"&gt;2-3. Exactly Three&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;aaaa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;span class="nv"&gt;aaa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="2-4-remainder"&gt;2-4. Remainder&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;aaa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="2-5-odd"&gt;2-5. Odd&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;ba&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ab&lt;/span&gt;
&lt;span class="nv"&gt;ca&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ac&lt;/span&gt;
&lt;span class="nv"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;
&lt;span class="nv"&gt;aaa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;bbb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;ccc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;span class="nv"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;span class="nv"&gt;cc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Sort the string to &amp;ldquo;aa&amp;hellip;aabbb&amp;hellip;bbbcc&amp;hellip;cc&amp;rdquo; pattern.&lt;/li&gt;
&lt;li&gt;Remove all &amp;ldquo;aaa&amp;rdquo;, &amp;ldquo;bbb&amp;rdquo;, &amp;ldquo;ccc&amp;rdquo; substring, this will keep the &lt;a href="https://en.wikipedia.org/wiki/Parity_(mathematics)"&gt;parity&lt;/a&gt; of each characters.&lt;/li&gt;
&lt;li&gt;If theres &amp;ldquo;aa&amp;rdquo;, &amp;ldquo;bb&amp;rdquo; or &amp;ldquo;cc&amp;rdquo; in the remaining string, it means that there&amp;rsquo;s at least one type of character has even number of appearances.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-6-the-only"&gt;2-6. The Only&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;aaa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;aa&lt;/span&gt;
&lt;span class="nv"&gt;bbb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bb&lt;/span&gt;
&lt;span class="nv"&gt;ccc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;cc&lt;/span&gt;
&lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="nv"&gt;bb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="nv"&gt;cc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;
&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;
&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;YY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Because for substring like &amp;ldquo;aaa..aa&amp;rdquo;, all &amp;ldquo;a&amp;rdquo;s has at least 1 neighbour which is same to itself.&lt;/li&gt;
&lt;li&gt;It means we can safely replace those substrings with a delimeter, marked as &amp;ldquo;X&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Check if the remaining string has exactly 1 character which is not &amp;ldquo;X&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-7-ascend"&gt;2-7. Ascend&lt;/h3&gt;
&lt;h4 id="solution1-9-lines"&gt;Solution1 (9 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;ba&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ab&lt;/span&gt;
&lt;span class="nv"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;
&lt;span class="nv"&gt;ca&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ac&lt;/span&gt;
&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xy&lt;/span&gt;
&lt;span class="nv"&gt;yx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xy&lt;/span&gt;
&lt;span class="nv"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;yc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Sort string to parttern &amp;ldquo;aa&amp;hellip;bb..cc&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Split every character &amp;ldquo;b&amp;rdquo; to &amp;ldquo;xy&amp;rdquo;, then sort the string to &amp;ldquo;aaa&amp;hellip;xx&amp;hellip;yy..cc&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Remove all the occurrences of &amp;ldquo;ax&amp;rdquo; and &amp;ldquo;yc&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;If:&lt;ul&gt;
&lt;li&gt;there&amp;rsquo;re remaining &amp;ldquo;a&amp;rdquo;s means &lt;code&gt;count(a) &amp;gt; count(b)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;there&amp;rsquo;re remaining &amp;ldquo;x&amp;rdquo;s means &lt;code&gt;count(b) &amp;gt; count(a)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;there&amp;rsquo;re remaining &amp;ldquo;y&amp;rdquo;s means &lt;code&gt;count(b) &amp;gt; count(c)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;there&amp;rsquo;re remaining &amp;ldquo;c&amp;rdquo;s means &lt;code&gt;count(b) &amp;gt; count(b)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Only if there&amp;rsquo;re any &amp;ldquo;xc&amp;rdquo;s in the remaining string, we&amp;rsquo;ll return &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Otherwise, return &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="solution2-8-lines"&gt;Solution2 (8 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;ba&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ab&lt;/span&gt;
&lt;span class="nv"&gt;ca&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ac&lt;/span&gt;
&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;cb&lt;/span&gt;
&lt;span class="nv"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;
&lt;span class="nv"&gt;cx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xc&lt;/span&gt;
&lt;span class="nv"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Sort string to pattern &amp;ldquo;aaa&amp;hellip;cccc&amp;hellip;bb&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;For every occurrence of &amp;ldquo;cb&amp;rdquo;, replace it with &amp;ldquo;x&amp;rdquo;. If there&amp;rsquo;re &lt;code&gt;n&lt;/code&gt; &amp;ldquo;x&amp;rdquo;s, means there&amp;rsquo;re &lt;code&gt;n&lt;/code&gt; &amp;ldquo;b&amp;rdquo;s and &lt;code&gt;n&lt;/code&gt; &amp;ldquo;c&amp;rdquo;s.&lt;/li&gt;
&lt;li&gt;Move every &amp;ldquo;x&amp;rdquo; to the front of &amp;ldquo;c&amp;rdquo;s.&lt;/li&gt;
&lt;li&gt;Eliminate every &amp;ldquo;a&amp;rdquo; with adjacent &amp;ldquo;x&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;If:&lt;ul&gt;
&lt;li&gt;there&amp;rsquo;re remaining &amp;ldquo;a&amp;rdquo;s means &lt;code&gt;count(a) &amp;gt; count(b)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;there&amp;rsquo;re remaining &amp;ldquo;x&amp;rdquo;s means &lt;code&gt;count(b) &amp;gt; count(a)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;there&amp;rsquo;s no remaining &amp;ldquo;c&amp;rdquo;s means &lt;code&gt;count(b) &amp;gt; count(a)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;We match the pattern &amp;ldquo;xc&amp;rdquo; as a signal for returning &amp;ldquo;true&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Otherwise, return &amp;ldquo;false&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-8-most"&gt;2-8. Most&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;ba&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ab&lt;/span&gt;
&lt;span class="nv"&gt;ca&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ac&lt;/span&gt;
&lt;span class="nv"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;
&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xy&lt;/span&gt;
&lt;span class="nv"&gt;yx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xy&lt;/span&gt;
&lt;span class="nv"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;yc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;ac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Similar idea from 2-7.&lt;/li&gt;
&lt;li&gt;Sort then split, make the string like &amp;ldquo;aaa&amp;hellip;xxx..yyy&amp;hellip;ccc&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s easy to know that &lt;code&gt;count(x) == count(y) == count(b)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Eliminate all occurances of &amp;ldquo;ax&amp;rdquo;s and &amp;ldquo;yc&amp;rdquo;s.&lt;/li&gt;
&lt;li&gt;It means:&lt;ul&gt;
&lt;li&gt;&lt;code&gt;count(remaining a) = count(a) - count(b)&lt;/code&gt; if there&amp;rsquo;re remaining &amp;ldquo;a&amp;rdquo;s &lt;/li&gt;
&lt;li&gt;&lt;code&gt;count(remaining x) = count(b) - count(a)&lt;/code&gt; if there&amp;rsquo;re remaining &amp;ldquo;x&amp;rdquo;s &lt;/li&gt;
&lt;li&gt;&lt;code&gt;count(remaining y) = count(b) - count(c)&lt;/code&gt; if there&amp;rsquo;re remaining &amp;ldquo;y&amp;rdquo;s&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count(remaining c) = count(c) - count(b)&lt;/code&gt; if there&amp;rsquo;re remaining &amp;ldquo;c&amp;rdquo;s&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If there&amp;rsquo;re only &amp;ldquo;x&amp;rdquo;s and &amp;ldquo;y&amp;rdquo;s remain, it means &amp;ldquo;b&amp;rdquo; has the largests count&lt;/li&gt;
&lt;li&gt;If there&amp;rsquo;re only &amp;ldquo;a&amp;rdquo;s or &amp;ldquo;ay&amp;rdquo;s remain, it means &lt;code&gt;count(a) &amp;gt; count(b) &amp;gt;= count(c)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If there&amp;rsquo;re only &amp;ldquo;c&amp;rdquo;s or &amp;ldquo;xc&amp;rdquo;s remain, it means &lt;code&gt;count(c) &amp;gt; count(b) &amp;gt;= count(a)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If there&amp;rsquo;re only &amp;ldquo;a&amp;rdquo;s and &amp;ldquo;c&amp;rdquo;s remain, we will eliminate all &amp;ldquo;ac&amp;rdquo;s, the type of character left is the final answer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-9-least"&gt;2-9. Least&lt;/h3&gt;
&lt;h4 id="solution1-11-lines"&gt;Solution1 (11 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;ba&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ab&lt;/span&gt;
&lt;span class="nv"&gt;ca&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ac&lt;/span&gt;
&lt;span class="nv"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;
&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xy&lt;/span&gt;
&lt;span class="nv"&gt;yx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xy&lt;/span&gt;
&lt;span class="nv"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;yc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;xy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;ac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Similar idea from 2-8&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="solution2-9-lines"&gt;Solution2 (9 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;ba&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ab&lt;/span&gt;
&lt;span class="nv"&gt;ca&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ac&lt;/span&gt;
&lt;span class="nv"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bc&lt;/span&gt;
&lt;span class="nv"&gt;ab&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;
&lt;span class="nv"&gt;xb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bx&lt;/span&gt;
&lt;span class="nv"&gt;xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;bc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;ac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Similar idea from 2-7, solution2&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cpt3-start-and-end"&gt;Cpt3. Start and End&lt;/h2&gt;
&lt;h3 id="3-1-remove"&gt;3-1. Remove&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="3-2-spin"&gt;3-2. Spin&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="3-3-a-to-b-2"&gt;3-3. A to B 2&lt;/h3&gt;
&lt;h4 id="solution1-4-lines"&gt;Solution1 (4 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution2-5-lines"&gt;Solution2 (5 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="nv"&gt;aX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;XX&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="nv"&gt;Xa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;XX&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="3-4-swap"&gt;3-4. Swap&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XXXXXXXXa&lt;/span&gt;
&lt;span class="nv"&gt;bX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Move all starting &amp;ldquo;a&amp;rdquo;s to the end of the string, and make it &amp;ldquo;XXXXXXXXa&amp;rdquo;. e.g. &lt;code&gt;aacbbb -&amp;gt; cbbbXXXXXXXXaXXXXXXXXa&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If there&amp;rsquo;re &amp;ldquo;b&amp;rdquo;s at the end of the original string, it will definitely followed with &amp;ldquo;X&amp;rdquo;. So we move &amp;ldquo;bX&amp;rdquo; to the beginning of the string.&lt;/li&gt;
&lt;li&gt;Remove all redundant &amp;ldquo;X&amp;rdquo;s.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="3-5-match"&gt;3-5. Match&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;aXaY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;bXbY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;cXcY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XaY&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XbY&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XcY&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Say the original string is &amp;ldquo;uv&amp;hellip;w&amp;rdquo; (&amp;ldquo;u&amp;rdquo;, &amp;ldquo;v&amp;rdquo; and &amp;ldquo;w&amp;rdquo; could be arbitrary characters among &amp;ldquo;a&amp;rdquo;, &amp;ldquo;b&amp;rdquo; and &amp;ldquo;c&amp;rdquo;).&lt;/li&gt;
&lt;li&gt;Firstly move the starting &amp;ldquo;u&amp;rdquo; to the end of the string, added with &amp;ldquo;X&amp;rdquo; and &amp;ldquo;Y&amp;rdquo;, i.e. &lt;code&gt;uv...w -&amp;gt; v...wXuY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If &amp;ldquo;wXuY&amp;rdquo; is &amp;ldquo;aXaY&amp;rdquo;, &amp;ldquo;bXbY&amp;rdquo; or &amp;ldquo;cXcY&amp;rdquo;, return &lt;code&gt;true&lt;/code&gt;. Otherwise, return &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="3-6-most-2"&gt;3-6. Most 2&lt;/h3&gt;
&lt;h3 id="solution1-12-lines"&gt;Solution1 (12 Lines)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ba=ab
cb=bc
ca=ac
ab=(start)X
Xa=aa
X=b
bc=(start)Y
Yb=bb
Y=c
ac=(start)Z
Za=aa
Z=c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="solution2-11-lines"&gt;Solution2 (11 Lines)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ba=ab
cb=bc
ca=ac
ab=(start)X
Xa=aa
X=b
bc=(start)Y
Yc=cc
ac=(start)Y
Ya=aa
Y=b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="3-7-palindrome"&gt;3-7. Palindrome&lt;/h3&gt;
&lt;h4 id="solution1-10-lines"&gt;Solution1 (10 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;XaX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;span class="nv"&gt;XbX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;span class="nv"&gt;XcX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;aXa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;bXb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;cXc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Xa&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Xb&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Xc&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution2-8-lines_1"&gt;Solution2 (8 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;aXaX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;bXbX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;cXcX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XaX&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XbX&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XcX&lt;/span&gt;
&lt;span class="nv"&gt;XX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="cpt4-once-upon-a-time"&gt;Cpt4. Once Upon A Time&lt;/h2&gt;
&lt;h3 id="4-1-hello-2"&gt;4-1. Hello 2&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(once)=(start)hello
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-2-remove-2"&gt;4-2. Remove 2&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(once)a=
(once)a=
(once)a=
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-3-cut"&gt;4-3. Cut&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(once)=(start)XXX
Xa=
Xb=
Xc=
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-4-remove-3"&gt;4-4. Remove 3&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XXX&lt;/span&gt;
&lt;span class="nv"&gt;bX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Xb&lt;/span&gt;
&lt;span class="nv"&gt;cX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Xc&lt;/span&gt;
&lt;span class="nv"&gt;aX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-5-reverse"&gt;4-5. Reverse&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="nv"&gt;Xa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Ya&lt;/span&gt;
&lt;span class="nv"&gt;Xb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Yb&lt;/span&gt;
&lt;span class="nv"&gt;Xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Yc&lt;/span&gt;
&lt;span class="nv"&gt;aY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;bY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;cY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-6-reverse-2"&gt;4-6. Reverse 2&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XXXXXXXXXX&lt;/span&gt;
&lt;span class="nv"&gt;aX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;bX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;cX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-7-cut-2"&gt;4-7. Cut 2&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXDXX&lt;/span&gt;
&lt;span class="nv"&gt;Xa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;Xb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;Xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;Da&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;Db&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;Dc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXDXX&amp;rdquo; = 58 * &amp;ldquo;X&amp;rdquo; + &amp;ldquo;D&amp;rdquo; + 2 * &amp;ldquo;X&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;60 &amp;ldquo;X&amp;rdquo;s is the &lt;a href="https://en.wikipedia.org/wiki/Least_common_multiple"&gt;LCM&lt;/a&gt; of all possible length of the remaing string (2, 3, 4, 5, 6)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-8-clone"&gt;4-8. Clone&lt;/h3&gt;
&lt;h4 id="solution1-13-lines"&gt;Solution1 (13 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XXX&lt;/span&gt;
&lt;span class="nv"&gt;Ya&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;Yb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;Yc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;XXXa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;YaaXX&lt;/span&gt;
&lt;span class="nv"&gt;XXXb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;YbbXX&lt;/span&gt;
&lt;span class="nv"&gt;XXXc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;YccXX&lt;/span&gt;
&lt;span class="nv"&gt;XXa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;YaaX&lt;/span&gt;
&lt;span class="nv"&gt;XXb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;YbbX&lt;/span&gt;
&lt;span class="nv"&gt;XXc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;YccX&lt;/span&gt;
&lt;span class="nv"&gt;Xa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Yaa&lt;/span&gt;
&lt;span class="nv"&gt;Xb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Ybb&lt;/span&gt;
&lt;span class="nv"&gt;Xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Ycc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution2-16-lines"&gt;Solution2 (16 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XXX&lt;/span&gt;
&lt;span class="nv"&gt;Xa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;aA&lt;/span&gt;
&lt;span class="nv"&gt;Xb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;bB&lt;/span&gt;
&lt;span class="nv"&gt;Xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;cC&lt;/span&gt;
&lt;span class="nv"&gt;Aa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;aA&lt;/span&gt;
&lt;span class="nv"&gt;Ab&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bA&lt;/span&gt;
&lt;span class="nv"&gt;Ac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;cA&lt;/span&gt;
&lt;span class="nv"&gt;Ba&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;aB&lt;/span&gt;
&lt;span class="nv"&gt;Bb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bB&lt;/span&gt;
&lt;span class="nv"&gt;Bc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;cB&lt;/span&gt;
&lt;span class="nv"&gt;Cc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;cC&lt;/span&gt;
&lt;span class="nv"&gt;Cb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bC&lt;/span&gt;
&lt;span class="nv"&gt;Ca&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;aC&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution3-10-lines"&gt;Solution3 (10 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;Xa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;AaY&lt;/span&gt;
&lt;span class="nv"&gt;Xb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;BbY&lt;/span&gt;
&lt;span class="nv"&gt;Xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;CcY&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-9-a-to-b-3"&gt;4-9. A to B 3&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(once)=(start)X
Xa=bX
Xb=aX
Xc=cX
X=
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-10-half"&gt;4-10. Half&lt;/h3&gt;
&lt;h4 id="solution1-9-lines_1"&gt;Solution1 (9 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(once)=(start)X
Xa=Y
Xb=Y
Xc=Y
Ya=aX
Yb=bX
Yc=cX
Y=
X=
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;X&amp;rdquo; is the operator to remove the character.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Y&amp;rdquo; is the operator to keep current character and remove the next character.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="solution2-8-lines_2"&gt;Solution2 (8 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(once)=(start)XX
XXa=X
XXb=X
XXc=X
Xa=aXX
Xb=bXX
Xc=cXX
X=
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;XX&amp;rdquo; is the operator to remove the character.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;X&amp;rdquo; is the operator to keep current character and remove the next character.&lt;/li&gt;
&lt;li&gt;This could help us to save 1 line of code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-11-clone-2"&gt;4-11. Clone 2&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Z&lt;/span&gt;
&lt;span class="nv"&gt;XZ&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;AY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;BY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;CY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;Xa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;AYaX&lt;/span&gt;
&lt;span class="nv"&gt;Xb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;BYbX&lt;/span&gt;
&lt;span class="nv"&gt;Xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;CYcX&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-12-to-b-or-not-to-b"&gt;4-12. To B or not to B&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(once)b=bX
(once)=Y
X=(start)Y
YYa=bYY
Yb=bY
Yc=cY
Ya=cY
Y=
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-13-center"&gt;4-13. Center&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;aY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;bY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;cY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;aYX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;
&lt;span class="nv"&gt;bYX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;
&lt;span class="nv"&gt;cYX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-14-center-2"&gt;4-14. Center 2&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Lx&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;R&lt;/span&gt;
&lt;span class="nv"&gt;LxaR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;LxbR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;LxcR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;Lxa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;aLY&lt;/span&gt;
&lt;span class="nv"&gt;Lxb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bLY&lt;/span&gt;
&lt;span class="nv"&gt;Lxc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;cLY&lt;/span&gt;
&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;
&lt;span class="nv"&gt;aRx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xRa&lt;/span&gt;
&lt;span class="nv"&gt;bRx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xRb&lt;/span&gt;
&lt;span class="nv"&gt;cRx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xRc&lt;/span&gt;
&lt;span class="nv"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xa&lt;/span&gt;
&lt;span class="nv"&gt;bx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xb&lt;/span&gt;
&lt;span class="nv"&gt;cx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;xc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-15-expansion"&gt;4-15. Expansion&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;YYYYYYXXXXXYYYYYXXXXYYYYXXXYYYXXYYXY&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;E&lt;/span&gt;
&lt;span class="nv"&gt;Xa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;aa&lt;/span&gt;
&lt;span class="nv"&gt;Xb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bb&lt;/span&gt;
&lt;span class="nv"&gt;Xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;cc&lt;/span&gt;
&lt;span class="nv"&gt;Ya&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;Yb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;Yc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;XE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;E&lt;/span&gt;
&lt;span class="nv"&gt;YE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;E&lt;/span&gt;
&lt;span class="nv"&gt;E&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-16-merge"&gt;4-16. Merge&lt;/h3&gt;
&lt;h4 id="solution1-10-lines_1"&gt;Solution1 (10 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;,&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;XXXXXXXXXXXZ&lt;/span&gt;
&lt;span class="nv"&gt;YXX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;YX&lt;/span&gt;
&lt;span class="nv"&gt;YX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;Z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;
&lt;span class="nv"&gt;Ya&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;Yb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;Yc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;Xa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;aZ&lt;/span&gt;
&lt;span class="nv"&gt;Xb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;bZ&lt;/span&gt;
&lt;span class="nv"&gt;Xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;cZ&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution2-9-lines_1"&gt;Solution2 (9 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Xa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Xb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;Xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;Xa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XaX&lt;/span&gt;
&lt;span class="nv"&gt;Xb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XbX&lt;/span&gt;
&lt;span class="nv"&gt;Xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XcX&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;,&lt;span class="o"&gt;=&lt;/span&gt;
,&lt;span class="o"&gt;=&lt;/span&gt;,&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="cpt5-math"&gt;Cpt5. Math&lt;/h2&gt;
&lt;h3 id="5-1-count"&gt;5-1. Count&lt;/h3&gt;
&lt;h4 id="solution1-11-lines_1"&gt;Solution1 (11 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XYXXYXXXYXXXXYXXXXXYXXXXXXY&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;XY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;XXY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;aa&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;XXXY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;aaaa&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;XXXXY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;aaaaaaaa&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;XXXXXY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;aaaaaaaaaaaaaaaa&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;XXXXXXY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&lt;/span&gt;
&lt;span class="nv"&gt;aX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution2-8-lines_3"&gt;Solution2 (8 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XYXXYXXXXYXXXXXXXXYXXXXXXXXXXXXXXXXYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXY&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;AX1&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;AX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution3-7-lines"&gt;Solution3 (7 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;XYXXYXXXXYXXXXXXXXYXXXXXXXXXXXXXXXXYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXY&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;aX1&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;aX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution4-5-lines"&gt;Solution4 (5 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(once)=X
X1=(start)aX
X0=(start)X
Xa=aaX
X=
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution5-11-lines-no-keyword"&gt;Solution5 (11 Lines, no keyword)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;X$&lt;/span&gt;
&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;Y$&lt;/span&gt;
&lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="n"&gt;YXXXXX$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;XXXXXX$aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&lt;/span&gt;
&lt;span class="n"&gt;YXXXX$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;XXXXX$aaaaaaaaaaaaaaaa&lt;/span&gt;
&lt;span class="n"&gt;YXXX$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;XXXX$aaaaaaaa&lt;/span&gt;
&lt;span class="n"&gt;YXX$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;XXX$aaaa&lt;/span&gt;
&lt;span class="n"&gt;YX$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;XX$aa&lt;/span&gt;
&lt;span class="n"&gt;Y$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;X$a&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="5-2-a-1"&gt;5-2. A + 1&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;X0&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="5-3-a-b"&gt;5-3. A + B&lt;/h3&gt;
&lt;h4 id="solution-1-14-lines"&gt;Solution 1 (14 lines)&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Not a good solution&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=|&lt;/span&gt;&lt;span class="nv"&gt;z0&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=|&lt;/span&gt;&lt;span class="nv"&gt;z1&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z0&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;111&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z1&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution-2-8-lines"&gt;Solution 2 (8 lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;+1 = |x+
+0 = |+
x| = |xx
| = 
1x = x0
0x = 1
x = 1
+ =
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="5-4-a-b"&gt;5-4. A - B&lt;/h3&gt;
&lt;h4 id="solution-1-18-lines"&gt;Solution 1 (18 lines)&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Not a good solution, too&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;once&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;G&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=|&lt;/span&gt;&lt;span class="nv"&gt;z0&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;G&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;G1&lt;/span&gt;
&lt;span class="nv"&gt;G1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=|&lt;/span&gt;&lt;span class="nv"&gt;z1&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;G&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;G&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z1&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;G1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=|&lt;/span&gt;&lt;span class="nv"&gt;z0&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;GG&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;G&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z0&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="o"&gt;|=&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution-2-8-lines_1"&gt;Solution 2 (8 lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;-1 = |x-
-0 = |-
x| = |xx
| = 
1x = 0
0x = x1
- = 
(start)0 = 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution-3-11-lines-no-keyword"&gt;Solution 3 (11 lines, no keyword)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;-1 = |x-
-0 = |-
x| = |xx
| = 
1x = 0
0x = x1
- = yyyyyyy
0y = y0
1y = y1
y0 = 
y =
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="5-5-a-b"&gt;5-5. A * B&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;No solution yet&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="5-6-a-b"&gt;5-6. A / B&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;No solution yet&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="cpt6-aftermath"&gt;Cpt6. Aftermath&lt;/h2&gt;
&lt;h3 id="6-1-hello-again"&gt;6-1. Hello Again&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;c=a
b=a
aa=a
a=helloworld
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="6-2-palinedrome-2"&gt;6-2. Palinedrome 2&lt;/h3&gt;
&lt;h4 id="solution1-32-lines"&gt;Solution1 (32 Lines)&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Not a good solution&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;^=^&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;
&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;
&lt;span class="nv"&gt;XA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;AX&lt;/span&gt;
&lt;span class="nv"&gt;XB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;BX&lt;/span&gt;
&lt;span class="nv"&gt;XC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;CX&lt;/span&gt;
&lt;span class="nv"&gt;YA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;AY&lt;/span&gt;
&lt;span class="nv"&gt;YB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;BY&lt;/span&gt;
&lt;span class="nv"&gt;YC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;CY&lt;/span&gt;
&lt;span class="nv"&gt;ZA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;AZ&lt;/span&gt;
&lt;span class="nv"&gt;ZB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;BZ&lt;/span&gt;
&lt;span class="nv"&gt;ZC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;CZ&lt;/span&gt;
&lt;span class="nv"&gt;AX&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;BY&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;CZ&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;Z&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;
&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;
&lt;span class="nv"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;Z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="o"&gt;^=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution2-21-lines"&gt;Solution2 (21 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;aa&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;AA&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;^=^&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;
&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;
&lt;span class="nv"&gt;XA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;AX&lt;/span&gt;
&lt;span class="nv"&gt;XB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;BX&lt;/span&gt;
&lt;span class="nv"&gt;XC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;CX&lt;/span&gt;
&lt;span class="nv"&gt;AXXX&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;BXXXXX&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;CXXXXXXX&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;XXX&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;XXXXX&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;XXXXXXX&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;XX&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;
&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="6-3-to-b-or-not-to-b-2"&gt;6-3. To B or not to B 2&lt;/h3&gt;
&lt;h4 id="solution-1-14-lines_1"&gt;Solution 1 (14 Lines)&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Not a good solution&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;^=^&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="nv"&gt;XbY&lt;/span&gt;
&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;XbY&lt;/span&gt;
&lt;span class="nv"&gt;AX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Xb&lt;/span&gt;
&lt;span class="nv"&gt;cX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Xc&lt;/span&gt;
&lt;span class="nv"&gt;YA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bY&lt;/span&gt;
&lt;span class="nv"&gt;Yc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;cY&lt;/span&gt;
&lt;span class="o"&gt;^=&lt;/span&gt;
&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="solution-2-13-lines"&gt;Solution 2 (13 Lines)&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=^&lt;/span&gt;&lt;span class="nv"&gt;AAAAAAAc&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;^=^&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;^=^&lt;/span&gt;&lt;span class="nv"&gt;XbX&lt;/span&gt;
&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;XbX&lt;/span&gt;&lt;span class="p"&gt;$&lt;/span&gt;

&lt;span class="nv"&gt;XAAAAAAAc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;bX&lt;/span&gt;
&lt;span class="nv"&gt;AAAAAAAcX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;Xb&lt;/span&gt;
&lt;span class="o"&gt;^=&lt;/span&gt;
&lt;span class="p"&gt;$&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;Xc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;cAX&lt;/span&gt;
&lt;span class="nv"&gt;cX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;XAcA&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="appendix"&gt;Appendix&lt;/h2&gt;
&lt;h3 id="proof-of-turing-completeness-explained"&gt;Proof of Turing Completeness Explained&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://web.stanford.edu/class/archive/cs/cs103/cs103.1176/lectures/20/Small20.pdf"&gt;Ref&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="implement-your-own-a2b-language"&gt;Implement Your Own A2B Language&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/Wizmann/a2b-lang"&gt;Wizmann/a2b-lang&lt;/a&gt;&lt;/p&gt;</content><category term="Blog"/><category term="game"/><category term="a2b"/><category term="solution"/></entry><entry><title>浅淡TCP BBR</title><link href="https://wizmann.top/bbr-intro.html" rel="alternate"/><published>2021-08-17T00:00:00+08:00</published><updated>2021-08-17T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2021-08-17:/bbr-intro.html</id><summary type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;p&gt;在一对跨地域的机器（美国&amp;lt;-&amp;gt;香港），使用TCP（Cubic拥塞控制算法）通信throughput最高2MB/s，丢包率0.02%。使用UDP通信throughput最高能达到140MB/s。&lt;/p&gt;
&lt;p&gt;这是一个非常典型的长肥管道（LFN），并且丢包 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;p&gt;在一对跨地域的机器（美国&amp;lt;-&amp;gt;香港），使用TCP（Cubic拥塞控制算法）通信throughput最高2MB/s，丢包率0.02%。使用UDP通信throughput最高能达到140MB/s。&lt;/p&gt;
&lt;p&gt;这是一个非常典型的长肥管道（LFN），并且丢包率比较高。尝试使用BBR算法后，throughput可达50MB/s+（Windows系统，通信协议使用用户态MsQuic）。&lt;/p&gt;
&lt;h2 id="loss-based-congestion-control-algorithm"&gt;Loss-based Congestion Control Algorithm&lt;/h2&gt;
&lt;p&gt;Reno和Cubic是比较经典的，用于TCP的拥塞控制算法。这一类算法使用的是基于丢包反馈的思想，即一旦产生了丢包，就认为链路上产生了拥塞。先将拥塞窗口减半，再进入快速恢复模式。&lt;/p&gt;
&lt;p&gt;在快速恢复完成后中，就又会重新进入拥塞避免阶段。&lt;/p&gt;
&lt;p&gt;&lt;img alt="TCP-Reno-Cubic" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/21-08-16/2021-08-16_23-07-29.png"&gt;&lt;/p&gt;
&lt;p&gt;Reno当收到一个ACK包时，会将拥塞窗口增大一个MSS，窗口大小线性增长。而Cubic使用的是一个基于上次拥塞事件产生时间的三次函数，所以拥塞窗口能更快速的恢复到拥塞事件发生之前的大小。&lt;/p&gt;
&lt;p&gt;但无论是Reno还是Cubic，在遭遇高丢包率的时候，其拥塞控制窗口的大小会一直处于一个非常小的状态。&lt;/p&gt;
&lt;p&gt;在RTT较大时，拥塞窗口的大小增长速度更加缓慢，使得带宽利用率长时间维持在一个较低的状态。&lt;/p&gt;
&lt;p&gt;下图为Cubic在有丢包（0.002%, 0.02%, 0.2%, 1%, 2%），高延时（200ms RTT）的网络条件下throughput数据。&lt;/p&gt;
&lt;p&gt;&lt;img alt="cubic-bandwidth" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/21-08-17/2021-08-17_00-18-45.png"&gt;&lt;/p&gt;
&lt;h2 id="bbr-congestion-based-congestion-control"&gt;BBR - Congestion-based Congestion Control&lt;/h2&gt;
&lt;p&gt;不同于Reno和Cubic，BBR并没有使用“丢包”做为拥塞产生的信号，而是构建了一个反馈系统，通过时延的变化来确定链路上是否发生了拥塞。&lt;/p&gt;
&lt;h3 id="_2"&gt;拥塞产生的三个阶段&lt;/h3&gt;
&lt;p&gt;&lt;img alt="BBR-3-stages" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/21-08-17/2021-08-17_00-58-34.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;App Limited 应用限制阶段  &lt;br&gt;
在此阶段，数据传输速率由用户程序决定。用户程序并没有利用所有的带宽，RTT维持稳定&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bandwidth Limited 带宽限制阶段            &lt;br&gt;
在此阶段，数据传输速率由链路带宽所决定，有效吞吐量等于链路带宽。但由于链路缓存的存在，发送端的发送速率可以略大于链路带宽。此时数据开始在链路缓存上堆积，RTT增加&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Buffer Limited 缓冲区限制阶段           &lt;br&gt;
当链路缓存无法容纳所有的数据包时，就会产生丢包&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Loss-based拥塞控制算法会在阶段3的时候产生“拥塞”信号，但是此时大概率为时已晚。因为链路缓存堆积的数据已经开始影响RTT，并且各个节点之间的缓存大小差异，还会导致短时间内的持续丢包，使得拥塞窗口大小急剧减小。&lt;/p&gt;
&lt;p&gt;而BBR会将拥塞控制在阶段1和阶段2的交界处，这样可以最大化利用带宽，并且使得链路时延最小。&lt;/p&gt;
&lt;h3 id="_3"&gt;确定拥塞窗口的大小&lt;/h3&gt;
&lt;p&gt;从理论上分析，要使一条连接同时保持最高throughput和最小的延迟，那么其发送速率一定等于网络带宽。此时，在途的数据大小BDP = BtlBw × RTprop，就可以用满链路的带宽而不产生拥塞。&lt;/p&gt;
&lt;p&gt;BDP意为“带宽时延乘积”。而BtlBw意为“瓶颈带宽”，即为整条链路中，带宽最小的部分。RTprop意为“链路固有传输延迟”。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;RTT（往返时延）与RTprop（链路固有传输延迟）的区别是：RTT包括了收发两端应用层的时延，而RTprop只包含网络传播的时延&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;不凑巧的是，在通信中我们几乎无法直接确定BtlBw和RTprop。BBR建立了一个模型来对其进行估计。公式如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="rtprop-hat" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/21-08-17/2021-08-17_10-02-28.png"&gt;&lt;/p&gt;
&lt;p&gt;η代表的是网络队列的抖动、接收方ACK时延等等。&lt;/p&gt;
&lt;p&gt;&lt;img alt="btlbw-hat" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/21-08-17/2021-08-17_10-04-06.png"&gt;&lt;/p&gt;
&lt;p&gt;但是，时延与带宽无法同时探测。因为探测时延时，我们必然要减慢发包速度，排空队列避免拥塞；而探测带宽时，我们需要尽量占满带宽，以检测ACK速率是否发生变化。所以时延与带宽的探测需要交替进行。&lt;/p&gt;
&lt;h4 id="probertt-"&gt;ProbeRTT - 时延探测&lt;/h4&gt;
&lt;p&gt;BBR每10秒钟会进入时延探测状态。在此状态下，BBR会限制拥塞窗口的大小到4个MSS（&lt;a href="https://blog.csdn.net/dog250/article/details/72042516"&gt;为什么？&lt;/a&gt;）。当收到ACK包后，会更新MinRTT的取样值。&lt;/p&gt;
&lt;h4 id="probebw-"&gt;ProbeBW - 带宽探测&lt;/h4&gt;
&lt;p&gt;BBR大部分时间都会处于ProbeBW状态。&lt;/p&gt;
&lt;p&gt;BBR通过计算包的发送时间与收到ACK时间的差来确定带宽，使用“送达速度”来拟合带宽。&lt;/p&gt;
&lt;p&gt;&lt;img alt="bw-probe-pacing" src="https://raw.githubusercontent.com/Wizmann/assets/6b0dcc0d2f7b2446ea0c3ca6faec29da6f28dc7e/wizmann-pic/21-08-17/image.png"&gt;&lt;/p&gt;
&lt;p&gt;同时，BBR会采用gain cycle来随机微调（+25%, -25%, 不变）发送速率，以实时检测链路上带宽的变化。（图中的绿线看起来像心电图的部分）&lt;/p&gt;
&lt;h3 id="_4"&gt;性能比较&lt;/h3&gt;
&lt;p&gt;这里是Cubic与BBR在有丢包（0.002%, 0.02%, 0.2%, 1%, 2%），高延时（200ms RTT）的网络条件下的throughput对比。&lt;/p&gt;
&lt;p&gt;&lt;img alt="perf-bbr-cubic" src="https://raw.githubusercontent.com/Wizmann/assets/8a78e8e7c7193f4bf5d6de01997f21491f3794ab/wizmann-pic/21-08-17/Snipaste_2021-08-17_14-54-21.png"&gt;&lt;/p&gt;
&lt;h2 id="_5"&gt;杂项&lt;/h2&gt;
&lt;p&gt;在Linux系统下，可以使用tc命令模拟不同的网络状态。&lt;/p&gt;
&lt;p&gt;例如100ms延迟（RTT=2*延迟），1%丢包率：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;tc&lt;span class="w"&gt; &lt;/span&gt;qdisc&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;lo&lt;span class="w"&gt; &lt;/span&gt;root&lt;span class="w"&gt; &lt;/span&gt;handle&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:0&lt;span class="w"&gt; &lt;/span&gt;netem&lt;span class="w"&gt; &lt;/span&gt;delay&lt;span class="w"&gt; &lt;/span&gt;100msec&lt;span class="w"&gt; &lt;/span&gt;loss&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在Windows下可以使用&lt;a href="http://jagt.github.io/clumsy/"&gt;Clumsy&lt;/a&gt;进行模拟，但是有怀疑其会严重影响网络性能，效果有待进一步测试。&lt;/p&gt;
&lt;p&gt;在Linux系统下，可以使用以下命令替换系统congestion control算法。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;sysctl&lt;span class="w"&gt; &lt;/span&gt;-w&lt;span class="w"&gt; &lt;/span&gt;net.ipv4.tcp_congestion_control&lt;span class="o"&gt;=&lt;/span&gt;cubic
sudo&lt;span class="w"&gt; &lt;/span&gt;sysctl&lt;span class="w"&gt; &lt;/span&gt;-w&lt;span class="w"&gt; &lt;/span&gt;net.ipv4.tcp_congestion_control&lt;span class="o"&gt;=&lt;/span&gt;bbr
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://juejin.cn/post/6844904065759969287"&gt;浅谈TCP/IP传输层TCP BBR算法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/CUBIC_TCP"&gt;CUBIC TCP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://queue.acm.org/detail.cfm?id=3022184"&gt;BBR: Congestion-Based Congestion Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/facebookincubator/mvfst"&gt;facebookincubator/mvfst&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.csdn.net/dog250/article/details/72042516"&gt;使用TCP时序图解释BBR拥塞控制算法的几个细节&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="tcp"/><category term="networking"/><category term="bbr"/></entry><entry><title>论文阅读-WiscKey：SSD友好的KV分离存储引擎</title><link href="https://wizmann.top/paper-wisckey.html" rel="alternate"/><published>2021-08-15T00:00:00+08:00</published><updated>2021-08-15T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2021-08-15:/paper-wisckey.html</id><summary type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;h3 id="lsm-tree"&gt;基于LSM-Tree的存储引擎&lt;/h3&gt;
&lt;p&gt;Log-Structed Merge-Tree (a.k.a. LSM-Tree)是当下常用的一种基于磁盘的存储引擎。与Hash索引和B-Tree同为数据库核心的数据结构。&lt;/p&gt;
&lt;p&gt;LSM-Tree的优势在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;无需将所有的Key索引在内存中。可以通过分级查找的方式，查 …&lt;/li&gt;&lt;/ol&gt;</summary><content type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;h3 id="lsm-tree"&gt;基于LSM-Tree的存储引擎&lt;/h3&gt;
&lt;p&gt;Log-Structed Merge-Tree (a.k.a. LSM-Tree)是当下常用的一种基于磁盘的存储引擎。与Hash索引和B-Tree同为数据库核心的数据结构。&lt;/p&gt;
&lt;p&gt;LSM-Tree的优势在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;无需将所有的Key索引在内存中。可以通过分级查找的方式，查询到特定KV在磁盘中的偏移量&lt;/li&gt;
&lt;li&gt;数据写入与合并使用顺序追加写，最大程度的利用磁盘的顺序写性能&lt;/li&gt;
&lt;li&gt;对于数据写入，会使用batch方式写入磁盘&lt;/li&gt;
&lt;li&gt;支持范围查询&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;LSM-Tree的劣势在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;读放大与写放大&lt;/li&gt;
&lt;li&gt;无法对单条数据加锁（事务支持）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;现在常用的LevelDB和RocksDB，都是基于LSM-Tree的存储引擎。&lt;/p&gt;
&lt;p&gt;&lt;img alt="LSM-Tree-Architecture" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/21-08-14/2021-08-14_18-00-50.png"&gt;&lt;/p&gt;
&lt;h3 id="wisckey"&gt;WiscKey主要解决的问题&lt;/h3&gt;
&lt;p&gt;LSM-Tree在性能上面的瓶颈主要在于读写的放大。简单说来，假设你的磁盘最大带宽为4GB/s，读写放大倍数为10，那么在应用层的有效吞吐量（&lt;a href="https://en.wikipedia.org/wiki/Goodput"&gt;Goodput&lt;/a&gt;）最多只能达到400MB/s。并且，对于一些大数据集，读写放大的值有可能会非常大（大于100）。&lt;/p&gt;
&lt;p&gt;那么是什么原因导致的读写放大呢？我们下面分开讨论。&lt;/p&gt;
&lt;h4 id="_2"&gt;读放大&lt;/h4&gt;
&lt;p&gt;我们重温一下LSM-Tree的查询机制：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先在mutable memtable中进行查找&lt;/li&gt;
&lt;li&gt;然后在immutable memtable中进行查找&lt;/li&gt;
&lt;li&gt;最后在不同的LSM-Tree层级中的SST file中进行查找&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于1和2，都是内存操作，其耗时与读取磁盘相比可以忽略不计。&lt;br&gt;
对于3，SST file文件的查找会先使用二分查找定位特定KV位于该层的哪一个SST文件中。&lt;/p&gt;
&lt;p&gt;如果特定的KV不存在于此SST文件中，会被常驻内存的bloom filter过滤掉，不会真正的读取文件。（大概率，bloom filter的原理了解一下）&lt;/p&gt;
&lt;p&gt;如果特定的KV在此SST文件中，会通过index block进行二分查找，确定KV位于哪个block。然后这个block会被从磁盘上读取到内存进行解压，最后通过二分+遍历找到对应的KV。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;论文里对于读放大的计算方法有点夸大了。对于RocksDB来说，一般情况下index block和bloom filter都是常驻内存的。除非是内存非常紧张的场景，否则并不会产生论文中如此夸张的磁盘读放大的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以读放大主要因为读取一个KV，需要读取+解压整个block。当KV大小远小于block size的时候，问题会更加严重。&lt;/p&gt;
&lt;h4 id="_3"&gt;写放大&lt;/h4&gt;
&lt;p&gt;我们再重温一个LSM-Tree的写入机制：&lt;br&gt;
1. 首先写入mutable memtable&lt;br&gt;
2. mutable memtable后续会被sealed，成为immutable memtable&lt;br&gt;
3. immutable memtable会被flush到磁盘，成为L0&lt;br&gt;
4. L0中的数据会在后台，逐层向下合并，直到合并到最底层&lt;/p&gt;
&lt;p&gt;层次数据逐层向下合并的过程中，必然会产生写放大。（具体原理这里不展开了）&lt;/p&gt;
&lt;p&gt;写放大值可以使用以下方法估算。已知&lt;code&gt;options.max_bytes_for_level_multiplier&lt;/code&gt;代表每一层大小的倍数k，并且假设L0与L1的大小相等，总共有N层。那么写放大约为&lt;code&gt;(N - 1) * k + 1&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="_4"&gt;正文&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;入活了入活了！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="wisckey_1"&gt;WiscKey的设计目标&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;降低写放大&lt;/li&gt;
&lt;li&gt;降低读放大&lt;/li&gt;
&lt;li&gt;对SSD进行优化&lt;/li&gt;
&lt;li&gt;提供LSM-Tree兼容的API&lt;/li&gt;
&lt;li&gt;针对现实场景的KV size&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="wisckeykv"&gt;WiscKey的设计思路——KV分离&lt;/h3&gt;
&lt;p&gt;在一般的场景中，在一对KV中，Key的大小远比Value的要小。如果我们在LSM-Tree中只保留Key，那么对于一次读写，我们所要处理的数据就会少很多，从而降低了读写放大。&lt;/p&gt;
&lt;p&gt;对于Value，我们会将其存储在另外一个数据结构vLog中。每一次查询，会在LSM-Tree中记录其在vLog中的&lt;code&gt;&amp;lt;offset, length&amp;gt;&lt;/code&gt; 。这样一来，读取Value的操作也只有一次磁盘访问，并且不会产生写放大。&lt;/p&gt;
&lt;p&gt;&lt;img alt="WiscKey-data-layout" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/21-08-14/2021-08-14_23-08-54.png"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里有一个疑问，如果按论文里面的设计，vLog里面的数据是不会打包的block进行压缩的，必然会损失capacity。如果打包压缩了，那么读放大并没有显著优化。又如果value size ≈ block size，那么其实在读放大上面的优化也就比较微弱了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="wisckey_2"&gt;WiscKey的设计挑战&lt;/h3&gt;
&lt;h4 id="_5"&gt;并发范围查找&lt;/h4&gt;
&lt;p&gt;因为使用了KV分离的存储方式，所以范围查找（range query）对于value就会退化成很多次随机读取。&lt;/p&gt;
&lt;p&gt;但是由于SSD的并发读取特性，WiscKey会将所需要读取的value的&lt;code&gt;&amp;lt;offset, length&amp;gt;&lt;/code&gt;放到一个队列中，多线程并发读取所需要的value。&lt;/p&gt;
&lt;p&gt;&lt;img alt="seq-rand-reads-on-ssd" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/21-08-14/2021-08-14_23-42-44.png"&gt;&lt;/p&gt;
&lt;p&gt;如图所示，对于较大的value size，顺序读与并发读的throughput基本保持一致。&lt;/p&gt;
&lt;p&gt;但是多线程并发读会消耗更多的CPU。&lt;/p&gt;
&lt;p&gt;&lt;img alt="CPU-usage" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/21-08-15/2021-08-15_16-02-21.png"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;不过对于一个存储系统来说，CPU大概是最不重要的资源了吧（见仁见智咯）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="_6"&gt;垃圾回收&lt;/h4&gt;
&lt;p&gt;对于重复写入的KV，LSM-Tree会通过层次合并来将旧值换出。而WiscKey会使用垃圾回收机制来将旧值换出。&lt;/p&gt;
&lt;p&gt;&lt;img alt="vlog-data-layout" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/21-08-15/2021-08-15_00-11-06.png"&gt;&lt;/p&gt;
&lt;p&gt;vLog可以视作一个循环数组，head指针表示数据的开头（较新的数据），tail指针表示数据的结尾（较旧的数据）。在head和tail指针之外的空间都视作free space。&lt;/p&gt;
&lt;p&gt;当空闲数据小于一定阈值之后，会触发GC。WiscKey会从tail依次读出一部分旧数据（batch read），查询LSM-Tree，如果这条数据已经被覆盖或删除，那么就丢弃此数据；否则从head指针处写入此条数据。&lt;/p&gt;
&lt;p&gt;为了保证在GC过程中的crash不产生数据的丢失，GC的流程为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将tail处的KV写入到head处，并调用&lt;code&gt;fsync()&lt;/code&gt;将其持久化&lt;/li&gt;
&lt;li&gt;同步的将KV的新位置，和head/tail指针的最新位置写入LSM-Tree&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;由于我们使用了LSM-Tree的WAL，可以保证所有在LSM-Tree里的数据都是可用的。&lt;/p&gt;
&lt;h4 id="crash-consistency"&gt;崩溃一致性（Crash Consistency）&lt;/h4&gt;
&lt;p&gt;在垃圾回收一节中，我们其实已经遇到了一致性的问题。其根本原因，在于LSM-Tree和vLog是两个不同的模块，在其间保持一致性必然是困难的。&lt;/p&gt;
&lt;p&gt;WiscKey使用了现代文件系统（ext4，btrfs和xfs）的一个有趣特性，即对于一个（将要）写入文件的数据流，文件系统会保证这个数据流的一个前缀（或者整个数据流）成功写入文件。&lt;/p&gt;
&lt;h3 id="wisckey_3"&gt;WiscKey的优化&lt;/h3&gt;
&lt;h4 id="vlogbuffer"&gt;vLog写入Buffer&lt;/h4&gt;
&lt;p&gt;&lt;img alt="impact-of-write-unit-size" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/21-08-15/2021-08-15_12-20-02.png"&gt;&lt;/p&gt;
&lt;p&gt;众所周知，磁盘的同步写入必然会带来一些overhead。对于小数据来说，这在性能上会产生严重的损耗。&lt;/p&gt;
&lt;p&gt;这里的优化类似于将vLog也添加一个memory table，所有写入vLog的数据都先写入这个memory table，然后依次flush到磁盘上。&lt;/p&gt;
&lt;p&gt;这样的优势在于将写入batch化，可以减少overhead，提升性能。劣势在于，在系统崩溃时，可能会丢失部分数据。但丢失数据时，仍能抱证上文提到的崩溃一致性。&lt;/p&gt;
&lt;h4 id="lsm-tree-wal"&gt;优化LSM-Tree WAL&lt;/h4&gt;
&lt;p&gt;LSM-Tree的WAL虽然保证了写入的数据的持久性，但是不可避免的，它也会消耗磁盘的一部分带宽。&lt;/p&gt;
&lt;p&gt;关闭WAL，意味着LSM-Tree memtable在进程重启时一定会丢失数据。不过我们可以利用vLog重建LSM-Tree（的memtable部分）。&lt;/p&gt;
&lt;p&gt;由于vLog之中已经包括了所有的KV对，所以在WiscKey重启时，我们可以从head指针处扫描vLog的数据，由于崩溃一致性的保证，当指针扫描到已经存在于LSM-Tree的数据时，可以认为LSM-Tree已经重建成功。&lt;/p&gt;
&lt;h4 id="_7"&gt;文件系统的优化&lt;/h4&gt;
&lt;p&gt;WiscKey使用&lt;code&gt;posix_fadvice()&lt;/code&gt;向OS层预声明接下来vLog的操作类型以适应不同场景的磁盘访问模式。使用&lt;code&gt;fallocate()&lt;/code&gt;，通过&amp;rdquo;hole-punching&amp;rdquo;功能进行GC，以减少数据的移动。&lt;/p&gt;
&lt;h3 id="wisckey_4"&gt;WiscKey的性能&lt;/h3&gt;
&lt;p&gt;论文的最后给出了一系列数字。由于WiscKey的读写放大很小，所以在value size比较大的场景下（&amp;gt;= 1KB），性能远优于传统LSM-Tree。同时，磁盘空间的使用也更友好。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里有一个疑问，论文里做microbenchmark的时候，对于LevelDB和RocksDB，是不是还开着压缩。。。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_8"&gt;后记&lt;/h2&gt;
&lt;p&gt;WiscKey应该是“LSM-Tree + KV分离”思路的比较早期的论文，其中仍有很多不明确的细节。但是整体思路是可行的。&lt;/p&gt;
&lt;p&gt;PingCAP的&lt;a href="https://pingcap.com/zh/blog/titan-design-and-implementation"&gt;Titan&lt;/a&gt;是一个基于WiscKey思想的RocksDB KV分离存储引擎。后续可以参考其实现再了解更多的实现思路与细节。&lt;/p&gt;</content><category term="Blog"/><category term="wisckey"/><category term="rocksdb"/><category term="leveldb"/><category term="lsm-tree"/><category term="storage"/><category term="system"/><category term="storage system"/></entry><entry><title>我到底从UW-CSE341学到了什么</title><link href="https://wizmann.top/UW-CSE341-au20.html" rel="alternate"/><published>2020-12-29T00:00:00+08:00</published><updated>2020-12-29T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2020-12-29:/UW-CSE341-au20.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;TL;DR 什么也没学到&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://sites.google.com/cs.washington.edu/cse341au20/home"&gt;课程首页&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Coursera-课程-&lt;a href="https://www.coursera.org/learn/programming-languages"&gt;A&lt;/a&gt;, &lt;a href="https://www.coursera.org/learn/programming-languages-part-b"&gt;B&lt;/a&gt;, &lt;a href="https://www.coursera.org/learn/programming-languages-part-c"&gt;C&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;介绍当中说，本课程主要内容是FP，并且顺道讨论一下程序语言的设计。&lt;/p&gt;
&lt;p&gt;UW官方上面的课程只有Slides和assignments，video不提供。Coursera有video，但是 …&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;TL;DR 什么也没学到&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://sites.google.com/cs.washington.edu/cse341au20/home"&gt;课程首页&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Coursera-课程-&lt;a href="https://www.coursera.org/learn/programming-languages"&gt;A&lt;/a&gt;, &lt;a href="https://www.coursera.org/learn/programming-languages-part-b"&gt;B&lt;/a&gt;, &lt;a href="https://www.coursera.org/learn/programming-languages-part-c"&gt;C&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;介绍当中说，本课程主要内容是FP，并且顺道讨论一下程序语言的设计。&lt;/p&gt;
&lt;p&gt;UW官方上面的课程只有Slides和assignments，video不提供。Coursera有video，但是版本比较老，是2013年的。下面的讨论都是基于au20的新版本。&lt;/p&gt;
&lt;p&gt;简单来说，前半学期（hw1-hw4)是关于OCaml，一种静态类型的FP。后半学期(hw5-hw7)是Racket，一种动态语言FP。课程里面80%+（的难度）都在于新的FP编程语言，只包含少数PL的内容。例如HW4中，需要实践一个简单粗暴的tokenizer/parser；HW6实现了一个虚假的编程语言MUPL，这个实现并不需要你解析代码，而是手写解析好的语法树，在上面实现求值、闭包、递归等。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;调试与debug也是一个非常蛋疼的问题，尤其是Racket写闭包的时候。。。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;学习建议：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;OCaml的部分比较简单，7天一个小长假就可以搞定。做为平时的娱乐调剂也可以，周期不会超过一个月。&lt;/li&gt;
&lt;li&gt;如果不想使用OCaml，可以尝试F#。因为都是一个流派的，语法接近。使用VS还可以有实时的提示。&lt;/li&gt;
&lt;li&gt;Racket的部分难度较大，主要是与平时所使用的语言差别较大。没啥好办法，只能多打log。&lt;/li&gt;
&lt;li&gt;HW7难度不高，但是提供的代码里面有一个在构造函数里面Call虚函数的迷惑操作。&lt;/li&gt;
&lt;li&gt;多写测试。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Repo地址：https://github.com/Wizmann/UW-CSE341-au20&lt;/p&gt;
&lt;p&gt;仅供参考。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;感谢华大（&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/20-12-29/2020-12-29_16-42-28.png"&gt;&lt;/p&gt;</content><category term="Blog"/><category term="公开课"/><category term="PL"/><category term="Functional Programming"/><category term="OCaml"/><category term="Racket"/></entry><entry><title>Introduction to Ceph</title><link href="https://wizmann.top/introduction-to-ceph.html" rel="alternate"/><published>2020-11-29T00:00:00+08:00</published><updated>2020-11-29T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2020-11-29:/introduction-to-ceph.html</id><summary type="html">&lt;h2 id="ceph"&gt;什么是Ceph&lt;/h2&gt;
&lt;p&gt;Ceph是一个可扩展的，高性能的分布式存储系统。提供了三种不同类型的接口以适应不同的应用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;block-based: 块存储，可以用做VM的虚拟磁盘&lt;/li&gt;
&lt;li&gt;object-based: 对象 …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;h2 id="ceph"&gt;什么是Ceph&lt;/h2&gt;
&lt;p&gt;Ceph是一个可扩展的，高性能的分布式存储系统。提供了三种不同类型的接口以适应不同的应用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;block-based: 块存储，可以用做VM的虚拟磁盘&lt;/li&gt;
&lt;li&gt;object-based: 对象存储，与Amazon S3等常用对象存储兼容&lt;/li&gt;
&lt;li&gt;file system: POSIX兼容的分布式文件系统，可以被本地系统挂载，并且能被多个客户端共享&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/20-11-28/2020-11-28_22-04-49.png"&gt;&lt;/p&gt;
&lt;h3 id="ceph_1"&gt;Ceph的特性&lt;/h3&gt;
&lt;p&gt;由于采用了CRUSH算法，Ceph有着优异的可扩展性（宣称可以无限扩展）。并且借助可扩展性，进而实现高性能、高可靠性和高可用性。&lt;/p&gt;
&lt;p&gt;Ceph是一个去中心化的存储系统，无需中心节点进行资源的管理与调度，全部的管理功能由存储节点自治完成。使得整个系统可以自我管理与自我恢复，减少运维成本与管理成本。&lt;/p&gt;
&lt;h2 id="rados-ceph"&gt;RADOS - Ceph的存储引擎&lt;/h2&gt;
&lt;p&gt;RADOS=Reliable Autonomic Distributed Object Store。RADOS是Ceph底层的存储引擎，所有的接口都建立在RADOS的功能之上。&lt;/p&gt;
&lt;h3 id="rados"&gt;RADOS中的存储结构&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/20-11-28/2020-11-28_22-24-56.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存储池（pool）：逻辑层，每一个pool里都包含一些放置组&lt;/li&gt;
&lt;li&gt;放置组（placement-group, PG)：逻辑层，一份数据会在PG当中进行灾备复制。每一个PG都对应着一系列的存储节点&lt;/li&gt;
&lt;li&gt;存储节点（OSD）：用以存储数据的物理节点。与PG之间形成多对多的关系。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一份数据在写入RADOS时，会先选中一个pool。Pool中再使用一定的hash规则，伪随机的选中某一个PG。PG会将数据写入多个OSD中。读取数据时，也是类似的规则。&lt;/p&gt;
&lt;p&gt;Pool是用户可见的管理数据的基本单位，用户可以对Pool进行一系列的配置（权限控制、使用SSD or HDD、使用数据拷贝 or 纠删码，etc.）。而PG与OSD对于用户是不可见的。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/20-11-28/2020-11-28_23-00-51.png"&gt;&lt;/p&gt;
&lt;h4 id="pg"&gt;PG的组织&lt;/h4&gt;
&lt;p&gt;在一致性哈希中，我们使用节点来划分哈希值域。这种方法的问题是，如果产生了数据不平衡，我们需要重新进行划分值域来进行再平衡。这会造成大量的数据迁移。&lt;/p&gt;
&lt;p&gt;CRUSH采用了虚拟节点（也就是PG）将哈希值域划分成了固定的等长区域。这种方法在单条数据与物理节点之间加入了一个虚拟层。之后，再使用哈希取模的算法确定数据属于哪个PG。使得数据的迁移是以虚拟节点为单位，而不是对每一条数据都重新计算。Ceph官方的建议是，每1个OSD对应着100个PG。&lt;/p&gt;
&lt;p&gt;一般情况下，在规划的初期需要确定PG的数目，如果后期需要调整PG，有可能会导致大量的数据迁移，甚至需要服务暂时停止服务。&lt;/p&gt;
&lt;h3 id="moncluster-map"&gt;监控子集群（MON）与Cluster Map&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/20-11-28/2020-11-28_22-48-10.png"&gt;&lt;/p&gt;
&lt;p&gt;RADOS集群中除了OSD存储节点之外，还有监控子集群（MON），用于存储系统的拓扑结构——Cluster Map。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;元数组管理（MDS）节点用于管理CephFS中的文件元信息，后文会有介绍。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;不同于传统的中心化管理节点，MON并不会对资源进行调配与调度，而仅仅是一个观测者，用以存储系统当前的拓扑与状态。&lt;/p&gt;
&lt;p&gt;MON与OSD、OSD与OSD之间会定时发送心跳包，检测OSD是否健康。如果某个节点失效，MON会更新内部存储的拓扑结构信息（ClusterMap），并且通过P2P协议广播出去，从而使得整个系统都有着（最终）一致的拓扑信息。&lt;/p&gt;
&lt;h3 id="_1"&gt;主从同步与节点自治&lt;/h3&gt;
&lt;p&gt;在一个PG中，会有一个主节点（Primary）和一个或多个从节点（Secondary）。主节点负责维护从节点的状态，包括数据复制（replication）、失效检测（failure detection）和失效恢复（failure recovery）。&lt;/p&gt;
&lt;h2 id="crush-ceph"&gt;CRUSH - Ceph皇冠上的明珠&lt;/h2&gt;
&lt;p&gt;CRUSH是一个可扩展的，伪随机的数据放置算法。以去中心化方法，将PG按规则映射到相应的存储设备上。并且系统的拓扑结构发生变化时，尽可能的减少数据的迁移。&lt;/p&gt;
&lt;h3 id="crush"&gt;CRUSH的优势&lt;/h3&gt;
&lt;p&gt;CRUSH对于每一个数据元素使用一个伪随机算法，决定其放置的位置。所以，只要所有参与者都拥有相同的系统拓扑结构信息，那么数据的位置就是一定的。所以我们可以去掉中心节点，采用P2P的方法来进行数据的存储与检索。&lt;/p&gt;
&lt;p&gt;并且，由于伪随机算法只与单个PG相关，如果我们操作得当，节点数量的变化并不会引起大量的数据迁移，而是会接近理论最优值。&lt;/p&gt;
&lt;h3 id="data-placement"&gt;数据放置（Data Placement）&lt;/h3&gt;
&lt;p&gt;CRUSH的数据放置算法有很多不同的实现，这里只介绍最常用的straw算法。&lt;/p&gt;
&lt;p&gt;Ceph中，每一个OSD节点都有一个权值w，代表着某个节点能支持多少数据的存储与检索。一般来说，权值与节点的容量成正比。&lt;/p&gt;
&lt;p&gt;假设一个pool里面有n个PG，在一条新的数据写入时，我们分别会计算这n个PG的length值。&lt;/p&gt;
&lt;div class="math"&gt;$$ length_{i} = f(w_{i}) * hash(x) $$&lt;/div&gt;
&lt;p&gt;&lt;span class="math"&gt;\(f(w_{i})\)&lt;/span&gt;是一个只于当前OSD节点权值有关的函数。&lt;span class="math"&gt;\(hash(x)\)&lt;/span&gt;代表当前PG的哈希值。所以，PG会放置在哪个OSD上，仅与其权值相关。&lt;/p&gt;
&lt;p&gt;假设某个OSD节点发生变化时（新加、删除、权值变化），在此受影响节点的数据会迁移到其它的OSD节点。其它OSD节点的原有数据并不会受到影响。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ceph当中的straw算法有&lt;code&gt;straw1&lt;/code&gt;和&lt;code&gt;straw2&lt;/code&gt;。&lt;code&gt;straw1&lt;/code&gt;的实现采用了有缺陷f(w)函数，会导致意外的数据迁移。&lt;code&gt;straw2&lt;/code&gt;解决了这个问题。&lt;br&gt;
详情请戳&lt;a href="https://www.spinics.net/lists/ceph-devel/msg21635.html"&gt;这里&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="_2"&gt;主从架构&lt;/h4&gt;
&lt;p&gt;每个PG所包含的OSD都由CRUSH算法计算得出，并根据配置选出前r个OSD进行主从配对。列表中的第1个OSD做为主节点（Primary），其它的节点为从节点（Secondary）。&lt;/p&gt;
&lt;p&gt;主从节点的分配与管理由PG内部进行自治，不需要额外的外部系统进行管理。&lt;/p&gt;
&lt;h2 id="cephfs"&gt;CephFS&lt;/h2&gt;
&lt;p&gt;CephFS是一个POSIX兼容的（共享）文件系统。CephFS利用文件元数据子系统（MDS）来维护目录树结构和文件和目录的元信息（owner, timestamps, inodes, etc.)等。&lt;/p&gt;
&lt;p&gt;MDS子系统会在内存里面维护一份Cache，对于需要持久化的信息，会使用WAL的方式写入RADOS里一个专用的Pool当中。&lt;/p&gt;
&lt;h3 id="dynamic-tree-partitioningdtp"&gt;动态树划分（Dynamic Tree Partitioning，DTP）&lt;/h3&gt;
&lt;p&gt;CephFS的扩展性的关键之一，在于元信息子系统的扩展性。CephFS实现了动态树划分的算法，将目录树结构根据当前系统的负载，将其划分到不同的MDS节点上去。&lt;/p&gt;
&lt;p&gt;维护目录树结构的优势在于利用了文件系统的局部性（locality），可以方便的进行预取（prefetch）。动态的树划分，可以保证元信息可以线性增长，以保持高可扩展性。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/20-11-29/2020-11-29_18-53-09.png"&gt;&lt;/p&gt;
&lt;h2 id="_3"&gt;写在最后&lt;/h2&gt;
&lt;p&gt;本文基于Ceph的三篇论文综合而成（CephFS、RADOS、CRUSH）。其中加入了一些自己的看法，使其逻辑通顺，并不保证与论文的思路完全一致。&lt;/p&gt;
&lt;p&gt;这三篇论文并没有明确的依赖关系，换句话说，需要综合阅读，才能有比较明确的理解。&lt;/p&gt;
&lt;p&gt;建议在通读论文后，去学习一下&lt;a href="https://www.youtube.com/watch?v=PmLPbrf-x9g&amp;amp;ab_channel=Ceph"&gt;这个视频&lt;/a&gt;，会对理解Ceph有很大的帮助。Youtube上面还有很多Ceph的tech talk，可以一并的了解一下。&lt;/p&gt;
&lt;p&gt;Ceph相关的书籍以实践居多，只推荐&lt;a href="https://www.oreilly.com/library/view/learning-ceph-/9781787127913/"&gt;Learning Ceph&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="_4"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://crossoverjie.top/2018/01/08/Consistent-Hash/"&gt;一致性 Hash 算法分析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zhuanlan.zhihu.com/p/60963885"&gt;从一致性 hash 到 ceph crush&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ceph.io/publications/"&gt;Ceph Publications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Blog"/><category term="Ceph"/><category term="Distributed System"/><category term="Storage System"/><category term="Storage"/><category term="System Design"/></entry><entry><title>2020 计蒜之道 线上决赛 - C. 攀登山峰</title><link href="https://wizmann.top/jisuanke-climb-the-hill.html" rel="alternate"/><published>2020-10-26T00:00:00+08:00</published><updated>2020-10-26T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2020-10-26:/jisuanke-climb-the-hill.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;本文使用了一种概率算法，不是正解，只求骗分。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;题意&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://nanti.jisuanke.com/t/49111"&gt;原题&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;给一个长度为n的数组A[1&amp;hellip;n]。&lt;/p&gt;
&lt;p&gt;现在有q个查询请求（q &amp;lt;= 1e5），每个请求给定一个长度为m的子数组A …&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;本文使用了一种概率算法，不是正解，只求骗分。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;题意&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://nanti.jisuanke.com/t/49111"&gt;原题&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;给一个长度为n的数组A[1&amp;hellip;n]。&lt;/p&gt;
&lt;p&gt;现在有q个查询请求（q &amp;lt;= 1e5），每个请求给定一个长度为m的子数组A[i&amp;hellip;j]和一个整数t。问在子数组中出现次数超过m/t的数字中（t &amp;lt;= 20），最大的数是多少。&lt;/p&gt;
&lt;h2 id="_2"&gt;题意中的坑&lt;/h2&gt;
&lt;p&gt;阈值m / t是一个实数。（题意不明先死个🐴好吗？）&lt;/p&gt;
&lt;h2 id="_3"&gt;解法&lt;/h2&gt;
&lt;p&gt;首先我们将每种数字出现的位置简历一个索引，此时对于任意一个数，我们可以用二分法在O(logn)的时间内求出其在某个区间内出现的次数。&lt;/p&gt;
&lt;p&gt;因为t最大是20，也就意味着如果我们随机取数，那么取到一个符合出现次数限制的（超过m/t次）数字的概率是1/t。如果我们进行多次尝试，并使用上面的方法对其进行验证，几乎可以保证我们一定可以取到正确的那一个。&lt;/p&gt;
&lt;p&gt;那么“多次尝试”是多少次呢？我们枚举所有的t，然后计算其在q=1e5的情况下的成功率。因为这是一个随机算法，我们先使用下面的代码分别计算一下成功率为10%和50%的期望尝试次数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;#coding=utf-8&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;fail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;fail&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/20-10-27/1603729521727_2020-10-27_00-25-20.png"&gt;&lt;/p&gt;
&lt;p&gt;由上表我们可以知道，对于不同的t，我们可以使用不同的尝试次数以达到预期的胜率。&lt;/p&gt;
&lt;p&gt;总的时间复杂度为O(q * logn * attempt)，对于极限数据可能会有超时的风险，所以我们在随机尝试时可以加入些许的优化，例如加上输入输出外挂，以及不计算重复值与小于最大值的值等。剩下的工作就是孜孜不倦的提交，直到获得AC为止。（评测机你辛苦了）&lt;/p&gt;
&lt;p&gt;以及，记得加上初始化随机数种子&lt;code&gt;srand(time(NULL));&lt;/code&gt;，否则你的随机数每次都一样。。。&lt;/p&gt;
&lt;p&gt;实际上总的胜率还是很高的，说明数据并没有达到极限，出题人手下留情做了个人（&lt;/p&gt;
&lt;p&gt;代码请见&lt;a href="https://github.com/Wizmann/ACM-ICPC/blob/master/Jisuanke/T49111-%E6%94%80%E7%99%BB%E5%B1%B1%E5%B3%B0.cc"&gt;这里&lt;/a&gt;&lt;/p&gt;</content><category term="Blog"/><category term="algorithm"/><category term="算法"/></entry><entry><title>6.824 Lab 2: Raft协议实现指南 （无剧透版）</title><link href="https://wizmann.top/raft-lab-mit-6.824.html" rel="alternate"/><published>2019-05-02T21:33:00+08:00</published><updated>2019-05-02T21:33:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2019-05-02:/raft-lab-mit-6.824.html</id><summary type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;p&gt;MIT6.824是一个用来学习分布式系统的非常好的资源。其中第二个课程作业就是关于&lt;a href="https://pdos.csail.mit.edu/6.824/labs/lab-raft.html"&gt;Raft算法&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;由于在工作中涉及到分布一致性算法的调研，接触了paxos/raft算法。然后被@neutronest安利了一发，于是开始 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;p&gt;MIT6.824是一个用来学习分布式系统的非常好的资源。其中第二个课程作业就是关于&lt;a href="https://pdos.csail.mit.edu/6.824/labs/lab-raft.html"&gt;Raft算法&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;由于在工作中涉及到分布一致性算法的调研，接触了paxos/raft算法。然后被@neutronest安利了一发，于是开始着手实现这个作业。&lt;/p&gt;
&lt;p&gt;本文是我对这个项目的实现总结。希望能在划出重点的同时，不涉及实现细节，避免破坏大家的写代码体验。&lt;/p&gt;
&lt;p&gt;本文唯一参考资料：&lt;a href="https://raft.github.io/raft.pdf"&gt;In Search of an Understandable Consensus Algorithm&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="_2"&gt;任务分解&lt;/h2&gt;
&lt;p&gt;在官方文档里，整个项目被分成了2A、2B、2C三个部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2A - 投票与选举&lt;/li&gt;
&lt;li&gt;2B - 一致性&lt;/li&gt;
&lt;li&gt;2C - 可持久化&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实际上，2C的工作量非常少，我们可以把2B和2C合成一个。然后单独提出几个比较重要的测试用例，划分成子项目。任务分解如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2A - 投票与选举&lt;/li&gt;
&lt;li&gt;2B/2C - 一致性和可持久化&lt;/li&gt;
&lt;li&gt;三个难度比较高的Case&lt;ul&gt;
&lt;li&gt;Test (2B): leader backs up quickly over incorrect follower logs  &lt;br&gt;
验证协议实现的正确性&lt;/li&gt;
&lt;li&gt;Test (2B): RPC counts aren&amp;rsquo;t too high    &lt;br&gt;
测试协议是否产生了过多的RPC请求。验证协议的性能。&lt;/li&gt;
&lt;li&gt;Test (2C): Figure 8 (unreliable)    &lt;br&gt;
测试在极端混乱的情况下，Raft协议是否能及时恢复正常工作。验证协议实现的正确性和性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以推荐大家按顺序以上顺序进行实现。并且充分利用版本控制对代码进行开发和重构。&lt;/p&gt;
&lt;h2 id="_3"&gt;需要关注的知识点&lt;/h2&gt;
&lt;p&gt;以下会介绍每一个部分需要重点关注的知识点，内容包括golang基础和论文中的知识点，无剧透，请放心食用。&lt;/p&gt;
&lt;h3 id="_4"&gt;准备工作&lt;/h3&gt;
&lt;p&gt;golang是一门傲慢的语言，其标准库的缺乏实在是让人感到TMD蛋疼。但是对于一个课程作业来说，我们也没有必要引入一系列第三方库。所以我们先要扩充&lt;code&gt;util.go&lt;/code&gt;文件，使其为我们的开发提供更多的便利。&lt;/p&gt;
&lt;h4 id="log"&gt;Log模块&lt;/h4&gt;
&lt;p&gt;项目给出的&lt;code&gt;DPrintf&lt;/code&gt;函数非常简单，只提供了一个&lt;code&gt;fmt.Printf&lt;/code&gt;的封装。并不能打印行号和文件名。这里提供一个扩展版本。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DPrintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Debug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lineno&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Caller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2006-01-02 15:04:05.00&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lineno&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s [%s:%d] &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;其输出示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mi"&gt;2019&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;09&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;35.04&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;raft.go:652&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;processing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;state&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LEADER&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;commitIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;logCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;leader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="maxmin"&gt;Max和Min函数&lt;/h4&gt;
&lt;p&gt;golang是没有对于int值的&lt;code&gt;max&lt;/code&gt;和&lt;code&gt;min&lt;/code&gt;函数的，这里省略脏话100句。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="assert"&gt;Assert函数&lt;/h4&gt;
&lt;p&gt;是的，你没有看错，golang也没有提供&lt;code&gt;assert&lt;/code&gt;函数。如果你嫌到处写&lt;code&gt;if&lt;/code&gt;和&lt;code&gt;panic&lt;/code&gt;太丑的话，可以使用这个&lt;code&gt;assert&lt;/code&gt;函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lineno&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Caller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2006-01-02 15:04:05.00&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lineno&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;reason&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s [%s:%d] &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="log-id"&gt;Log Id&lt;/h4&gt;
&lt;p&gt;为了验证日志的一致性，我们在日志中额外加入一个UUID来进行标识。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;math/rand&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="n"&gt;CreateLogId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Error: &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%X&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="si"&gt;%X&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="si"&gt;%X&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="si"&gt;%X&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="si"&gt;%X&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;以上代码可以生成一个（伪）UUID对日志进行标识。推荐使用&lt;code&gt;math/rand&lt;/code&gt;，因为这里我们使用伪随机数就够了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：这里的UUID只是看起来像一个UUID，实际上UUID有其特殊的规范与格式。但是由于golang内部没有提供可用的UUID库，所以只好随手模拟了一个。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="_5"&gt;文件组织&lt;/h4&gt;
&lt;p&gt;默认的实现是把所有的东西都写到了&lt;code&gt;raft.go&lt;/code&gt;文件里。一个非常大的文件可能会给我们的开发带来负担，所以我的做法是把所有的类声明放到&lt;code&gt;models.go&lt;/code&gt;文件里。以避免文件的膨胀。&lt;/p&gt;
&lt;h4 id="defer"&gt;锁与defer&lt;/h4&gt;
&lt;p&gt;在raft实现中，锁可以用来保证在多线程环境下数据的正确性。所以只要在涉及到raft内部状态的变化时，都需要加锁。一个常见的加锁pattern是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 加锁&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 在函数执行完成后解锁&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这里推荐使用defer，因为手动控制锁实现是过于容易出错。但是defer也是有坑的！&lt;/p&gt;
&lt;p&gt;不同于C++的大括号作用域，defer的触发时间是在函数执行完成之后，而并不是退出当前大括号时。这点非常需要注意，否则极易出现死锁。&lt;/p&gt;
&lt;p&gt;如果我们想实现C++中&lt;code&gt;do { ... } while (0);&lt;/code&gt;类似的lock guard pattern，可以使用以下实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// do something here&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这样一来，在执行完当前lambda之后，就会自动解锁。&lt;/p&gt;
&lt;h4 id="_6"&gt;刷新定时器&lt;/h4&gt;
&lt;p&gt;由于raft算法里面使用了定时器，这里提供一个刷新定时器的golang代码。这样实现是为了每次在刷新的时候，清空定时器中原有的超时时间，以避免混乱。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Raft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;renewTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="nx"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// pass&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// pass&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;rf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;以及，在定时器超时之后，不要忘了更新定时器。&lt;/p&gt;
&lt;h3 id="2a-"&gt;2A - 投票与选举&lt;/h3&gt;
&lt;h4 id="_7"&gt;所需要类的声明&lt;/h4&gt;
&lt;p&gt;论文中的&lt;code&gt;Figure2&lt;/code&gt;包含了算法中所有的类以及基本算法。在2A中，所有的类都会被用到。由于2A中只包括投票与选举，所以和日志相关的字段可以先忽略掉。&lt;/p&gt;
&lt;h4 id="checklist-for-2a"&gt;Checklist for 2A&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;实现raft状态机的三个状态：leader，follower和candidate&lt;/li&gt;
&lt;li&gt;实现RPC函数：&lt;code&gt;sendRequestVote&lt;/code&gt;（发送端）和&lt;code&gt;RequestVote&lt;/code&gt;（接收端的回调函数）&lt;/li&gt;
&lt;li&gt;实现RPC函数：&lt;code&gt;sendAppendEntries&lt;/code&gt;（发送端）和&lt;code&gt;AppendEntries&lt;/code&gt;（接收端的回调函数）    &lt;/li&gt;
&lt;li&gt;保证raft状态机的任期号（&lt;code&gt;currentTerm&lt;/code&gt;）是单调递增的&lt;/li&gt;
&lt;li&gt;一个Follower对于某一个Term只能投出一票&lt;/li&gt;
&lt;li&gt;实现Leader心跳，维护当前任期（Term）。&lt;/li&gt;
&lt;li&gt;实现Follower选举超时（election timeout）&lt;/li&gt;
&lt;li&gt;实现Candidate选举的三种场景&lt;ul&gt;
&lt;li&gt;获得多数选票，赢得选举。状态切换为Leader&lt;/li&gt;
&lt;li&gt;其它的节点已经被选为Leader。状态切换为Follower&lt;/li&gt;
&lt;li&gt;在选举中并未获得多数选票，状态切换为Follower&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;实现Candidate随机选举超时（randomized election timeout）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2b2c-"&gt;2B/2C - 日志复制与持久化&lt;/h3&gt;
&lt;h4 id="_8"&gt;基本工作流&lt;/h4&gt;
&lt;p&gt;日志复制的基本工作流如下：&lt;/p&gt;
&lt;p&gt;Leader接受用户请求，将状态变化写入本机的日志流中，并且把日志复制到Followers。如果本条日志合法，Followers会将这条日志标记为“提交”（committed），然后再将这条日志“应用”（apply）到Raft协议之外的状态机。Follower在提交日志之后，就可以向Leader回报这条日志已经被提交。在本条日志被多数节点提交之后，Leader再将这条日志标记为提交。此时，用户的请求就可以被确认（ACK）了。&lt;/p&gt;
&lt;p&gt;Raft的论文中，Leader需要维护&lt;code&gt;commitIndex&lt;/code&gt;和&lt;code&gt;lastApplied&lt;/code&gt;这两个状态。为了简单起见，我们可以忽略“应用”（apply）这个过程。这两个状态我们只需要维护&lt;code&gt;commitIndex&lt;/code&gt;即可。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Raft协议不是2PC，千万不要搞混了哦～&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="_9"&gt;回滚与滚回来&lt;/h4&gt;
&lt;p&gt;&lt;img alt="rollback" src="https://raw.githubusercontent.com/Wizmann/assets/3f1056d6f142755204092fb89a474dc964608bab/wizmann-pic/2019-05-02_14-40-52.png"&gt;&lt;/p&gt;
&lt;p&gt;从上面的工作流我们可以看到，对于已经committed的日志，仍然有可能是不可靠的。&lt;/p&gt;
&lt;p&gt;例如，在Term1时，节点1作业Leader提交到了日志(1, 2)，而Follower节点Node2和Node3分别提交到了日志(1, 2)和(1, 3)。此时Leader短暂断线，出发选举超时，就会进行下一轮的选举。如果节点Node2被选为Leader，那么节点Node3就会被Leader多出一条日志，这是不被允许的。如果节点Node3被选为Leader，那么Node2就比Leader在Term1少一条日志，需要补齐。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里有人可能会怀疑，节点2比节点3少一条日志，那么按照论文里的说法，因为节点3的日志比较节点2要多，所以只有节点3才能赢得下一轮选举。这其实是不对的，如果节点3断线，节点1和节点2仍然可以组成一个quorum，选举出Leader。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以我们需要考虑将已committed的日志回滚（向左滚），以及缺失的日志补齐（向右滚）。这里其实有一些优化的点，我们后文再说。&lt;/p&gt;
&lt;p&gt;再次注意，保证日志的一致性是Raft协议正确性的必须保证，在这一点上一定要注意。&lt;/p&gt;
&lt;h4 id="_10"&gt;乱序请求&lt;/h4&gt;
&lt;p&gt;本项目中，模拟的RPC协议并不能保证可靠性（会丢包）、有序性（会乱序），也没有SLA（没有超时时间的上限），更不用想拥塞控制。我们可以理解为它在底层使用了UDP协议，而不是TCP。所以我们不能做出任何假设。&lt;/p&gt;
&lt;p&gt;例如，两个请求先后来到Leader端，A请求编号(1,100)，B请求编号(1,110)。然后我们依次将Log复制到Follower端（A先B后），但是在Follower端有可能收到的顺序是B先A后。甚至只收到B，没收到A。这种情况日常工程中的TCP协议下几乎不能发生，但是在测试环境中要十分小心。&lt;/p&gt;
&lt;h4 id="checklist-for-2b2c"&gt;Checklist for 2B/2C&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;日志的状态会影响Leader选举  &lt;br&gt;
如果两份日志流的最后一条日志的Term不一样，那么我们认为Term号大的日志“比较新”。如果Term号一样，那么Index大的日志“比较新”&lt;/li&gt;
&lt;li&gt;如果Leader和Follower的日志不一致，那么Follower需要拷贝Leader的日志（向左滚或向右滚的正确性）    &lt;br&gt;
这里推荐使用Assert加断言进行保证，如果出错可以获得实时的现场&lt;/li&gt;
&lt;li&gt;对于小于当前Term的日志，Leader不需要等多数Follower确认就可以直接commit&lt;/li&gt;
&lt;li&gt;一个重要特性：如果两个日志的(Term, Index)一致，那么其内容也是一致的。并且在此日志之前的所有日志都必须是一致的&lt;/li&gt;
&lt;li&gt;另一个重要特性：RPC请求是幂等的，也就是多次重复发送一个请求并不会破坏Raft协议的状态&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3case"&gt;最后的3个Case&lt;/h3&gt;
&lt;p&gt;最后的三个Case有一个共同点，就是对协议的效率和正确性有比较高的要求。即使前面的代码里你的实现是正确的，也有可能因为各种其它的原因造成Case挂掉。&lt;/p&gt;
&lt;p&gt;建议首先解决正确性问题，再提升效率。&lt;/p&gt;
&lt;h4 id="_11"&gt;向左滚的优化（重要！）&lt;/h4&gt;
&lt;p&gt;在论文的5.3节，介绍了一种回滚的优化。如果Leader和Follower在某个Index上的日志不一致，Leader的版本记为(Term1, Index)，Follower的版本记为(Term2, Index)。那么Follower需要回滚所有日志，直到Term小于&lt;code&gt;Min(Term1, Term2)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这样的好处是可以加快回滚的效率。虽然论文上表示这种优化并非必要，但是在模拟出来的极端网络环境下，这样的优化可以帮助我们通过一些比较变态的Case。&lt;/p&gt;
&lt;h4 id="_12"&gt;其它的非官方优化&lt;/h4&gt;
&lt;p&gt;这里还有一些论文里没的提到的优化方案，不保证一定是正确的。&lt;/p&gt;
&lt;p&gt;为了不剧透，放到单独的链接里了：&lt;a href="https://github.com/Wizmann/assets/blob/master/wizmann-pic/19-05-02/raft-hints.md"&gt;剧透警告！&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;还有一个Bonus挑战，谁比较闲可以试一下。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_13"&gt;测试结果&lt;/h2&gt;
&lt;p&gt;&lt;img alt="tests" src="https://raw.githubusercontent.com/Wizmann/assets/e35dd59aa533ddd19065f070dcb85a3734cc035d/wizmann-pic/19-05-02/2019-05-02_21-37-14.png"&gt;&lt;/p&gt;
&lt;p&gt;在Travis CI上面运行的测试。自我感觉实现的比较一般，所以你们的程序应该跑的比我快一点才正常。&lt;/p&gt;
&lt;h2 id="_14"&gt;总结&lt;/h2&gt;
&lt;p&gt;想要完整正确的实现这个项目，首先一定要把论文读懂。并且划出实现上应该注意的重点。&lt;/p&gt;
&lt;p&gt;当遇到正确性问题时，一定要回归论文，大部分的问题都可以获得解答。当遇到性能问题时，可以参考作业上面的Hints，里面也有非常有用的信息。&lt;/p&gt;
&lt;p&gt;MIT的这个课程还有基于raft实现kv storage的项目，后续如果有时间应该还会做吧。&lt;/p&gt;</content><category term="Blog"/><category term="raft"/><category term="分布式系统"/></entry><entry><title>白话一致性协议 - Paxos、Raft和PacificA[2]</title><link href="https://wizmann.top/paxos-raft-pecifaca[2].html" rel="alternate"/><published>2019-02-18T00:00:00+08:00</published><updated>2019-02-18T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2019-02-18:/paxos-raft-pecifaca[2].html</id><summary type="html">&lt;h2 id="pacifica"&gt;PacificA是一个框架&lt;/h2&gt;
&lt;p&gt;虽然在题目中我们把Paxos、Raft和PacificA并列，但是Paxos和Raft在论文中称自己为一种“算法”（algorithm）；而PacificA对自己的定位是一种通用的，强一致的数据同步&lt;strong&gt;框架&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在论文中，作者提到现有的可证明的数据同步协 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="pacifica"&gt;PacificA是一个框架&lt;/h2&gt;
&lt;p&gt;虽然在题目中我们把Paxos、Raft和PacificA并列，但是Paxos和Raft在论文中称自己为一种“算法”（algorithm）；而PacificA对自己的定位是一种通用的，强一致的数据同步&lt;strong&gt;框架&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在论文中，作者提到现有的可证明的数据同步协议往往过分简化了性能问题，导致看起来很美的理论设计无法转变有实际的系统（注：本篇论文应该早于Raft的论文）。所以作者的目标是将算法理论与实际相结合，进行相应的系统设计。&lt;/p&gt;
&lt;h2 id="pacifica_1"&gt;PacificA的实现&lt;/h2&gt;
&lt;p&gt;与Paxos和Raft不同的是，PacificA采用的算法非常简单。所以在这里我不进行太多铺垫，直接进入正题。&lt;/p&gt;
&lt;h3 id="_1"&gt;主从同步&lt;/h3&gt;
&lt;p&gt;PacificA使用了主从同步模型，用户的读写请求都会发往主节点，以保证强一致性。&lt;/p&gt;
&lt;p&gt;主节点会对发来的写请求进行编号，使得所有写请求编号唯一且单调递增。这个编号也会同步到从节点。&lt;/p&gt;
&lt;p&gt;无论是主节点还是从节点，所有的写请求都写入一个只追加的日志。主从节点都需要维护&lt;code&gt;committed&lt;/code&gt;指针，代表在这个指针之前的数据都已经被所有节点所认可，处理“已确认”状态。从节点需要额外维护一个&lt;code&gt;prepared&lt;/code&gt;指针，代表在这个指针之前所有的数据都处于“待确认”状态，而在&lt;code&gt;prepared&lt;/code&gt;指针之后的数据，都是“待同步”状态。&lt;/p&gt;
&lt;p&gt;主从之间的数据同步使用两步提交模型（2-PC）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;主节点首先把写请求写入日志&lt;/li&gt;
&lt;li&gt;主节点发送&lt;code&gt;prepare&lt;/code&gt;请求到从节点，这个请求中包含写入的数据&lt;/li&gt;
&lt;li&gt;从节点收到&lt;code&gt;prepare&lt;/code&gt;请求后，将数据加入日志，并移动&lt;code&gt;prepared&lt;/code&gt;指针，将其标记为“待确认”&lt;/li&gt;
&lt;li&gt;当所有从节点返回ACK后，主节点移动&lt;code&gt;committed&lt;/code&gt;指针，表明这个数据处于“待确认”状态&lt;/li&gt;
&lt;li&gt;主节点向所有从节点发送ACK消息，确认这条请求已经被最终确认&lt;/li&gt;
&lt;li&gt;从节点收到ACK消息后，移动&lt;code&gt;committed&lt;/code&gt;指针，确认请求&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以对于一个节点，总会有:      &lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/19-02-18/1902180052.PNG"&gt;&lt;/p&gt;
&lt;h3 id="_2"&gt;全局配置管理器&lt;/h3&gt;
&lt;p&gt;PacificA使用了一个“中心化的”全局配置管理器。这个管理器用于探测系统内的失效节点，管理、更新节点的配置。而Raft是“去中心化的”，通过节点之间的选举通信来管理配置。&lt;/p&gt;
&lt;p&gt;PacificA的全局配置管理器保证在任何情况下，当且仅当全局配置管理器认可节点&lt;code&gt;s&lt;/code&gt;为主节点时，节点&lt;code&gt;s&lt;/code&gt;才会认为自己是主节点。&lt;/p&gt;
&lt;p&gt;全局配置管理器在“钦点”了主节点后，主节点会与从节点发送心跳包（beacons），维护一个租期（lease）。在租期内，主节点和从节点都会互相承认相互之间的主从关系。当租期失效时，主节点会向全局配置管理器报告从节点失效。当从节点收不到心跳包时，从节点会报告主节点失效。&lt;/p&gt;
&lt;p&gt;一个中心化的配置管理器会让整个系统的维护变的非常简单，但是也会带来单点失效的隐患。这里，全局配置管理器使用了Paxos算法来保证管理器节点之间的一致性，可以容忍少于半数节点的失效。&lt;/p&gt;
&lt;h3 id="_3"&gt;配置变化与灾难恢复&lt;/h3&gt;
&lt;p&gt;由于我们使用的全局的配置管理器，所以添加删除从节点会是非常简单的事情。这里我们主要讨论主节点的失效与灾难恢复。&lt;/p&gt;
&lt;p&gt;当主节点失效之后，从节点会揭竿而起，向配置管理器申请成为主节点。这里要注意，根据上面的讨论，从节点中的&lt;code&gt;committed&lt;/code&gt;指针有可能会落后于主节点，以及不同从节点中的&lt;code&gt;committed&lt;/code&gt;指针可能会不一致。但是被主节点ACK的数据，一定位于从节点的日志中，并处于“待确认”状态。&lt;/p&gt;
&lt;p&gt;所以在新的主节点被指派之后，会重新的向其它的从节点发出&lt;code&gt;prepare&lt;/code&gt;指令，要求确认其日志中待确认的数据。从而保持数据的一致性&lt;/p&gt;
&lt;h2 id="pacifica_2"&gt;PacificA的正确性的简单讨论&lt;/h2&gt;
&lt;p&gt;一个强一致性的系统一定会包含以下三种特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;线性一致性（Linearizability）     &lt;br&gt;
由于我们的写请求位于一个只可追加写的日志当中，并且不同的副本的日志保持强一致。所以不同的副本的状态也应该是一致的。&lt;/li&gt;
&lt;li&gt;可持久性（Durability）    &lt;br&gt;
如果用户收到了ACK，那么这个请求一定已经持久化到所有的副本之上了。即使发生了主节点失效，新的主节点仍会维持已ACK的数据。&lt;/li&gt;
&lt;li&gt;前进性（Progress，不知道怎么翻译）         &lt;br&gt;
全局配置管理器在处理完配置更新请求后，一定可以剔除失效的节点。使得整个系统可以处理用户的读写请求。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="_4"&gt;一些其它的讨论&lt;/h2&gt;
&lt;h3 id="_5"&gt;全局配置管理器的可用性和性能&lt;/h3&gt;
&lt;p&gt;由于全局配置管理器在逻辑上是整个系统的单点，所以其可用性和性能是非常值得关注的。&lt;/p&gt;
&lt;p&gt;全局配置管理器了Paxos算法，所以在少于一半的节点失效时，它仍能对外提供服务。&lt;/p&gt;
&lt;p&gt;同时，全局配置管理器的处理不在整个系统的关键路径上，所以在一般情况下不会影响系统的整体性能。同时，在系统不正常运行的情况下，即使配置管理器暂时失效，也不会影响系统的运行。&lt;/p&gt;
&lt;h3 id="_6"&gt;可持久性&lt;/h3&gt;
&lt;p&gt;PacificA的日志同步采用了两步提交，所以用户收到ACK时，说明用户的写请求已经被持久化在所有的节点之上了。&lt;/p&gt;
&lt;p&gt;这意味着，在一个有n台机器的集群里，即使有n - 1台节点失效，我们仍能提供可用的服务。（但是一般只提供只读服务）&lt;/p&gt;
&lt;h3 id="vs-paxos"&gt;主从复制 vs. Paxos&lt;/h3&gt;
&lt;p&gt;在Paxos范式的实现中，如果一个请求被多数节点认可，我们就可以向用户端返回ACK，声明这个请求已经被整个系统所认可。但是在主从复制的范式下，必须要所有的节点都认可这个请求，我们才可以说这个请求被整个系统所认可。&lt;/p&gt;
&lt;p&gt;因为这两种范式之间的不同策略导致了微妙的差别。&lt;/p&gt;
&lt;p&gt;我们很容易看出，Paxos范式中对于单个节点的性能波动并不敏感，但是主从复制的一个慢节点可能会拖慢整个系统。但是，如果系统中多数节点全部失效，那么Paxos范式就无法提供服务了（读/写都不可以的）；对于主从复制范式，只要有一个节点是存活的状态，我们就可以对外提供服务，并且保持强一致性。&lt;/p&gt;
&lt;p&gt;更重要的是，使用单点来管理整个系统的配置，并让开发与运维的成本降低。换做Paxos范式，一个节点若要成为主节点，则需要同多数节点进行协商。&lt;/p&gt;
&lt;p&gt;这两种范式的选择是非常有争议的，PecificA选择主从复制的主要原因就是因为它简单。（太实在了）&lt;/p&gt;
&lt;h3 id="_7"&gt;在强一致性上的妥协&lt;/h3&gt;
&lt;p&gt;如果需要放松对强一致性的要求，我们可以让从节点支持读请求。这样带来的问题是我们有可能读到陈旧的数据，由强一致性退化到最终一致性。&lt;/p&gt;
&lt;p&gt;最终一致性从本质上说需要满足以下两个要求：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;所有的节点需要以同样的顺序执行同样的状态更新操作&lt;/li&gt;
&lt;li&gt;在处理请求时，必须返回最新的状态&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果放松第一个要求，就会面临“状态分叉”的问题（像git branch一样），所以我们需要处理这种不一致的问题（像git rebase一样）。这就会带来额外的复杂性和不确定性。&lt;/p&gt;
&lt;p&gt;放松第二个要求是更加理性的，因为在PecificA中，所有的状态变化全都被写入一个“只可追加写”的日志中。并且当前的状态变化通过日志指针的移动来表示。又因为从节点的日志一定是主节点的前辍，并且日志指针稍微落后与主节点。所以如果我们可以放松强一致性的要求，就可以让从节点来处理读请求。&lt;/p&gt;
&lt;h2 id="_8"&gt;写在后面&lt;/h2&gt;
&lt;p&gt;还有好多东西没读透呢。要不再饶一篇？&lt;/p&gt;</content><category term="Blog"/><category term="pecificA"/><category term="数据库"/><category term="分布式系统"/><category term="主从复制"/></entry><entry><title>C++类型擦除与`std::function`性能探索</title><link href="https://wizmann.top/cpp-type-erasure-and-std-function.html" rel="alternate"/><published>2019-02-01T00:00:00+08:00</published><updated>2019-02-01T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2019-02-01:/cpp-type-erasure-and-std-function.html</id><summary type="html">&lt;h2 id="_1"&gt;什么是类型擦除&lt;/h2&gt;
&lt;p&gt;对于Python这种动态类型语言来说，是不存在“类型擦除”这个概念的。Python对象的行为并不由接口定义，而是由“当前方法和属性的集合”决定。&lt;/p&gt;
&lt;p&gt;所以，以下的代码是完全合 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;什么是类型擦除&lt;/h2&gt;
&lt;p&gt;对于Python这种动态类型语言来说，是不存在“类型擦除”这个概念的。Python对象的行为并不由接口定义，而是由“当前方法和属性的集合”决定。&lt;/p&gt;
&lt;p&gt;所以，以下的代码是完全合法的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;do_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;do_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;do_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bar&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;但是对于C++这种静态类型语言来讲，我们就不能使用这种语法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;do_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;???&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// &amp;lt;--&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;do_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;do_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bar&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;熟悉C++的同学们都知道，因为&lt;code&gt;Foo&lt;/code&gt;和&lt;code&gt;Bar&lt;/code&gt;的类型不同，我们不能直接将不同类型的实例传入&lt;code&gt;do_print(obj)&lt;/code&gt;函数。所以我们需要一种方法擦除类型信息，提供一种类型的抽象。使得实现不依赖于具体类型，而是依赖于类型抽象。&lt;/p&gt;
&lt;h2 id="c"&gt;C++中类型擦除的实现&lt;/h2&gt;
&lt;h3 id="-void"&gt;简单粗暴 - &lt;code&gt;void*&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;写过C语言同学们一定非常熟悉&lt;code&gt;qsort&lt;/code&gt;函数的写法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// http://www.cplusplus.com/reference/cstdlib/qsort/&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;qsort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这里的&lt;code&gt;compare(const void*, const void*)&lt;/code&gt;函数就是C语言风格的类型擦除，可以支持不同类型的指针类型传入。但是缺陷是在函数中，我们仍然需要将已擦除的类型恢复，以读取其中的数据。&lt;/p&gt;
&lt;p&gt;这种类型擦除方法，并不会带开额外的开销。但是这样的强制类型隐含着类型不匹配的风险，需要程序员格外注意。&lt;/p&gt;
&lt;h3 id="-virtual-function"&gt;面向对象的经典方法 - 虚函数（virtual function）&lt;/h3&gt;
&lt;p&gt;C++做为C语言的进化，引入了面向对象的理念。而多态，做为面向对象编程的一个重要特性，为我们的代码带来了更多的弹性。&lt;/p&gt;
&lt;p&gt;对于上面的例子，我们可以使用以下的代码来实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;IPrintable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IPrintable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IPrintable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;do_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IPrintable&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;do_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;do_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Bar&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在这里，我们使用了一个&lt;code&gt;IPrintable&lt;/code&gt;基类，擦除了子类&lt;code&gt;Foo&lt;/code&gt;和&lt;code&gt;Bar&lt;/code&gt;的具体类型信息。也就是说，只要子类实现了基类的接口，就可以做为参数传入&lt;code&gt;do_print(obj)&lt;/code&gt;中。这样的好处是我们只需要为继承同样接口的类型完成一套实现，提供了更好的封装与抽象。&lt;/p&gt;
&lt;p&gt;但是，这种实现的问题在于虚函数的调用是有额外的开销的。需要进行一次运行时虚表的查找，才可以确定对象需要调用哪一个函数。&lt;/p&gt;
&lt;h3 id="template"&gt;使用模板（template）&lt;/h3&gt;
&lt;p&gt;C++提供了模板，支持将类型以模板参数形式传入参数。使得我们可以以一种独立于特定类型的方式编写代码。&lt;/p&gt;
&lt;p&gt;我们可以改写上文中的&lt;code&gt;do_print(obj)&lt;/code&gt;函数，使其可以支持不同的类型：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;do_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这里，传入参数的类型&lt;code&gt;T&lt;/code&gt;无需继承&lt;code&gt;IPrintable&lt;/code&gt;接口，只要其实现了&lt;code&gt;print()&lt;/code&gt;成员函数即可做为对象传入。&lt;/p&gt;
&lt;p&gt;C++模板的类型擦除作用于编译期，可以尽早的发现风险，同时（一般来说）不影响运行时的性能。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：Java/C#的泛型(generic)语法与C++的模板非常类似，但是Java/C#的泛型是作用于运行时的。这里注意区分二者的区别。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;但是模板也有其局限性。模板有隐含的接口语义，但是由于模板所使用的对象并没有共同的基类（接口），所以它不能使用一个统一的容器来储存对象。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;???&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;objs&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="c-stdfunction"&gt;C++类型擦除实战 —— &lt;code&gt;std::function&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;在C语言中，我们要表示一个函数对象只能使用函数本身以及函数指针。但是在C++中，我们有了更多的选择：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;函数&lt;/li&gt;
&lt;li&gt;inline lambda&lt;/li&gt;
&lt;li&gt;函数指针（C-style）&lt;/li&gt;
&lt;li&gt;仿函数（factor class）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;std::bind&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;std::function&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上面的这些对象，我们可以统称为可调用（callable）对象。也就是说，我们可以使用类似&lt;code&gt;f(obj)&lt;/code&gt;的语法，以函数形式调用这些对象。&lt;/p&gt;
&lt;p&gt;思考以下的场景：我们想要实现一个回调函数。这个函数是用户定义的，可以是以上可调用对象的任意一种。那么我们应该用什么类型来表示这个回调函数对象呢？&lt;/p&gt;
&lt;p&gt;是的，答案就是&lt;code&gt;std::function&lt;/code&gt;。C++中的&lt;code&gt;std::function&lt;/code&gt;为我们提供了对可调用对象的抽象。我们可以使用&lt;code&gt;std::function&lt;/code&gt;封装可调用对象，从而擦除其类型信息，使用统一的方法对其进行调用。&lt;/p&gt;
&lt;p&gt;请参考以下代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// http://www.cplusplus.com/reference/functional/function/function/&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;     // std::cout&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;functional&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;   // std::function, std::negate&lt;/span&gt;

&lt;span class="c1"&gt;// a function:&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;half&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;

&lt;span class="c1"&gt;// a function object class:&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;third_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// a class with data members:&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MyValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;fifth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;half&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// function&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;half&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="c1"&gt;// function pointer&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;third_t&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;// function object&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;};&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// lambda expression&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;negate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;// standard function object&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fn1(60): &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fn2(60): &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fn3(60): &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fn4(60): &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fn5(60): &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// stuff with members:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyValue&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;MyValue&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// pointer to data member&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyValue&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fifth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;MyValue&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;fifth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// pointer to member function&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;MyValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sixty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;value(sixty): &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sixty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fifth(sixty): &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fifth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sixty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="stdfunction"&gt;&lt;code&gt;std::function&lt;/code&gt;的缺陷&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;std::function&lt;/code&gt;的类型擦除功能异常强大，几乎可以封装所有的可调用类型。但是，语法上面的便利却会带来了性能上的损失。&lt;/p&gt;
&lt;p&gt;从&lt;a href="https://gist.github.com/Wizmann/30073037f31d796efd6f42798dd85aee"&gt;benchmark&lt;/a&gt;结果上我们可以看出，在&lt;code&gt;O2&lt;/code&gt;的优化参数下，函数调用（包括函数、函数模板和仿函数）、函数指针和lambda的性能相仿。而虚函数大概需要花费5倍左右的时间，而&lt;code&gt;std::function&lt;/code&gt;则需要花费6倍以上的时间。对于一个会被经常调用到的函数，带来的额外的性能开销是不可以忽略的。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;method&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Linux (Azure VM, E5-2673 v3, -O0)&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Linux (Azure VM, E5-2673 v3, -O2)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td style="text-align: right;"&gt;12.4s&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1.2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Function Ptr&lt;/td&gt;
&lt;td style="text-align: right;"&gt;13.5s&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1.2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inline Lambda&lt;/td&gt;
&lt;td style="text-align: right;"&gt;12.7s&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1.2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Virtual Function&lt;/td&gt;
&lt;td style="text-align: right;"&gt;14.1s&lt;/td&gt;
&lt;td style="text-align: right;"&gt;6.3s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;std::function&lt;/td&gt;
&lt;td style="text-align: right;"&gt;77.3s&lt;/td&gt;
&lt;td style="text-align: right;"&gt;7.2s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;究其原因，是由于&lt;code&gt;std::function&lt;/code&gt;的模板参数中只提供了参数类型和返回值类型，所以为了进行类型擦除，其中内置了一个虚函数。所以一次&lt;code&gt;std::function&lt;/code&gt;调用会引发隐式的多次函数调用，其中还包含着一次虚函数的调用。所以性能下降也就不难解释了。&lt;/p&gt;
&lt;h3 id="_2"&gt;解决方案&lt;/h3&gt;
&lt;p&gt;可以确定的是，除非必要，不要使用&lt;code&gt;std::function&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;例如，在&lt;code&gt;std::sort&lt;/code&gt;中，我们使用模板传入可调用类型，这样就可以避免&lt;code&gt;std::function&lt;/code&gt;的额外开销：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;RandomIt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Compare&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RandomIt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RandomIt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Compare&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;又例如我们可以避免使用不同的可调用类型来规避类型擦除，如统一使用函数指针。在C++14之后，inline lambda也可以表示为函数指针，所以我们也可以通过闭包来封装其它的可调用对象了。&lt;/p&gt;
&lt;p&gt;当然，也可以自己造个&lt;a href="https://codereview.stackexchange.com/questions/14730/impossibly-fast-delegate-in-c11"&gt;轮子&lt;/a&gt;，这就又是另一个故事了。&lt;/p&gt;
&lt;h2 id="_3"&gt;写在最后&lt;/h2&gt;
&lt;p&gt;新的C++规范给我们带来了很多的语法糖。对于传统C++程序员来说，好处在于我们可以写出更舒服的，更符合直觉的代码，但缺点是我们需要了解更多语言背后的东西。所以对于自己不熟悉的新式语法，无论看起来多么诱人，也需要多加谨慎。&lt;/p&gt;
&lt;h2 id="_4"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/Wizmann/30073037f31d796efd6f42798dd85aee"&gt;Benchmark for &amp;ldquo;function pointer&amp;rdquo;, &amp;ldquo;virtual function&amp;rdquo; and &amp;ldquo;std::function&amp;rdquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.modernescpp.com/index.php/c-core-guidelines-type-erasure"&gt;C++ Core Guidelines: Type Erasure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://davekilian.com/cpp-type-erasure.html"&gt;C++ &amp;lsquo;Type Erasure&amp;rsquo; Explained&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="C++"/><category term="modern C++"/><category term="std::function"/></entry><entry><title>在WSL中获取Windows剪贴板中的图片</title><link href="https://wizmann.top/get-image-from-clipboard-in-wsl.md.html" rel="alternate"/><published>2019-01-04T00:00:00+08:00</published><updated>2019-01-04T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2019-01-04:/get-image-from-clipboard-in-wsl.md.html</id><summary type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;p&gt;Win10里面的WSL（Windows Subsystem For Linux)算是一个开发神器了，虽然功能不是100%完善，但是对于轻度开发已经足够了。现在我的日常开发，就是一个 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;p&gt;Win10里面的WSL（Windows Subsystem For Linux)算是一个开发神器了，虽然功能不是100%完善，但是对于轻度开发已经足够了。现在我的日常开发，就是一个全屏CMD跑内部工具，一个全屏WSL跑tmux+vim。&lt;/p&gt;
&lt;p&gt;（跑题了）&lt;/p&gt;
&lt;h2 id="_2"&gt;问题&lt;/h2&gt;
&lt;p&gt;之前的文章里，我有写到使用github做为图床，并且使用python脚本进行图片上传。但是仍有一点问题，就是之前的脚本只能上传文件，不能直接上传剪贴板里的图片。&lt;/p&gt;
&lt;h2 id="_3"&gt;解决&lt;/h2&gt;
&lt;p&gt;发现Windows里面有内置的访问剪贴板工具，但是只在powershell下可用。不过我们可以在WSL里直接调用exe文件（这点非常神奇），然后读出图片文件放入临时文件夹。然后我们再读出这个文件进行上传。&lt;/p&gt;
&lt;p&gt;总的流程仍然是上传已有的图片文件，但是我们把它放在临时文件夹并隐藏了起来。看起来就是实现了WSL和Windows剪贴板的互操作。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;TMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/mnt/c/Users/me/AppData/Local/Temp/
&lt;span class="nv"&gt;TMPWIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C:&lt;span class="se"&gt;\\&lt;/span&gt;Users&lt;span class="se"&gt;\\&lt;/span&gt;me&lt;span class="se"&gt;\\&lt;/span&gt;AppData&lt;span class="se"&gt;\\&lt;/span&gt;Local&lt;span class="se"&gt;\\&lt;/span&gt;Temp&lt;span class="se"&gt;\\&lt;/span&gt;

&lt;span class="nv"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;date&lt;span class="w"&gt; &lt;/span&gt;+&lt;span class="s2"&gt;&amp;quot;%Y-%m-%d_%H-%M-%S&amp;quot;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;(Get-Clipboard -Format Image).Save(\&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$TMPWIN&lt;/span&gt;&lt;span class="s2"&gt;\\&lt;/span&gt;&lt;span class="nv"&gt;$ts&lt;/span&gt;&lt;span class="s2"&gt;.png\&amp;quot;)&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/null

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-ne&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;no image in clipboard&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;upload.py&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$TMP&lt;/span&gt;/&lt;span class="nv"&gt;$ts&lt;/span&gt;.png
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="闲聊"/><category term="WSL"/><category term="powershell"/></entry><entry><title>白话一致性协议 - Paxos、Raft和PacificA[1]</title><link href="https://wizmann.top/paxos-raft-pecifaca[1].html" rel="alternate"/><published>2018-12-05T00:00:00+08:00</published><updated>2018-12-05T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2018-12-05:/paxos-raft-pecifaca[1].html</id><summary type="html">&lt;h2 id="-multi-paxos"&gt;书接上文 - Multi Paxos&lt;/h2&gt;
&lt;p&gt;在上一篇文章中，我们提到了Basic Paxos和Multi Paxos的异同。在&lt;a href="https://lamport.azurewebsites.net/pubs/paxos-simple.pdf"&gt;Paxos Made Simple&lt;/a&gt;论文中，作者提到了Multi Paxos的一种实现。这个实现允许我们对一个连续的数 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="-multi-paxos"&gt;书接上文 - Multi Paxos&lt;/h2&gt;
&lt;p&gt;在上一篇文章中，我们提到了Basic Paxos和Multi Paxos的异同。在&lt;a href="https://lamport.azurewebsites.net/pubs/paxos-simple.pdf"&gt;Paxos Made Simple&lt;/a&gt;论文中，作者提到了Multi Paxos的一种实现。这个实现允许我们对一个连续的数据流（也可以称为复制日志，replicated log）达成共识，从而实现节点状态的一致性复制。&lt;/p&gt;
&lt;h3 id="_1"&gt;确定性状态机&lt;/h3&gt;
&lt;p&gt;我们可以将系统中的每一个节点抽象为一个有着确定性状态机，即给定多个状态一致的状态机，在执行同一个命令之后，其状态仍保持一致。（可以想一想编译原理里面的DFA）&lt;/p&gt;
&lt;h3 id="leader-proposer"&gt;Leader - 系统中唯一的proposer&lt;/h3&gt;
&lt;p&gt;如果系统中存在有多个proposer，那么就很可能会出现多个提案相互干扰的情况。虽然根据证明，最终这些提案都会收敛到一致，但是性能会非常低下。所以我们可以在系统中通过选举，选出一个leader做为主proposer（distinguishied proposer），所有的提案都由leader提出。&lt;/p&gt;
&lt;p&gt;这样一来，在绝大多数情况下都不会出现提案相互干扰的情况。只有在leader切换的瞬间，可能会出现相同编号的不同提案，但是我们的算法可以很好的处理这种情况。&lt;/p&gt;
&lt;h3 id="tcp"&gt;分布式系统中的“TCP”&lt;/h3&gt;
&lt;p&gt;类似于TCP协议中序列号，Multi Paxos中的每一个命令都有一个递增的编号。即我们前一个执行的命令是100号，那么下一个执行的命令一定是101号。每一个命令都是一个Paxos实例，Leader向所有节点发布这个提案，在提案达成一致之后（多数节点返回ACK），就可以认为这个命令已经达成了一致。&lt;/p&gt;
&lt;p&gt;和TCP一样，如果我们顺序的发布并表决提案，效率会非常低下（TCP停等模型）。所以，Multi Paxos采用类似滑动窗口的方案，每次对N个提案进行表决，以增加表决的带宽。&lt;/p&gt;
&lt;p&gt;和TCP不同的是，如果某些序号的TCP包在传输中丢失，最坏的情况是我们会RST这条链接，其它的工作都交给应用层逻辑来解决。&lt;/p&gt;
&lt;p&gt;但是对于Multi Paxos来说，如果某些提案没有被表决，那么就会在日志中留下空洞（gap）。这会直接影响系统的一致性。如果恰巧这个时候发生了Leader失效，那么新选举出来的Leader节点就要处理日志中的空洞。&lt;/p&gt;
&lt;p&gt;解决空洞的原理也很简单，就是Leader向所有成员询问，对于这个提案，是否已经有达成共识的值。如果有的话，就使用这个值。如果没有，就用一个no-op（无操作）命令来填补这个空位。但是，对于实际工程中来说，我们还需要解决未达成共识时值的冲突等情况。&lt;/p&gt;
&lt;h2 id="raft"&gt;为什么我们还需要Raft？&lt;/h2&gt;
&lt;p&gt;Multi-Paxos在现实的工程当中更多的是一种符号。因为理论与实践上的隔阂是如此之大，如果想在工程意义上实现一个可用的Multi-Paxos算法，必然会在原算法的基础上进行一系列的魔改，这些魔改虽然均声称自己实现了Multi-Paxos算法，但是这些算法大多不能被证明是正确的。&lt;/p&gt;
&lt;p&gt;Raft的目标是，即让算法满足工程化需要，又能保证其正确性。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Raft论文当中说Paxos算法难以理解，我并不这么觉得。因为Paxos论文里面把困难的部分都一笔带过了。只剩下简单的那部分了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="raft-vs-paxos"&gt;Raft vs. Paxos&lt;/h2&gt;
&lt;h3 id="leader"&gt;Leader选举&lt;/h3&gt;
&lt;p&gt;在Paxos论文中，Leader选举被视作一种特殊的“提案选举”。只需要Proposer和Acceptor进行一轮或多轮（取决于运气）投票，就可以确定Leader。&lt;/p&gt;
&lt;p&gt;但在实际工程中，我们需要考虑以下的问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;如何判断Leader是否存活&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;是否每一个节点都有资格担当Leader&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="leader_1"&gt;Leader的任期&lt;/h4&gt;
&lt;p&gt;Leader在被选举出来之后，都会被赋予一个任期编号（term）。在任期里，Leader会向所有成员发送心跳包以延续自己的任期。&lt;/p&gt;
&lt;p&gt;如果Leader失效无法发送心跳包的话，成员就会产生一个“选举超时”，此时就会重新触发一轮选举。&lt;/p&gt;
&lt;p&gt;选举的流程和Basic-Paxos算法类似，proposer向所有成员发送“我要当老大”的提案，成员们会酌情回复。如果得到了多数成员的肯定，这个proposer就是下一个任期的Leader了。&lt;/p&gt;
&lt;p&gt;从本质上说，每一个任期的Leader选举，都是一个独立的Basic-Paxos实例。任期号相当于Paxos里面的提案编号。&lt;/p&gt;
&lt;h4 id="leader_2"&gt;Leader资格的认定&lt;/h4&gt;
&lt;p&gt;Raft采用强一致性的模型，对于已经ACK的用户请求，要尽力保证其状态不丢失。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果你问我，现在来一核弹把机房炸了，数据都丢了，那你怎么能保证强一致性。         &lt;br&gt;
其实这个问题非常简单。很明显，我们保证了丢数据的强一致性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以我们要选出一个Leader，使其能够包含所有已经ACK的提案。当一个proposer向其它节点发送提案时，就会收到其它节点的响应。因为一个已经ACK的提案必然被多数节点所认可，所以如果一个proposer没有包含所有被ACK的提案时，它的提案就会被其它包含更多状态的节点驳回。最后被选出来的Leader，一定是包含所有被ACK的状态的节点。&lt;/p&gt;
&lt;h3 id="_2"&gt;日志复制&lt;/h3&gt;
&lt;p&gt;当Leader被选出后，Leader就会开始处理用户的请求。用户的请求可以看做一系列的命令，在接收到提案后，提案首先被分发到所有节点，节点的状态机顺序执行这些命令。在多数节点返回ACK后，这个命令就被视为“已提交”（commited）。&lt;/p&gt;
&lt;p&gt;上文中已经提到了一致性算法中的日志非常类似于网络协议中的TCP。即如果两个命令的ID一样，那么其内容必定也一样；如果两个节点都有认可了编号为p的命令，那么所有编号小于p的命令也必定保持一致。（被称为Log Matching Property）&lt;/p&gt;
&lt;p&gt;Raft为了简化算法的工程实现，把节点的状态抽象为严格append only的日志。即我们可以将日志指针向后或向前移动，来“回滚”或“更新”状态。但是绝对不允许在日志中间添加或删除日志条目。所以，在Leader发生变化时，如果leader和其他follower之间的日志不同，那么follower需要回滚日志以保持和leader日志的一致性。&lt;/p&gt;
&lt;h3 id="_3"&gt;安全性&lt;/h3&gt;
&lt;h4 id="_4"&gt;不归我管的事我不拿主意&lt;/h4&gt;
&lt;p&gt;前文我们说到，一个节点要成为Leader，一定要拥有所有已经被ACK的状态，否则就会被其它节点驳回。&lt;/p&gt;
&lt;p&gt;但是现实都会出现一些小小的意外。在系统的运行过程中，如果有一些提案只被少数节点认可，与此同时发起提案的Leader意外退出。那么在不同节点上的日志会产生“分叉”，那么我们如何解决日志当中的冲突呢？&lt;/p&gt;
&lt;p&gt;很明显，因为这些以少数节点认可的提案并没有被确认。所以我们无论是接受提案还是驳回提案，都不影响我们强一致性的要求。所以关键是处理冲突，使其不产生影响系统一致性的后效。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/18-12-02/Snipaste_2018-12-02_17-34-59.png"&gt;&lt;/p&gt;
&lt;p&gt;假设在Term1，最后一个提案是&amp;rdquo;Value:3&amp;rdquo;，这个提案并没有得到多数节点的认可，Leader就挂掉了。选出来了一个新Leader，Term数加1。在Term2，被提出的第一个提案是&amp;rdquo;Value:1&amp;rdquo;，这个提案也没有得到多数节点的认可，Leader也挂掉了。&lt;/p&gt;
&lt;p&gt;因为这两个分叉的提案都没有得到多数节点的认可，所以下一个Leader可能已经确认这两个提案，或者两个中的一个，也可能一个都没有确认。新的Leader在被选出后，需要面对的第一个问题是如何处理属于旧Term的提案。&lt;/p&gt;
&lt;p&gt;解决方案有两种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;新Leader将日志中仍没有被多数节点认可的提案重新提出，直到被多数节点认可为止&lt;/li&gt;
&lt;li&gt;新Leader忽略属于旧的Term的提案，只提交属于本Term的提案；对于日志冲突，使用复制日志的方法解决，但不会显式认可旧Term的提案。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/18-12-02/Snipaste_2018-12-02_22-02-45.png"&gt;&lt;/p&gt;
&lt;p&gt;对于方案1，有一个隐含的问题。如上图所示，在时间点1，S2为Leader，标红的两个提案并没有被确认。此时如果Leader在时间点2重新提出&amp;rdquo;Term1/Value3&amp;rdquo;，并且得到了S1和S2的认可，那么这条提案已经被多数节点认可。但是在时间点3，S3被选举为了Leader。S1和S2需要回滚日志以保持与S3日志的一致。此时就出现了一种情况，那就是已经被确认的日志被回滚掉了，强一致性就不能满足了。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/18-12-02/Snipaste_2018-12-02_22-12-50.png"&gt;&lt;/p&gt;
&lt;p&gt;如果我们采用方案2，那么被选出的新Leader提出的第一个提案的Term一定为3。确认新提案的节点接下来会复制Leader的日志，回滚掉没有被认可的提案&amp;rdquo;Term2/Value1&amp;rdquo;。对于标绿的&amp;rdquo;Term1/Value3&amp;rdquo;，虽然被复制到了其它的节点上，但是这个值并不会被确认。这样一来，我们既保证了已经被确认的提案不会被回滚，又保证了日志的一致性。&lt;/p&gt;
&lt;p&gt;在具体实现中，“T3/V1”往往是一个空命令(no-op)。这样一来，即使没有写请求，Leader就可以更快的确认新的任期并同步Log了。&lt;/p&gt;
&lt;h4 id="_5"&gt;如何证明&lt;/h4&gt;
&lt;p&gt;那么怎么保证上面的作法它是正确的呢？&lt;/p&gt;
&lt;p&gt;假设当前任期为T1，此时由于系统故障，我们选出了新的Leader - S2，并记Term为T2。因为我们严格遵守了Log Matching Property。&lt;/p&gt;
&lt;p&gt;那么，对于以下两种情况：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;T2的Leader和Voter的Log中最后一个提案的编号是一致的，那么可以知道他们日志中的提案都是完全一致的&lt;/li&gt;
&lt;li&gt;T2中Leader的Log比Voter更新，那么Leader一定包含比Voter更多的提案；否则Voter就不会给Leader投票&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们都可以证明，对于前一个Term已经被确认的提案，一定会被包含在后一个Term的日志中。也就是说，一个被确认的提案不会中途丢失。&lt;/p&gt;
&lt;h2 id="_6"&gt;成员变化&lt;/h2&gt;
&lt;p&gt;以上我们的讨论都基于系统的节点不会发生变更，但是在现实工程中，我们很难对此进行任何保证。所以一个实用的系统，一定能解决成员变化的问题。&lt;/p&gt;
&lt;p&gt;成员变化问题的本质是系统中不能同时出现两个Leader。&lt;/p&gt;
&lt;p&gt;在Raft中，我们将过渡期的配置称为“共同一致”（joint consensus），一但它被确认，说明系统已经过渡到了新的成员配置。&lt;/p&gt;
&lt;p&gt;具体的策略如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;系统中只有旧的配置C_old，新加入的成员不可能成为Leader&lt;/li&gt;
&lt;li&gt;当前系统的Leader接受到新的配置C_new。然后Leader向所有节点发起修改配置为C_old+new的提案。&lt;/li&gt;
&lt;li&gt;即使这个时间点Leader挂掉了，新的Leader也只会拥有旧配置C_old或者过渡期配置C_old+new。这取决于Leader选举的时机（和运气）。&lt;/li&gt;
&lt;li&gt;当过渡期配置C_old+new被多数节点确认后，Leader向所有节点发起修改配置为C_new的提案。&lt;/li&gt;
&lt;li&gt;如果这个时间点Leader挂掉了，新Leader会从拥有C_old+new和C_new的节点中选出。新的Leader仍然可以进行配置的变更，而不影响整个系统的安全性。&lt;/li&gt;
&lt;li&gt;直到C_new被确认，配置更换宣告完成。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;“共同一致”允许节点无需考虑安全性的情况下，在任意时间进行配置的更换。配置的更换也不会影响客户端的请求。&lt;/p&gt;
&lt;p&gt;以上我们解决的是安全性问题，但是在实际工程中我们还需要兼顾效率问题。&lt;/p&gt;
&lt;p&gt;例如新加入的节点可以视作“non-voting members”，只同步数据，不能对提案进行投票。直到数据同步基本完成，才进行配置变更。这样避免了新的节点由于缺少Log不能及时的处理提案。&lt;/p&gt;
&lt;p&gt;又如新的成员列表中，不包含原先的Leader节点。在旧Leader认可了新的配置提案之后，就可以退位让贤，让其它节点选举出新的Leader。&lt;/p&gt;
&lt;p&gt;以及被清除出成员列表的节点，不会收到后续的心跳，它们会认为Leader已经失效，所以自己跳出来竞选Leader。这样一来，就会触发新的（无意义 的）Leader选举，影响系统的可用性。解决方案是，如果一个节点在一个时间段内收到了Leader的心跳，那么就会忽略Leader的竞选请求。这样既不会影响正常的选举，又可以屏蔽无效的选举请求。&lt;/p&gt;
&lt;h2 id="_7"&gt;快照&lt;/h2&gt;
&lt;p&gt;我们的提案越来越多，日志也越来越长。随之而来的是漫长的恢复时间以及磁盘空间的浪费。快照技术可以帮我们清除旧的无用日志，只保留有用的状态信息。&lt;/p&gt;
&lt;p&gt;在Raft算法中，每个节点都能自主的生成快照。好处是避免Leader分发快照造成的效率降低，也简化了Leader的功能和职责。又由于日志的“TCP特性”，所以不同节点上，只要保证提案编号一致，那么其内容就可以保证一致。&lt;/p&gt;
&lt;h2 id="_8"&gt;客户端交互&lt;/h2&gt;
&lt;p&gt;由于客户端不了解系统内部的选举情况，所以在开始通信时，会随机选一台节点发送请求。如果这个节点不是Leader，就会拒绝这个请求，会告知客户端哪个节点是当前任期的Leader。如果Leader失效，客户端请求超时，就会重新随机选择节点，获取新任Leader信息。&lt;/p&gt;
&lt;p&gt;对于客户端发送的写请求，Leader需要记录其唯一的请求ID，以避免客户端发送的重复请求。&lt;/p&gt;
&lt;p&gt;对于客户端发送的读请求，Leader需要再次确认它是仍是当前任期的Leader，避免向客户端发送过期数据。如果对数据正确性和时效性的敏感性不高，就可以向系统中的任意节点发送请求，&lt;/p&gt;
&lt;h2 id="_9"&gt;写在后面&lt;/h2&gt;
&lt;p&gt;Paxos的亮点在于把复杂的东西说简单了。而Raft的亮点是把简单的东西具体化，使之成为能落地的工程项目。&lt;/p&gt;
&lt;p&gt;但是Paxos做为一种Quorum协议（俗称P2P），其工程复杂性是难以避免的。Raft在Paxos协议上面加入了很多限制以简化实现，但是想要完整的实现其功能仍不是一件容易的事。（有兴趣的同学可以&lt;a href="https://pdos.csail.mit.edu/6.824/labs/lab-raft.html"&gt;挑战一下自己&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;下面一篇文章我们会换一种新思路，学习PecificA算法，看一看如何使用Paxos实现一个主从复制协议。&lt;/p&gt;
&lt;h2 id="_10"&gt;写在更后面&lt;/h2&gt;
&lt;p&gt;个人觉得，Raft论文的一个更大亮点是充分的思考了Paxos/Multi-Paxos在工程实践上的缺陷。思考并提出有价值的质疑，而不是被他人的观点带着走，真的是最重要的能力之一了。&lt;/p&gt;
&lt;p&gt;大胆猜测是因为有足够的理解能力，有额外的带宽去发问？这是一个有意思的问题。&lt;/p&gt;</content><category term="Blog"/><category term="paxos"/><category term="basic paxos"/><category term="multi paxos"/><category term="raft"/><category term="数据库"/><category term="分布式系统"/><category term="一致性"/></entry><entry><title>白话一致性协议 - Paxos、Raft和PacificA[0]</title><link href="https://wizmann.top/paxos-raft-pecifaca[0].html" rel="alternate"/><published>2018-11-25T00:00:00+08:00</published><updated>2018-11-25T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2018-11-25:/paxos-raft-pecifaca[0].html</id><summary type="html">&lt;h2 id="-paxos"&gt;一致性协议 - Paxos&lt;/h2&gt;
&lt;p&gt;在分布式系统当中，我们往往需要保持节点之间的一致性。在绝大多数情况下，我们需要让系统中的节点相 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="-paxos"&gt;一致性协议 - Paxos&lt;/h2&gt;
&lt;p&gt;在分布式系统当中，我们往往需要保持节点之间的一致性。在绝大多数情况下，我们需要让系统中的节点相互协调通力合作，有可能的让系统正确的工作。但是，由于分布式系统本身的特性，需要我们在不可靠的硬件上尽可能的构建可靠的系统。所以，看似简单的一致性问题成为了分布式系统领域的一个重要的课题。&lt;/p&gt;
&lt;p&gt;Paxos算法是Leslie Lamport于1990年提出的一种一致性算法。也是目前公认解决分布式一致性问题最有效的算法之一。&lt;/p&gt;
&lt;p&gt;Paxos算法的目标是在一个不可靠的分布式系统内，只通过网络通信，能够快速且正确地在集群内部对某个数据的值达成一致。并且保证不论发生任何异常，都不会破坏系统的一致性。&lt;/p&gt;
&lt;h2 id="paxos"&gt;Paxos算法&lt;/h2&gt;
&lt;h3 id="-"&gt;另一种（简化了的）形象的问题描述 - 买车位&lt;/h3&gt;
&lt;p&gt;某小区的一些居民在抢车位，而车位只有一个。居民们达成协议，只要一个报价获得半数以上居民认可，那么提出这个出价的居民则获得了车位的所有权。&lt;/p&gt;
&lt;p&gt;居民之间非常友善，如果知道了车位已经有了买家，就不会继续出价购买，并且会帮忙传播这个信息。&lt;/p&gt;
&lt;p&gt;居民们都是遵纪守法的好公民，在整个过程中都只会如实的与其它用户分享信息。信息的分享是在网上，通过一对一的私密聊天进行。但是小区的手机信号非常差，我们不能保证通信的质量，一些信息可能会丢失。但是居民不会掉线。也不会失去记忆，并且通信的内容是完整的，不会被篡改的。&lt;/p&gt;
&lt;p&gt;划重点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;需要半数以上居民的认可，才能声称拥有车位。这个居民被称为车位的“公认拥有者”&lt;/li&gt;
&lt;li&gt;车位有且只有一个，所以一个车位不能同时有两个“公认拥有者”&lt;/li&gt;
&lt;li&gt;车位可以暂时没有拥有者，但是需要尽快选出一个&lt;/li&gt;
&lt;li&gt;通信是不可靠的(not-reliable)，但是正确性(integrity)和可持久性（durability）是可以保证的&lt;/li&gt;
&lt;li&gt;整个流程的目标是确定车位的拥有者。流程的参与者不会以自己拥有车位为最终目标&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="_1"&gt;如何选出最终的买家&lt;/h3&gt;
&lt;p&gt;由于通信是一对一的，对于所有参与者来说，他们对整个系统的了解都是片面的、过时的。但是参与者会通过与其它参与者进行通信，不断获得更及时的信息，从而最终达成一致。&lt;/p&gt;
&lt;p&gt;对于普通居民，会记录“已知最高报价”和“已确认报价”两个状态。会处理两种请求：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;询价：如果居民已确认了某个报价，则返回这个报价。否则会尝试更新已知最高报价，并报告买家当前的最高报价&lt;/li&gt;
&lt;li&gt;报价：居民会将请求中的报价与自己已知的最高报价进行比较，如果高于或等于本地已经报价，无论是否已经有已确认报价，都会确认这个报价&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而对于买家，会发出两种不同的信息：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;询价：以某一个报价问询多数居民，如果有已确认的报价，则放弃自己的报价。如果这个报价低于居民已知的报价，则提高报价。&lt;/li&gt;
&lt;li&gt;报价：如果询价过程中收到了已确认的报价，则帮忙转发这个报价。否则发送自己的报价，如果报价获得了多数居民的认可，即可以认为所有权已经更新&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="_2"&gt;一致性的直观证明&lt;/h3&gt;
&lt;p&gt;报价阶段，除了保证正确性之外，对于居民和买家并没有任何约束。其本质参与者之间同步信息的过程。&lt;/p&gt;
&lt;p&gt;而一致性在报价阶段可以被很好的保证&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果车位还没有主人，那么大家就拼一拼运气和手速，直到有一个买家获得了半数居民的认可。&lt;/li&gt;
&lt;li&gt;如果用户A已经声明以价格P买入车位（记为&lt;code&gt;(P, A)&lt;/code&gt;），此时必有多数居民已经认可&lt;code&gt;(P, A)&lt;/code&gt;。如果用户B想要声明以价格Q(Q &amp;gt;= P)买入车位，首先需要向多数居民询价，在询价的过程中，一定会收到用户A已经拥有车位的信息，此时B只会帮A扩散信息，而不会去争夺拥有权。系统最终会达到一个稳定的状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="-_1"&gt;失忆 - 放松可持久性要求&lt;/h3&gt;
&lt;p&gt;如果我们放松可持久性的限制。即居民可以掉线，或者清空自己的记忆。那此时最差情况是多数已经确认报价的居民不再承认报价，那么系统就有可能退化到“仍没有人拥有车位”的状态。此时我们只需要再进行一轮选举，选出车位新的主人即可。这并不会破坏整个系统的一致性。&lt;/p&gt;
&lt;h3 id="_3"&gt;旁观者视角&lt;/h3&gt;
&lt;p&gt;假如我们做为旁观者，想要观察是谁最终拥有了车位。可以有以下两种方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;“推”模型      &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当新的买家被选举出来时，新买家会通知所有旁观者车位的拥有者发生了变化。这样观察者们可以实时的获得状态的变化，但是由于通信是不可靠的，旁观者可能会错过状态变化的信息。如果这种情况出现，观察者只能等待下次状态变化，才能更新自己的状态。&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;“拉”模型&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;旁观者可以假装自己是一个买家，向多数居民进行询价。如果最终买家已经确定，那么询价的响应中一定包含着最新的拥有者信息。&lt;/p&gt;
&lt;h3 id="paxos_1"&gt;Paxos如何解决活锁问题&lt;/h3&gt;
&lt;p&gt;假设居民里有买家A、B，同时向其它居民提出询价/报价。如果他们的询价/报价顺序排列如下，会出现什么状况呢？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;询价，&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;块&lt;/span&gt;
&lt;span class="err"&gt;众居民：好的，最高价为&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;块&lt;/span&gt;
&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="err"&gt;：加钱，&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;块&lt;/span&gt;
&lt;span class="err"&gt;众居民：收到，最高价为&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;块&lt;/span&gt;
&lt;span class="err"&gt;（此时&lt;/span&gt;&lt;span class="n"&gt;A仍旧认为1块是最高报价&lt;/span&gt;&lt;span class="err"&gt;）&lt;/span&gt;
&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="err"&gt;：最终报价，&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;块&lt;/span&gt;
&lt;span class="err"&gt;众居民：不行不行，&lt;/span&gt;&lt;span class="n"&gt;B已经加到两块钱了&lt;/span&gt;
&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="err"&gt;：（内心&lt;/span&gt;&lt;span class="n"&gt;mmp&lt;/span&gt;&lt;span class="err"&gt;）询价，&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;块&lt;/span&gt;
&lt;span class="err"&gt;（&lt;/span&gt;&lt;span class="n"&gt;B对A提高了报价也毫无准备&lt;/span&gt;&lt;span class="err"&gt;）&lt;/span&gt;
&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="err"&gt;：最终报价，&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;块&lt;/span&gt;
&lt;span class="err"&gt;众居民：滚粗，&lt;/span&gt;&lt;span class="n"&gt;A已经报价3块了&lt;/span&gt;
&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="err"&gt;：我加钱&lt;/span&gt;
&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="err"&gt;：我再加&lt;/span&gt;
&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="err"&gt;：我加钱&lt;/span&gt;
&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="err"&gt;：我再加&lt;/span&gt;
&lt;span class="err"&gt;众居民：。。。（你们玩个球啊）&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;震惊，这帮无聊的人居然为了这几块钱可以玩一天！&lt;/p&gt;
&lt;p&gt;以这样的流程进行下去，系统会陷入活锁，几乎不能达成一致了。想要解决这个问题，可以将A和B的询价重试时间加入随机化因子，这样可以帮助更快的让居民们达成一致。&lt;/p&gt;
&lt;h3 id="paxos_2"&gt;Paxos如何解决投票分裂问题&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/18-11-25/split-vots.png"&gt;&lt;/p&gt;
&lt;p&gt;如图所示，居民们的投票可能会发生分裂，即没有一个值达到了半数。这里的解决方案是让买家重新进行询价，同时加入随机化因子，使得投票达成半数以上的概率更大。&lt;/p&gt;
&lt;h2 id="_4"&gt;说正经的&lt;/h2&gt;
&lt;p&gt;对于Paxos算法的官方描述和正确性的详细证明可以参考&lt;a href="https://lamport.azurewebsites.net/pubs/paxos-simple.pdf"&gt;原论文&lt;/a&gt;。这里就不搬运了，只是把我的例子和官方通用术语进行一下讲解，避免把大家带跑偏了。&lt;/p&gt;
&lt;p&gt;在上面的例子中，“车位”的通用术语被称为“共识”，整个系统中最多有一个共识。而“询价请求”被称为“prepare请求”，“报价请求”被称为“accept请求”。&lt;/p&gt;
&lt;p&gt;每个请求的价格被称为“编号”，编号大的请求可以覆盖编号小的请求，和“价高者得”是一个道理。请求中所带的信息被称为“value”，在我们的例子中，代表着购买者的身份信息。&lt;/p&gt;
&lt;h2 id="basic-paxosmulti-paxos"&gt;Basic Paxos和Multi Paxos&lt;/h2&gt;
&lt;p&gt;上面我们描述的Paxos算法又被称为Basic Paxos，因为每一轮流程执行完，所有的参与者都会（且只会）达成一个共识。而在实际的应用中，我们需要连续不断的对多个值达成共识。这时Basic Paxos算法就力不能及了，一来每一个值的共识都至少需要两次广播网络请求，性能太低，二来同时存在的多个提案会互相竞争，使得通信的效率下降。&lt;/p&gt;
&lt;p&gt;所以为了解决这个问题，Multi Paxos算法应运而生，即一种可以高效的、连续不断的对多个值达成共识的算法。&lt;/p&gt;
&lt;p&gt;下一篇文章中，我们会介绍一种被普遍认可，以及已经被工业界应用的Multi Paxos的实现 —— Raft算法。&lt;/p&gt;
&lt;h2 id="_5"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lamport.azurewebsites.net/pubs/paxos-simple.pdf"&gt;Paxos Made Simple&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://book.douban.com/subject/26292004/"&gt;从Paxos到Zookeeper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zhuanlan.zhihu.com/p/31780743"&gt;知乎：Paxos算法详解&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="paxos"/><category term="basic paxos"/><category term="数据库"/><category term="分布式系统"/><category term="一致性"/></entry><entry><title>七牛云图床自救指南（附github图床小工具）</title><link href="https://wizmann.top/qnsaver.html" rel="alternate"/><published>2018-11-16T22:23:00+08:00</published><updated>2018-11-16T22:23:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2018-11-16:/qnsaver.html</id><summary type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;p&gt;之前一直在用七牛云的存储做图床（简称白嫖）。但是免费的午餐必然不会长久，七牛要求所有bucket都要绑定备案过的域名，否则就停掉你的bucket的外链。这 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;背景&lt;/h2&gt;
&lt;p&gt;之前一直在用七牛云的存储做图床（简称白嫖）。但是免费的午餐必然不会长久，七牛要求所有bucket都要绑定备案过的域名，否则就停掉你的bucket的外链。这事我也不吐槽，毕竟是白嫖，也不能要求啥。&lt;/p&gt;
&lt;p&gt;但是最智障的是，你外链停了没关系，但是我在后台portal查看文件，上面的图还是显示不了，点下载也没有反应，只显示“ [5402] 获取 bucket 域名失败”。说好不嫖了，你却又不让我走了，都没办法数据迁移的。&lt;/p&gt;
&lt;p&gt;因为博客里的图全都存在了七牛的图床上，这么一波搞下来就非常伤。于是我积极展开自救行动。&lt;/p&gt;
&lt;h2 id="_2"&gt;大侦探毛利小五郎&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;我：你看我们天天查问题，像不像柯南在查案子？     &lt;br&gt;
同事：我觉得我们更像毛利小五郎。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;大胆猜测七牛的portal也是使用了外链的URL，如果不绑域名的话，是没有文件的URL的。但是我手里又没有备案后的域名。事情就陷入了僵局。&lt;/p&gt;
&lt;p&gt;七牛提供了小工具（qrsctl）让我们管理文件，我觉得这可能是个突破点，万一小工具可以把数据下载下来呢？结果也是不行，这就非常GG了。&lt;/p&gt;
&lt;p&gt;此时，我又发现小工具有拷贝数据的功能，可以把跨bucket拷贝数据，但是我的所有的bucket都没有绑域名。也并不能解决问题。&lt;/p&gt;
&lt;p&gt;我突然又想到，七牛云其实并没有完全禁止外链。对于一个全新的bucket，七牛会免费提供30天的测试域名，所以新的bucket是可以进行文件下载的。&lt;/p&gt;
&lt;p&gt;这样问题就解决了，我新建一个bucket，挂上测试域名，然后把文件都下载下来。这样数据就保住了。&lt;/p&gt;
&lt;h2 id="_3"&gt;一波自信操作&lt;/h2&gt;
&lt;p&gt;首先我们先从portal上获取ak和sk。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/18-11-16/20181116221134.png"&gt;&lt;/p&gt;
&lt;p&gt;然后使用qrsctl，登录，并获取bucket下面的所有文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./qshell_linux_x64&lt;span class="w"&gt; &lt;/span&gt;account&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;ak&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;sk&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;youname@example.com
./qshell_linux_x64&lt;span class="w"&gt; &lt;/span&gt;listbucket&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bucket_name&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;awk&lt;span class="w"&gt; &lt;/span&gt;-F&lt;span class="s2"&gt;&amp;quot;\t&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;files.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;接下来把文件拷贝到新的bucket下面。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./qshell_linux_x64&lt;span class="w"&gt; &lt;/span&gt;batchcopy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bucket_name&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;new_bucket_name&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;files.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;此时需要登录portal，获取新的bucket的测试域名。然后填入下载配置文件中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;dest_dir&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;./dest_dir&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;bucket&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;{ new_bucket_name }&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;cdn_domain&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;{ your_test_domain.clouddn.com }&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;prefix&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;suffixes&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;最后把文件统统下载下来，大功告成。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./qshell_linux_x64&lt;span class="w"&gt; &lt;/span&gt;qdownload&lt;span class="w"&gt; &lt;/span&gt;qdisk_down.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="github"&gt;附录：使用Github做图床&lt;/h2&gt;
&lt;p&gt;Github的Blob文件都是存在S3的，墙外性能还是可以的。对于博客这种轻量使用场景已经足够用了，而且重要的是Github不会搞个智障操作强行锁你数据。&lt;/p&gt;
&lt;p&gt;第一步我们需要申请一个&amp;rdquo;Personal access token&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/18-11-19/WeChat%20Screenshot_20181119143629.png"&gt;&lt;/p&gt;
&lt;p&gt;然后允许这个token操纵我们的公开repos。注意，这个token非常重要，请不要泄露！&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/Wizmann/assets/master/wizmann-pic/18-11-19/WeChat%20Screenshot_20181119143932.png"&gt;&lt;/p&gt;
&lt;p&gt;最后我们可以使用这段代码上传图片（或者其它文件）了：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;#coding=utf-8&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;base64&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%y-%m-&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;upload_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://api.github.com/repos/{{ your_id }}/{{ your_repo }}/contents/{{ path_in_repo }}/&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;upload_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Authorization&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;token {{ your_token }}&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;message&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;upload data&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;content&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;branch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;master&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;content&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;content&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;download_url&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="闲聊"/></entry><entry><title>容斥原理以及一些题目</title><link href="https://wizmann.top/inclusive-exclusive-principle.html" rel="alternate"/><published>2018-10-14T00:00:00+08:00</published><updated>2018-10-14T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2018-10-14:/inclusive-exclusive-principle.html</id><summary type="html">&lt;h2 id="_1"&gt;什么是容斥原理&lt;/h2&gt;
&lt;p&gt;容斥原理是一种计数手段。例如在下图中，我们想&lt;strong&gt;不重复、不遗漏&lt;/strong&gt;的求出包含在ABC三个集合中所包含的元素的个数，应该使用怎么样的方法 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;什么是容斥原理&lt;/h2&gt;
&lt;p&gt;容斥原理是一种计数手段。例如在下图中，我们想&lt;strong&gt;不重复、不遗漏&lt;/strong&gt;的求出包含在ABC三个集合中所包含的元素的个数，应该使用怎么样的方法呢？&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="https://raw.githubusercontent.com/Wizmann/assets/master/blog/181007-Inclusion-exclusion-principle/500px-Inclusion-exclusion.svg.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="formula" src="https://github.com/Wizmann/assets/raw/master/blog/181007-Inclusion-exclusion-principle/formula.PNG"&gt;&lt;/p&gt;
&lt;p&gt;这个问题对于我们来说并不陌生，当然也并不困难。直观的方法是把所有的元素计数，再把重复的元素排除出去。这种计数的方法，有“容”有“斥”，我们讲其称做“容斥原理”。&lt;/p&gt;
&lt;h2 id="_2"&gt;容斥原理的应用&lt;/h2&gt;
&lt;p&gt;小规模的计数问题自然难不倒我们，我们甚至可以使用&lt;code&gt;visit[]&lt;/code&gt;数组来记录某元素是否出现。但是当问题的规模增大时，使用数组记录这种方式需要使用更多的内存，在很多情况下，这是我们不能接受的。&lt;/p&gt;
&lt;h3 id="_3"&gt;考虑一个问题&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;问题：统计在1~N中的，能被2或3整除的数。(1 &amp;lt;= N &amp;lt;= 1e9)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们先把这个问题拆成两部分来看：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;N以内的，能被2整除的数&lt;/li&gt;
&lt;li&gt;N以内的，能被3整除的数&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这两个问题都非常简单，我们可以直接使用除法进行求解，其结果分别为&lt;code&gt;N/2&lt;/code&gt;和&lt;code&gt;N/3&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;与此同时，我们不能忽略同时能被2和3整除的数。这里我们先求得2和3的最小公倍数6，然后应用容斥原理，将重复计数的，能同时被2和3整除的数减去，即得到最后的结果。&lt;/p&gt;
&lt;h3 id="hdu-2204eddy"&gt;一个更复杂的问题 （HDU-2204，Eddy的爱好）&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个正整数N，确定在1到N之间有多少个可以表示成M^K（K&amp;gt;1)的数。 (1 &amp;lt;= N &amp;lt;=1e18)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这里我们先考虑K=2和3时的情况。对于正整数N，我们有&lt;code&gt;pow(K, 1.0/2)&lt;/code&gt;个数可以表示为&lt;code&gt;2^K&lt;/code&gt;；有&lt;code&gt;pow(K, 1.0/3)&lt;/code&gt;个数可以表示为&lt;code&gt;3^K&lt;/code&gt;。这个原理非常简单，这里不做展开。&lt;/p&gt;
&lt;p&gt;但是，对于N=64来说，既可以表示为&lt;code&gt;4^3&lt;/code&gt;，又可以表示为&lt;code&gt;8^2&lt;/code&gt;。那么在上面计数的时候一定出现了重复计数的情况。所以根据容斥原理，我们将所有6的乘方全部排除。&lt;/p&gt;
&lt;p&gt;那么对于N=4096的情况，它可以表示为&lt;code&gt;2^12&lt;/code&gt;。那么在计数中我们是否需要考虑12的乘方呢？答案是否定的，因为12的乘方一定是6的乘方，这种情况我们已经处理过了，所以不需要再次处理。推而广之，若K可以分解质因数为&lt;code&gt;a^k1 + b^k2 + c^k3&lt;/code&gt;，当且仅当&lt;code&gt;k1 == k2 == k3 == 1&lt;/code&gt;时，我们才进行计数。&lt;/p&gt;
&lt;p&gt;现在我们考虑更普遍的情况，对于任意K，我们先对其进行质因数分解。根据容斥原理，当其质因数的个数为奇数时，我们对其进行计数；为偶数时，我们从计数中排除这种重复情况。&lt;/p&gt;
&lt;h2 id="_4"&gt;更多的例题&lt;/h2&gt;
&lt;h3 id="hdu-1796"&gt;计数：不能被集合里的数整除的数（HDU - 1796）&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个正整数集合，求在1~N中，有多少个数不能被集合中的数整除。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这道题是第一个例子的扩展。我们枚举集合的子集合，并求出子集合的最小公倍数，使用容斥原理进行计数即可。&lt;/p&gt;
&lt;h3 id="1poj-1091"&gt;计数：集合中至少有一对数的最大公约数为1的集合数（POJ - 1091）&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;求大小为N+1的集合A[N + 1]，对于任意A[i]有 A[i] &amp;lt;= M，且A[N + 1]一定包含整数M，集合内的数可以重复。问有多少数这样的集合，使得集合中至少有一对数的最大公约数为1。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这道题的关键在于每一个集合都必须包含M。我们可以反向求解，“至少有一对的最大公约数为1”的否命题为“所有的数对的最大公约数均不为1”。这里枚举所有的最大公约数的值，并且使用容斥原理排除重复记数。&lt;/p&gt;
&lt;h3 id="hdu-2841"&gt;计数：平面上斜率不同的点（HDU - 2841）&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;给定整数N、M。求一共有多少种不同的k=n/m，使得 1 &amp;lt;= n &amp;lt;= N，1 &amp;lt;= m &amp;lt;= M。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因为k=n/m，所以在n和m的取值不互质时，我们可以将其进行约分，就会产生可能的计数重复。所以本题可以转化为求“一共有多少对互质的n、m”。我们可以枚举m来求n，就又可以转化为“对于给定的m，有多少个n与其互质”。此时可以对m进行分解质因数，使用容斥原理进行统计。&lt;/p&gt;
&lt;h3 id="dp-leetcode-920-number-of-music-playlists"&gt;容斥原理 + DP （Leetcode - 920. Number of Music Playlists）&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;给定N种不同的元素，让你生成一个长度为L的列表，问有多少种不同的列表组合满足：&lt;br&gt;
1. 所有的元素至少出现一次&lt;br&gt;
2. 相同的元素之间至少距离K&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本题的难度在于“所有的元素至少出现一次”，如果无脑DP的话，我们需要使用一维的DP来记录元素出现的情况。不过我们可以忽略这个条件，直接求意为“长度为L的列表，有多少个组合满足相同元素之间至少距离K”。这个问题我们可以使用O(N)的DP来解决。&lt;/p&gt;
&lt;p&gt;此时的问题是我们求出来的结果可能不满足“所有的元素至少出现一次”，也就是说我们的列表里可能有不足N个元素。此时我们使用容斥原理，减去列表中不足N个元素的情况。&lt;/p&gt;
&lt;h2 id="_5"&gt;如果我们来出题&amp;hellip;&lt;/h2&gt;
&lt;p&gt;对于容斥原理，如果我们站在出题人的角度，可以将其应用在如下几类“求并集的大小”的（伪）数论问题上：求能被集合中的数整数的数、求能表示为集合中的数的乘方的数、求与给定的数互质的数等。也可以用来配合DP求组合数。&lt;/p&gt;
&lt;p&gt;但无论包装成什么样子的题目，如果它的核心是一个计数问题，并且涉及到“求并集的大小”，我们就可以尝试使用容斥原理来求解。&lt;/p&gt;
&lt;h2 id="_6"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://zh.wikipedia.org/wiki/%E6%8E%92%E5%AE%B9%E5%8E%9F%E7%90%86"&gt;容斥原理 - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vjudge.net/contest/253352#overview"&gt;ACM老年队容斥原理&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="Algorithm"/><category term="容斥原理"/><category term="计数"/></entry><entry><title>实现一个无锁消息队列</title><link href="https://wizmann.top/implement-non-blocking-queue.html" rel="alternate"/><published>2018-05-02T00:39:00+08:00</published><updated>2018-05-02T00:39:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2018-05-02:/implement-non-blocking-queue.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;240414更新：后续补充了一篇勘误文章，见&lt;a href="/implement-non-blocking-queue-2.html"&gt;这里&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;目标&lt;/h2&gt;
&lt;p&gt;实现一个多读多写的无锁消息队列。&lt;/p&gt;
&lt;h2 id="cmpxchg-"&gt;cmpxchg - 比较并替换&lt;/h2&gt;
&lt;p&gt;比较并替换（compare-and-swap, CAS）是一个用于 …&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;240414更新：后续补充了一篇勘误文章，见&lt;a href="/implement-non-blocking-queue-2.html"&gt;这里&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;目标&lt;/h2&gt;
&lt;p&gt;实现一个多读多写的无锁消息队列。&lt;/p&gt;
&lt;h2 id="cmpxchg-"&gt;cmpxchg - 比较并替换&lt;/h2&gt;
&lt;p&gt;比较并替换（compare-and-swap, CAS）是一个用于多线程同步的原子操作。&lt;/p&gt;
&lt;p&gt;其工作流程是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;cmpxchg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;oldval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newval&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;oldval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newval&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;也就是说，只有当&lt;code&gt;val&lt;/code&gt;等于&lt;code&gt;oldval&lt;/code&gt;时，我们才会将&lt;code&gt;val&lt;/code&gt;的值替换成&lt;code&gt;newval&lt;/code&gt;。在多线程的场景下，cmpxchg用来保证多线程写的原子性。&lt;/p&gt;
&lt;p&gt;例如，线程1和线程2都要写入&lt;code&gt;val&lt;/code&gt;变量，但是我们需要保证只有一个线程能写成功。使用cmpxchg，能保证只有一个线程能成功的将&lt;code&gt;val&lt;/code&gt;变量替换成新值，写失败的线程会得到&lt;code&gt;False&lt;/code&gt;的返回值。&lt;/p&gt;
&lt;h2 id="access_once-"&gt;ACCESS_ONCE - 消除优化歧义&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&amp;amp;(x))；&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;ACCESS_ONCE&lt;/code&gt;的作用是将一个指针转化成&lt;code&gt;volatile&lt;/code&gt;指针，使得读取操作“真的”去读取指针的值而不被编译器优化掉。&lt;/p&gt;
&lt;h2 id="_2"&gt;实现&lt;/h2&gt;
&lt;h3 id="nullable"&gt;原子操作与Nullable&lt;/h3&gt;
&lt;p&gt;说到多线程，我们就不能不谈原子操作。对于一个队列来说，我们可以在其中存储任意复杂的数据结构，但是这些数据结构大部分都不支持原子操作。&lt;/p&gt;
&lt;p&gt;同样，我们也没有一种有效的手段来标识一个值是“不存在的”。是的，我们可以自己实现一个&lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt;的模板，但是带来的额外成本就是对于任意&lt;code&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt;的赋值都要经过两步以上的中间步骤，这简直就是竞态bug产生的温床。&lt;/p&gt;
&lt;p&gt;不过，在C++中自带着一个有着&amp;rdquo;Nullable&amp;rdquo;语意的数据结构 —— 指针。当指针为NULL时，意味着值是不存在的，而指针不为NULL时，它代表着它所指向的值。更重要的是，指针的赋值、读取、拷贝都是原子的，这给我们的代码实现提供了非常大的便利。&lt;/p&gt;
&lt;h3 id="_3"&gt;数据结构&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/18-5-1/40471673.jpg"&gt;&lt;/p&gt;
&lt;p&gt;我们使用单链表做为基础数据结构，链表的头代表着队列的头，链表的尾对应着队列的尾。这样添加数据时，我们在TAIL节点处写入，弹出数据时从HEAD节点处弹出。&lt;/p&gt;
&lt;p&gt;那么问题来了，在单线程下，维护头尾节点是非常容易的操作。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;维护头节点&lt;/span&gt;
&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;
&lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HEAD&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="c1"&gt;# 操作链表&lt;/span&gt;

&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;维护尾节点&lt;/span&gt;
&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;newnode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;TAIL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newnode&lt;/span&gt; &lt;span class="c1"&gt;# 操作链表&lt;/span&gt;
&lt;span class="n"&gt;TAIL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TAIL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="c1"&gt;# 操作链表&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;但是在多线程环境下，维护尾节点需要对链表进行两次操作，我们很难把它做为原子的。这大概是实现无锁队列最大的难点之一。&lt;/p&gt;
&lt;h3 id="_4"&gt;框架代码&lt;/h3&gt;
&lt;p&gt;无锁队列中，&lt;code&gt;push&lt;/code&gt;和&lt;code&gt;pop&lt;/code&gt;两个函数是核心代码。但是我们需要先把框架代码先搭好。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;NonBlockingQueue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;NonBlockingQueue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InnerNode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// pass&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// pass&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;InnerNode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value_ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;InnerNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;InnerNode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;InnerNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;InnerNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这里的&lt;code&gt;dummy&lt;/code&gt;是一个假的头节点，是为了方便节点的插入的，可以替换成一个头节点指针。&lt;code&gt;tail&lt;/code&gt;是尾节点，在构造函数里，我们也将其置为一个假的尾节点，注意这里尾节点的设计，后文会再次提到。&lt;/p&gt;
&lt;h3 id="_5"&gt;出队操作&lt;/h3&gt;
&lt;p&gt;我们先从最简单的出队操作开始&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;InnerNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACCESS_ONCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;__sync_bool_compare_and_swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value_ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// delete(cur); &amp;lt;- why?&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;代码中的&lt;code&gt;__sync_bool_compare_and_swap&lt;/code&gt;即上文所说的&lt;code&gt;cmpxchg&lt;/code&gt;函数，保证了赋值的原子性。&lt;/p&gt;
&lt;p&gt;操作过程非常简单，我们先找到位于队列头的值（HEAD节点后面的第一个）。然后使用CAS操作将其换出链表。&lt;/p&gt;
&lt;p&gt;由于tail节点是假的尾节点，所以在&lt;code&gt;head-&amp;gt;next == tail&lt;/code&gt;时，我们认为队列为空，返回false。&lt;/p&gt;
&lt;p&gt;这里有一点需要注意，&lt;code&gt;cur&lt;/code&gt;指针在while循环外看似已经脱离了链表，可以放心的删除了。但是由于其它线程仍有可能持有该指针，所以我们并不能在这里对它进行删除操作。&lt;/p&gt;
&lt;p&gt;在实际工程中，我们可以将其放置于一个回收队列中，待一小段时间后（如500ms），所有的线程都不持有该指针时，就可以安全的将其回收了。这里由于篇幅原因（注释：懒），就不实现了。&lt;/p&gt;
&lt;h3 id="_6"&gt;入队操作&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;InnerNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;InnerNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InnerNode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACCESS_ONCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__sync_bool_compare_and_swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value_ptr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这里的&lt;code&gt;push&lt;/code&gt;操作有一个trick，我们将&lt;code&gt;tail-&amp;gt;value_ptr&lt;/code&gt;做为“一把锁”。当&lt;code&gt;value_ptr&lt;/code&gt;为空时，tail指针代表着一个“假尾节点”。当我们向尾部追加数据时，先将数据写入&lt;code&gt;value_ptr&lt;/code&gt;，代表这个节点已经被“占领”。然后再向它的后面追加新的“假尾节点”，最后将指针移动过去。&lt;/p&gt;
&lt;p&gt;这样一来，进入&lt;code&gt;if&lt;/code&gt;代码块的线程一定是写入&lt;code&gt;tail-&amp;gt;value_ptr&lt;/code&gt;成功的那一个，后面的指针移动也是单线程的了。&lt;/p&gt;
&lt;h2 id="_7"&gt;感悟与可能的改进&lt;/h2&gt;
&lt;p&gt;最近确实好久不写这么底层的代码，手生的厉害，对于多线程状态的分析也不是很灵光。确实需要多努力了。本文中的代码也许还有一些问题，所以欢迎大家指正。&lt;/p&gt;
&lt;p&gt;在写这段代码的过程中，感觉有如下需要注意的地方：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;析构一块内存是否是安全的，会不会别的线程仍在持有这块内存的指针&lt;/li&gt;
&lt;li&gt;编译器会不会给我们捣乱，比如重排指令等&lt;/li&gt;
&lt;li&gt;利用CAS的特性，我们可以实现一个锁的结构，但是以哪个变量/指针做为锁可以获得最好的效果&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除了用链表实现队列之外，还可以使用环型数组。感觉上来说比使用链表更优雅一点。关键在于环型数组中隐含着前驱指针和后继节点的信息，所以不需要进行复杂的内存管理工作。&lt;/p&gt;
&lt;p&gt;完整实现请参考&lt;a href="https://paste.ubuntu.com/p/vYD6h5sm9n/"&gt;链接&lt;/a&gt;，亲测在Ubuntu 16.04下使用&lt;code&gt;g++ main.cc -lpthread&lt;/code&gt;编译运行成功。（p.s. 不要加C++11标签，编不过的）&lt;/p&gt;
&lt;h2 id="_8"&gt;相关链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://coolshell.cn/articles/8239.html"&gt;无锁队列的实现 - 酷壳&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;弱弱感觉文章里说的实现有问题（240414更新：其实是没有问题的，见勘误文章）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://cloud.tencent.com/developer/article/1006241"&gt;共享内存无锁队列的实现&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;指出了实现上面可能踩到的坑&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://cloud.tencent.com/developer/article/1071029"&gt;一种高效无锁内存队列的实现&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;环形数组的实现&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="multi-thread"/><category term="cas"/><category term="cmpxchg"/></entry><entry><title>一种区间交问题的奇怪姿势</title><link href="https://wizmann.top/range-problem.html" rel="alternate"/><published>2018-02-20T22:59:47+08:00</published><updated>2018-02-20T22:59:47+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2018-02-20:/range-problem.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;Update[220504]: 原来这种数据结构叫&lt;a href="https://oi-wiki.org/ds/odt/"&gt;珂朵莉树&lt;/a&gt;啊，真神奇。。。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;我们要解决什么问题&lt;/h2&gt;
&lt;p&gt;区间交问题，是我们在做题中经常遇到的问题。&lt;/p&gt;
&lt;p&gt;例如，&lt;a href="https://leetcode.com/problems/insert-interval/description/"&gt;Insert …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;Update[220504]: 原来这种数据结构叫&lt;a href="https://oi-wiki.org/ds/odt/"&gt;珂朵莉树&lt;/a&gt;啊，真神奇。。。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;我们要解决什么问题&lt;/h2&gt;
&lt;p&gt;区间交问题，是我们在做题中经常遇到的问题。&lt;/p&gt;
&lt;p&gt;例如，&lt;a href="https://leetcode.com/problems/insert-interval/description/"&gt;Insert Interval&lt;/a&gt;一题，就是比较直白的区间交问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一系列的整数区间，再插入一个新的区间，问合并后的整数区间是什么&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;类似的还有&lt;a href="https://leetcode.com/problems/merge-intervals/description/"&gt;Merge Intervals&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一系列可能有重叠的整数区间，求合并后的整数区间&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;另一种区间交问题的描述是时间区间相关的问题，如&lt;a href="http://lintcode.com/en/problem/time-intersection/"&gt;Time Intersection&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定用户A和用户B的在线时间区间，问两人同时在线的时间区间&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;又如经典的会议室安排问题&lt;a href="https://segmentfault.com/a/1190000003894670"&gt;Meeting Rooms&lt;/a&gt;和&lt;a href="http://www.cnblogs.com/grandyang/p/5244720.html"&gt;Meeting Rooms II&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定N个会议的时间区间，问一个人能否参加所有的会议&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;以及&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定N个会议的时间区间，问最少需要多少个会议室&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;还有系统设计与API设计包装后的算法题&lt;a href="https://leetcode.com/problems/range-module/description/"&gt;Range Module&lt;/a&gt;。归根结底，都是整数区间问题的变形或者包装。&lt;/p&gt;
&lt;h2 id="_2"&gt;传统解法&lt;/h2&gt;
&lt;p&gt;对于这类区间问题，传统的解法是将区间使用顺序容器（如&lt;code&gt;vector&lt;/code&gt;）保存，在查询和修改时，使用“排序+遍历”或者“排序+二分”。&lt;/p&gt;
&lt;p&gt;这种解决在一定程度上是区间问题的通解，但是这样做也有它的问题。&lt;/p&gt;
&lt;p&gt;一来区间问题有很多对区间序列进行随机增加、删除，这样的操作对于顺序容器是非常不友好的。&lt;/p&gt;
&lt;p&gt;二来对于使用“起点”或“终点”排序的区间，二分查找需要处理很多重复值，在某些情况下会发生复杂度的退化。&lt;/p&gt;
&lt;p&gt;那么我们如何优化我们的实现来解决以上的问题呢？&lt;/p&gt;
&lt;h2 id="stdsetinterval"&gt;使用&lt;code&gt;std::set&amp;lt;Interval&amp;gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;我们以&lt;a href="https://leetcode.com/problems/merge-intervals/description/"&gt;Merge Intervals&lt;/a&gt;一题为例。只要两个区间有交集，无论是哪一种形式的相交，那么我们就需要把这两个区间合并。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/18-2-20/85403056.jpg"&gt;&lt;/p&gt;
&lt;p&gt;所以，我们只需要能高效的判断两个区间&lt;strong&gt;是否相交&lt;/strong&gt;，就可以解决这个问题了。&lt;/p&gt;
&lt;p&gt;但是在这里，我们反其道而行之，先来讨论一下&lt;strong&gt;不相交&lt;/strong&gt;的情况。对于两个不相交的区间&lt;code&gt;A&lt;/code&gt;和&lt;code&gt;B&lt;/code&gt;，只存在两种情况，一是&lt;code&gt;A&lt;/code&gt;在&lt;code&gt;B&lt;/code&gt;左面，二是&lt;code&gt;A&lt;/code&gt;在&lt;code&gt;B&lt;/code&gt;右面。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/18-2-20/87075632.jpg"&gt;&lt;/p&gt;
&lt;p&gt;我们可以把区间的左右关系看成不相交区间的顺序关系，即：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果区间&lt;code&gt;A&lt;/code&gt;在区间&lt;code&gt;B&lt;/code&gt;的“左边”，我们说&lt;code&gt;A &amp;lt; B&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;如果区间&lt;code&gt;A&lt;/code&gt;在区间&lt;code&gt;B&lt;/code&gt;的“右边”，我们说&lt;code&gt;A &amp;gt; B&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，根据不相交区间的性质，我们可以很自然的将它们存储在&lt;code&gt;std::set&amp;lt;Interval&amp;gt;&lt;/code&gt;当中。这样我们就可以在&lt;code&gt;O(logN)&lt;/code&gt;时间进行查找、随机插入与随机删除。&lt;/p&gt;
&lt;p&gt;那么，回到最开始判断区间&lt;strong&gt;是否相交&lt;/strong&gt;的问题。对于相交的区间&lt;code&gt;A&lt;/code&gt;和&lt;code&gt;B&lt;/code&gt;，非常明显，&lt;code&gt;A &amp;lt; B&lt;/code&gt;与&lt;code&gt;A &amp;gt; B&lt;/code&gt;都是不成立的。在&lt;code&gt;std::set&amp;lt;Interval&amp;gt;&lt;/code&gt;中，这种关系被判定为&lt;strong&gt;相等&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;虽然这种&lt;strong&gt;相等&lt;/strong&gt;关系是不符合常规逻辑的，但是却非常实用。如果两个区间有“大小”关系，我们可以知道区间的相对位置。而如果两个区间“相等”，则我们可以知道两个区间一定相交。更重要的是，在这类题目中，两个相交的区间是不能同时存在的。这与&lt;code&gt;std::set&amp;lt;Interval&amp;gt;&lt;/code&gt;中元素的唯一性相呼应。&lt;/p&gt;
&lt;p&gt;所以，在使用&lt;code&gt;std::set&amp;lt;Interval&amp;gt;&lt;/code&gt;来存储区间时，我们可以使用如下的性质：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;find()&lt;/code&gt;函数来查找相交区间。这里要注意，相交的区间可能有多个&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;insert()&lt;/code&gt;来插入区间。这里要注意，先要判断是否有区间与新插入的区间相交&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;erase()&lt;/code&gt;来删除区间。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="-merge-intervals"&gt;实战 - Merge Intervals&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;在Merge Intervals一题中使用std::set&lt;Interval&gt;并不是最优的解法。这里只做举例。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;题目链接：&lt;a href="https://leetcode.com/problems/merge-intervals/description/"&gt;Merge Intervals&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; * Definition for an interval.&lt;/span&gt;
&lt;span class="cm"&gt; * struct Interval {&lt;/span&gt;
&lt;span class="cm"&gt; *     int start;&lt;/span&gt;
&lt;span class="cm"&gt; *     int end;&lt;/span&gt;
&lt;span class="cm"&gt; *     Interval() : start(0), end(0) {}&lt;/span&gt;
&lt;span class="cm"&gt; *     Interval(int s, int e) : start(s), end(e) {}&lt;/span&gt;
&lt;span class="cm"&gt; * };&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;

&lt;span class="c1"&gt;// overload the comparator for std::set&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Interval&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Interval&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Interval&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Interval&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;intervals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Interval&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;intervals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// merge intervals which are overlaped&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;erase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// add the new interval to std::set&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// copy the intervals to a vector&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Interval&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;back_inserter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;上面的代码中，&lt;code&gt;std::set&amp;lt;Interval&amp;gt;&lt;/code&gt;中存储了已经合并好的区间。当加入新的区间时，我们会先判断新区间是否与已有区间相关，如果相交，则进行合并。&lt;/p&gt;
&lt;h2 id="-range-module"&gt;实战 - Range Module&lt;/h2&gt;
&lt;p&gt;题目链接：&lt;a href="https://leetcode.com/problems/range-module/description/"&gt;Range Module&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;题意：   &lt;br&gt;
设计一个类，提供三个接口：        &lt;br&gt;&lt;br&gt;&lt;br&gt;
接口1：&lt;code&gt;void addRange(int left, int right)&lt;/code&gt;   &lt;br&gt;
将区间&lt;code&gt;[left, right - 1]&lt;/code&gt;加入区间集合 &lt;br&gt;&lt;br&gt;&lt;br&gt;
接口2：&lt;code&gt;bool queryRange(int left, int right)&lt;/code&gt;   &lt;br&gt;
查询是否已有区间与区间&lt;code&gt;[left, right - 1]&lt;/code&gt;相交 &lt;br&gt;&lt;br&gt;&lt;br&gt;
接口3：&lt;code&gt;void removeRange(int left, int right)&lt;/code&gt;&lt;br&gt;
移除已有区间内，位于&lt;code&gt;[left, right - 1]&lt;/code&gt;范围内的所有数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个题目看似可以完全套用我们上面讲到的&lt;code&gt;std::set&amp;lt;Interval&amp;gt;&lt;/code&gt;的实现，但是这里有几个暗坑需要注意。&lt;/p&gt;
&lt;p&gt;首先我们来看接口3，这里的删除并不是删除区间，而是删除整数，所以我们可以使用&lt;code&gt;find()&lt;/code&gt;函数，但是与之前的合并操作不同，我们在这里要删除区间中的一部分。&lt;/p&gt;
&lt;p&gt;在删除整数操作进行完之后，会引入一个新问题，这就是一些连续的整数区间，会在&lt;code&gt;std::set&amp;lt;Interval&amp;gt;&lt;/code&gt;中表现为独立的多个区间。例如，区间&lt;code&gt;[1, 5]&lt;/code&gt;，在删除了&lt;code&gt;[2, 3]&lt;/code&gt;之后，会形成两个区间&lt;code&gt;[1, 1]&lt;/code&gt; 和 &lt;code&gt;[4, 5]&lt;/code&gt;。我们再把区间&lt;code&gt;[2, 3]&lt;/code&gt;加回来，如果不进行特殊操作，就会产生三个不相交但连续的区间&lt;code&gt;[1, 1]&lt;/code&gt;、&lt;code&gt;[2, 3]&lt;/code&gt;和&lt;code&gt;[4, 5]&lt;/code&gt;。所以我们在插入区间时，要多做一步区间合并的操作。&lt;/p&gt;
&lt;p&gt;具体的实现为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在插入区间&lt;code&gt;[l, r]&lt;/code&gt;之前，先查找是不存在区间包含&lt;code&gt;[l - 1, l - 1]&lt;/code&gt;或&lt;code&gt;[r + 1, r + 1]&lt;/code&gt;。如果有，则先将已有的相邻区间合并的新区间里&lt;/li&gt;
&lt;li&gt;将新的区间进行合并操作，插入&lt;code&gt;std::set&amp;lt;Interval&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;正确性证明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;已知1：空区间集合不包含&lt;strong&gt;不相交但连续的区间&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;已知2：只有插入操作会产生&lt;strong&gt;不相交但连续的区间&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;归纳假设：我们保证在任何插入新区间的操作之前，&lt;code&gt;std::set&amp;lt;Interval&amp;gt;&lt;/code&gt;中均不包含&lt;strong&gt;不相交但连续的区间&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;证明：&lt;br&gt;&lt;br&gt;
如果区间集合内不包含&lt;strong&gt;不相交但连续的区间&lt;/strong&gt;，那么对于新加区间，我们只需要尝试合并其近邻区间&lt;code&gt;[l - 1, l - 1]&lt;/code&gt;和&lt;code&gt;[r + 1, r + 1]&lt;/code&gt;，就不会产生&lt;strong&gt;不相交但连续的区间&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代码实现如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MyInterval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyInterval&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;RangeModule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RangeModule&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// pass&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;addRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;MyInterval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;liter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;liter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;liter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;MyInterval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;riter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;riter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;riter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;doAddRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doAddRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;MyInterval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;erase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queryRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;MyInterval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;removeRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;MyInterval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;erase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;newInterval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyInterval&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="algorithm"/><category term="leetcode"/><category term="C++"/></entry><entry><title>Bw-Tree：在新硬件平台上的新B-Tree</title><link href="https://wizmann.top/bw-tree.html" rel="alternate"/><published>2017-12-18T00:49:00+08:00</published><updated>2017-12-18T00:49:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2017-12-18:/bw-tree.html</id><summary type="html">&lt;h2 id="ars-bw-tree"&gt;ARS 与 Bw-Tree&lt;/h2&gt;
&lt;p&gt;nosql数据库从本质上说，都属于ARS（Atomic Record Stores，“原子记录存储”）。&lt;/p&gt;
&lt;p&gt;最常见的“原子记录存储”一种实现就是朴素的Hash表：通过一个特定的key，来读写一条 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="ars-bw-tree"&gt;ARS 与 Bw-Tree&lt;/h2&gt;
&lt;p&gt;nosql数据库从本质上说，都属于ARS（Atomic Record Stores，“原子记录存储”）。&lt;/p&gt;
&lt;p&gt;最常见的“原子记录存储”一种实现就是朴素的Hash表：通过一个特定的key，来读写一条独立的数据记录。&lt;/p&gt;
&lt;p&gt;一些基于key-value（键-值）模型的nosql的内部实现正是使用了Hash表，例如Redis&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;、memcache、Riak等。&lt;/p&gt;
&lt;p&gt;而有一些nosql数据库为了支持高效的key-sequential（键-序列）查找，采用了tree-based&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;数据结构进行数据存储，所以B-Tree成为了一些数据库（both nosql and sql）的首选。&lt;/p&gt;
&lt;p&gt;本文介绍了一种基于新型硬件的高性能ARS实现，其核心技术有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;页式内存管理&lt;/li&gt;
&lt;li&gt;Bw-Tree，一种基于B-Tree的树存储结构&lt;/li&gt;
&lt;li&gt;基于日志的存储管理&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-8/19953353.jpg"&gt;&lt;/p&gt;
&lt;h2 id="bw-tree"&gt;在现代硬件上的Bw-Tree&lt;/h2&gt;
&lt;h3 id="cpu"&gt;现代多核CPU&lt;/h3&gt;
&lt;p&gt;多核CPU带来了高并发，但是同时也引入了锁竞争和缓存失效问题。&lt;/p&gt;
&lt;p&gt;为了讲解锁竞争，这里我们举一个经典的例子：多线程计数器。&lt;/p&gt;
&lt;p&gt;我们都知道，如果不使用锁来保护计数器变量的话，那么最终的结果几乎不可能是正确的。多个线程中，只能有唯一一个线程可以持有锁，其它的线程都需要等待。这样就影响到了程序的并发度。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里一些高级玩家会提到CAS（compare-and-swap）命令。CAS翻译成中文就是“比较并交换”，用在多线程编程中实现数据交换操作。详情请见：&lt;a href="https://en.wikipedia.org/wiki/Compare-and-swap"&gt;比较并交换&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;缓存失效产生于两种场景。一是上文提到的锁争用，即每次锁争用都会让当前线程陷入内核态，产生上下文切换，导致CPU缓存的失效。二是缓存一致性协议导致的缓存行失效，即多个CPU在共享一个共同的主存资源时，为了保证缓存中的数据一致性，在主存资源被修改后，相应的缓存行也会失效。&lt;/p&gt;
&lt;p&gt;Bw-Tree为了解决以上的问题，使用了以下两个措施。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;无锁数据结构    &lt;br&gt;
避免了系统阻塞在锁上，更避免了由于锁争用导致的缓存失效以及上下文切换。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;增量更新    &lt;br&gt;
使用增量更新而不是原地更新，避免修改共享的主存资源，规避缓存一致性产生的缓存失效问题。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="_1"&gt;现代存储设备&lt;/h3&gt;
&lt;p&gt;数据库系统的一个重要瓶颈就是IO性能。SSD（固态硬盘）提供了比传统机械 硬盘更好的读写性能，虽然表面上缓解了问题，但是IO仍然可能是整个系统的瓶颈。&lt;/p&gt;
&lt;p&gt;所以，Bw-Tree使用大内存做为读缓存，同时采用append-only结构保存写信息。因为不论是SSD还是机械硬盘，顺序读写的性能都非常出色。&lt;/p&gt;
&lt;h2 id="bw-tree_1"&gt;Bw-Tree的页式存储结构&lt;/h2&gt;
&lt;h3 id="mapping-table"&gt;映射表（Mapping Table）&lt;/h3&gt;
&lt;p&gt;上文中我们提到了缓存一致性（cache coherance），简单来说，就是当我们修改多个CPU共享的内存资源时，会导致缓存的失效，进而影响指令的执行效率。&lt;/p&gt;
&lt;p&gt;Bw-Tree使用页式（paginated）存储管理与映射表解决了这个问题。Bw-Tree以“页”做为存储的单元，每一页都有一个PID。页的物理位置可以存储在主存上，也可以存储在磁盘上。&lt;/p&gt;
&lt;p&gt;映射表将PID所代表的映射到页所在的具体物理位置。所以当页的物理位置发生改变时，仍然保持PID一致，不需要对Bw-Tree的结构进行任何修改。&lt;/p&gt;
&lt;h3 id="delta-updating"&gt;增量修改（Delta Updating）&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-10/18893113.jpg"&gt;&lt;/p&gt;
&lt;p&gt;假设我们现在有数据&lt;code&gt;D&lt;/code&gt;，当有修改请求&lt;code&gt;delta&lt;/code&gt;到来时，我们可以将数据&lt;code&gt;D&lt;/code&gt;&lt;strong&gt;原地&lt;/strong&gt;修改为&lt;code&gt;D'&lt;/code&gt;。也可以使用增量更新的方法将其保存为&lt;code&gt;delta + D&lt;/code&gt;的形式。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-18/98762144.jpg"&gt;&lt;/p&gt;
&lt;p&gt;增量更新看起来比原地更新耗费了更多的内存，但其优势也非常明显。一是修改不需要对页加锁，可以使用CAS无锁方法安全的更新共享资源。二是不需要修改页内存，不会导致现有cache失效。&lt;/p&gt;
&lt;p&gt;当增量过多时，Bw-Tree会自动合并增量和页内存，这个过程同样是无锁的。&lt;/p&gt;
&lt;h3 id="elastic-virtual-pages"&gt;弹性虚拟页（Elastic Virtual Pages）&lt;/h3&gt;
&lt;p&gt;&lt;img alt="image" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-10/91449803.jpg"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;B+-Tree，图片来源：&lt;a href="https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html"&gt;B+ Trees Visualization&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;B+-Tree的特性有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;所有记录都在叶子节点（节点也被称为页）上，并且是顺序存放的&lt;/li&gt;
&lt;li&gt;每个非叶子节点包含关键字（references）与孩子指针&lt;/li&gt;
&lt;li&gt;叶子节点有一个指向左右兄弟的指针，方便顺序遍历数据&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bw-Tree在B+-Tree的基础上添加了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;low/high key，用来标明本节点以及子节点的数据范围&lt;/li&gt;
&lt;li&gt;每个节点（包括叶子节点和中间节点）都有一个side pointer指向其右面的兄弟节点&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="_2"&gt;范围查询&lt;/h3&gt;
&lt;p&gt;由于Bw-Tree的数据都分布在叶子节点，并且叶子节点之间可以通过兄弟指针进行遍历。&lt;/p&gt;
&lt;p&gt;我们使用游标（cursor）来标记当前检索的位置。并且使用缓存当前页上符合条件的记录。这样可以加速逐条遍历操作（&amp;rdquo;next-record&amp;rdquo; functionality）。&lt;/p&gt;
&lt;p&gt;逐条遍历操作是原子的，但是逐条遍历某一段数据则不是原子的。如果读写同时发生在同一页，则我们会根据事务的同步级别来决定是否需要重建检索缓存。&lt;/p&gt;
&lt;h3 id="_3"&gt;垃圾回收&lt;/h3&gt;
&lt;p&gt;无锁数据结构导致的一个结果，是我们无法显式的让某个页失效。这意味着，一些线程会持有过时的数据，所以在删除这些过时的数据时要非常小心。&lt;/p&gt;
&lt;p&gt;所以这里引入了“代”（epoch）的概念，每一个线程执行每一个操作都在某一个代中，并且这一代中的所有数据以及过时数据都不会被删除。当某一代中所有线程操作都被执行完毕后，这一代就会结束，其中的过时数据就会被安全的回收。&lt;/p&gt;
&lt;h2 id="bw-tree_2"&gt;Bw-Tree的结构改变&lt;/h2&gt;
&lt;p&gt;Bw-Tree的结构会在某些操作下进行改变，以维护其性质。结构改变的操作仍然是无锁的。&lt;/p&gt;
&lt;p&gt;为了方便理解，我们假设结构改变的写操作不是并发的。&lt;/p&gt;
&lt;h3 id="_4"&gt;节点分裂&lt;/h3&gt;
&lt;p&gt;当某线程发现Bw-Tree中某个节点的大小超出了系统设定的阈值后，在执行完其预定的任务后，就会触发节点的分裂操作。&lt;/p&gt;
&lt;p&gt;节点分裂分为两步执行，每一步都是原子的：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;子节点分裂&lt;/li&gt;
&lt;li&gt;子节点更新后，向上更新父节点&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="_5"&gt;子节点分裂&lt;/h4&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-13/53138696.jpg"&gt;&lt;/p&gt;
&lt;p&gt;上图是Bw-Tree中的一部分，现在我们想分裂&lt;code&gt;PQ&lt;/code&gt;节点为&lt;code&gt;P&lt;/code&gt;和&lt;code&gt;Q&lt;/code&gt;两个子节点。即大于某个值&lt;code&gt;KP&lt;/code&gt;的数据全部迁移到新节点&lt;code&gt;Q&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;节点分裂的操作如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先拷贝Q中的数据到一个新的数据页&lt;code&gt;Q'&lt;/code&gt;，这一步并不会影响到其它的线程。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-13/52526691.jpg"&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;在P节点，使用CAS操作，添加分裂的信息Δ，标明该节点已经分裂，其中包含着&lt;code&gt;KP&lt;/code&gt;的信息，所以当查询的Key大于&lt;code&gt;KP&lt;/code&gt;时，会跳转到新节点&lt;code&gt;Q'&lt;/code&gt;进行查询。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-13/7152787.jpg"&gt;&lt;/p&gt;
&lt;h4 id="_6"&gt;父节点更新&lt;/h4&gt;
&lt;p&gt;同样，父节点的更新仍然是采用增量修改的模式。&lt;/p&gt;
&lt;p&gt;我们在父节点使用CAS操作添加一条修改增量（index term delta record）。当查询请求落在&lt;code&gt;Q&lt;/code&gt;节点的范围内时，会直接跳转到&lt;code&gt;Q'&lt;/code&gt;节点。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-13/29669418.jpg"&gt;&lt;/p&gt;
&lt;h4 id="_7"&gt;更新合并&lt;/h4&gt;
&lt;p&gt;使用增量更新可以减少数据更新、节点分裂时的时间开销，从而避免失败的分裂操作（failed splits）。&lt;/p&gt;
&lt;p&gt;但是最终，我们仍会将产生的更新增量合并成一条完整的记录，以避免过多的空间浪费和指针跳转。&lt;/p&gt;
&lt;h3 id="_8"&gt;子节点合并&lt;/h3&gt;
&lt;p&gt;在Bw-Tree数据减少时，我们为了避免过多的指针跳转，需要进行节点合并。节点合并比节点分裂复杂一点，所以需要一系列的原子操作来进行。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-14/37353459.jpg"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;删除节点&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;删除节点时使用标记删除，仍然是CAS操作，添加一个删除增量（remove node delta）到&lt;code&gt;Q&lt;/code&gt;。之后所有的读写请求全部转发到其左兄弟&lt;code&gt;P&lt;/code&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里有个猜测，在Q中原有的数据仍然是要到Q节点进行访问的。论文里没有说，通过常识推断一下应该如此。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-14/79837579.jpg"&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;合并子节点&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在&lt;code&gt;P&lt;/code&gt;节点之前用CAS操作添加合并增量（node merge delta）。合并增量将&lt;code&gt;P&lt;/code&gt;节点和&lt;code&gt;Q&lt;/code&gt;节点从逻辑上合为一个，并且负责转发读写请求。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-14/81902381.jpg"&gt;&lt;/p&gt;
&lt;h4 id="_9"&gt;父节点更新&lt;/h4&gt;
&lt;p&gt;这个就非常简单，就是CAS操作在父节点标记删除&lt;code&gt;Q&lt;/code&gt;节点的Key即可。&lt;/p&gt;
&lt;h3 id="_10"&gt;序列化结构修改&lt;/h3&gt;
&lt;p&gt;上面的Bw-Tree结构修改的实现都基于一个假设：数据库的同步机制会处理好数据更新冲突问题。&lt;/p&gt;
&lt;p&gt;同步机制包括数据库系统的锁管理器（lock manager）、事务管理组件（transactional component）；或者是采用弃疗方案，允许随机交叉写。&lt;/p&gt;
&lt;p&gt;但是在Bw-Tree内部，我们需要序列化树的结构修改（俗称排队）。当一个SMO操作遇到了未完成的SMO操作时，当前线程会等待之前的SMO操作完成后再继续当前操作。&lt;/p&gt;
&lt;p&gt;这样的方案可能会形成一个“SMO栈”，但是这种场景比较少见，实现起来也比较简单。&lt;/p&gt;
&lt;h2 id="_11"&gt;缓存管理&lt;/h2&gt;
&lt;p&gt;缓存层负责内存与SSD磁盘之间的读、写回以及换页操作。缓存层为Bw-Tree层提供了逻辑页的抽象。&lt;/p&gt;
&lt;p&gt;Bw-Tree使用PID访问逻辑页，当逻辑页位于磁盘中时，缓存层先把页读取到内存中，再使用CAS操作将PID指针从磁盘偏移量指向内存偏移量。&lt;/p&gt;
&lt;h3 id="lsn"&gt;预写日志协议与日志序列号（LSN）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;日志序列号（LSN）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;插入或修改Bw-Tree的增量都会被打上日志序列号。日志序列号由事务子系统产生。&lt;/p&gt;
&lt;p&gt;在页的刷写增量（flush delta）中，记录着最后被刷入（flush）磁盘的日志序列号。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事务日志协调&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;事务子系统维护着一个“最大写入日志序列号”（End of Stable Log, ESL）。事务子系统通过ESL来限制数据管理子系统的持久化进度，也就是说，数据管理子系统只能持久化事务号小于ESL的事务。这保证了预写日志协议的因果性。&lt;/p&gt;
&lt;p&gt;数据管理子系统通过向事务子系统反馈最后刷写的事务序号以提供反馈。当事务子系统想要向前移动“事务重做指针”（Redo-Scan-Start-Point, RSSP）时，会向事务子系统发送请求。当事务序号大于RSSP，且小于ESL的所以事务全部刷写到磁盘之后，数据管理子系统会向事务子系统发送ACK信号。最后事务子系统向前移动RSSP，已经落盘的事务信息抛弃。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bw-Tree的结构修改&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们将Bw-Tree的结构修改（SMO）封装成为一个系统事务。由于Bw-Tree的结构修改是无锁的，所以会有多个线程操作同一页的情况。&lt;/p&gt;
&lt;p&gt;将SMO视做事务，允许我们并发的执行SMO操作，当且仅当某一个SMO操作“胜出”时，才将事务提交。&lt;/p&gt;
&lt;h3 id="lss"&gt;将页写回日志式存储（LSS）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;页封装（Page Marshalling）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们如果要将页写回LSS，首先要先逻辑页转化成线性顺序存储的结构，便于我们将其存储到磁盘。&lt;/p&gt;
&lt;p&gt;然后我们要将页的状态设定为“锁定”（captured），以防止后续的修改破坏预写日志协议。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增量刷写（Incremental Flushing）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当刷写页面时，缓存管理器只会刷写ESL之前的数据记录。这样的好处有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;减少磁盘的使用&lt;/li&gt;
&lt;li&gt;避免产生过多的磁盘垃圾&lt;/li&gt;
&lt;li&gt;避免SSD的写入放大开销&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;刷写操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用双Buffer进行磁盘刷写，可以避免线程等待IO操作。&lt;/p&gt;
&lt;p&gt;在刷写操作完成之后，我们会更新mapping table，将页指针改变成磁盘的偏移量。并将内存中的页换出。&lt;/p&gt;
&lt;p&gt;缓存管理器会监视系统内存的使用情况，如果内存不够用，就将一部分页从自动内存中换出。&lt;/p&gt;
&lt;h2 id="_12"&gt;性能&lt;/h2&gt;
&lt;h3 id="_13"&gt;我们的对手&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;BerkeleyDB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;性能良好的独立存储引擎。我们使用C语言实现版本，内置存储引擎为B-Tree。&lt;/p&gt;
&lt;p&gt;运行模式为性能较好的“无事务模式”，支持一写多读。&lt;/p&gt;
&lt;p&gt;在整个实验中，我们将BerkeleyDB的缓存开到足够大，全部使用主存进行存储与查询操作。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SkipList&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;无锁的跳表实现。&lt;/p&gt;
&lt;h3 id="_14"&gt;测试数据集&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;XBox Live     &lt;br&gt;
网游数据。Key的平均大小是94Bytes，Value的平均大小是1.2K。读写比大概是7.5: 1&lt;/li&gt;
&lt;li&gt;商业数据库的备份流   &lt;br&gt;
总共有27M数据块，去重后有12M。读写比为2.2：1，Key是20Bytes的SHA1哈希值，Value是44Bytes的元信息。&lt;/li&gt;
&lt;li&gt;综合KV数据     &lt;br&gt;
8Bytes整数Key，8Bytes整数Value。读写比从5：1。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_15"&gt;比赛项目&lt;/h3&gt;
&lt;h4 id="_16"&gt;增量链长度阈值对性能的影响&lt;/h4&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-17/40340311.jpg"&gt;&lt;/p&gt;
&lt;p&gt;增量链长度阈值影响触发页合并（consolidation）的频率。从图中我们做出如下推测：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;增量链长度较短时，读写性能好，但页合并开销大&lt;/li&gt;
&lt;li&gt;增量链长度转长时，读写开销大，页合并开销小&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;系统的整体性能就在这两个因素下面取一个平衡。&lt;/p&gt;
&lt;h4 id="_17"&gt;无锁环境下的更新失败&lt;/h4&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-17/63409936.jpg"&gt;&lt;/p&gt;
&lt;p&gt;数据中我们可以看出，Bw-Tree写入失败（Failed Updates）是非常少的。但是“综合”数据集的“页拆分失败”和“页合并失败”明显高于其它数据集。&lt;/p&gt;
&lt;p&gt;这是因为“综合”数据集中的数据都比较小，更新起来比较快，所以会导致比较多的线程竞争。&lt;/p&gt;
&lt;h4 id="b-tree"&gt;与传统B-Tree的比较&lt;/h4&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-17/63409936.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Bw-Tree明显胜出，其原因有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Bw-Tree是无锁的，所以并发程度更高&lt;/li&gt;
&lt;li&gt;Bw-Tree对CPU cache更加友好&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="bw-tree_3"&gt;Bw-Tree与无锁跳表比较&lt;/h4&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-17/63409936.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Bw-Tree仍然明显胜出，其原因归于Bw-Tree更友好使用了CPU cache。&lt;/p&gt;
&lt;h4 id="_18"&gt;缓存性能&lt;/h4&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-12-17/63354469.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Bw-Tree的优势有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;与跳表相比不需要过多的指针跳转&lt;/li&gt;
&lt;li&gt;内存使用更加高效&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="201026"&gt;后续（201026）&lt;/h2&gt;
&lt;p&gt;到了新组之后，发现了一个使用BW-Tree的存储引擎。不过已经即将废弃了（挥手&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;特指Redis的一些主要功能&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;tree-based数据结构的一个例子就是图书馆。图书馆用A-Z代表大类，然后使用数字代表小类，最后加上一个数字确定这本书的书号。      &lt;br&gt;
图书馆藏书的顺序是按照书号的顺序进行排序的。所以我们在查找一本书的时候，可以使用特定的书号，利用其中的层次信息查找某一本书，也可以根据某一个书号范围进行查找一系列连续的书。      &lt;br&gt;
如果还弄不明白的话，可以使用&lt;a href="http://www.ztflh.com/"&gt;中国图书馆分类法网站&lt;/a&gt;加深一下理解。&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;图片来源：&lt;a href="https://en.wikipedia.org/wiki/B%2B_tree"&gt;Wikipedia&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Blog"/><category term="bw-tree"/><category term="azure"/><category term="storage"/><category term="b-tree"/></entry><entry><title>Windows Azure Storage Made Simple</title><link href="https://wizmann.top/azure-storage-made-simple.html" rel="alternate"/><published>2017-10-11T21:12:15+08:00</published><updated>2017-10-11T21:12:15+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2017-10-11:/azure-storage-made-simple.html</id><summary type="html">&lt;h2 id="_1"&gt;加机器就是一把梭&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;没有什么问题是加一千台机器解决不了的，如果有，就再加一千台。   &lt;br&gt;
 —— 《21天精通分布式系统》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;分布式系统在设计之初，是为了解 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;加机器就是一把梭&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;没有什么问题是加一千台机器解决不了的，如果有，就再加一千台。   &lt;br&gt;
 —— 《21天精通分布式系统》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;分布式系统在设计之初，是为了解决单机系统的可用性和可扩展性问题的。&lt;/p&gt;
&lt;p&gt;举个例子，单机系统就是雇一个小弟替你干活，但是这个小弟不太靠谱，偶尔泡个病号不上班，偶尔工作太多一个人干不过来。&lt;/p&gt;
&lt;p&gt;分布式系统就是雇一群小弟帮你干活，偶尔有一两个小弟泡病号，我们会有富裕的人力顶上，工作太多我们可以继续拉新的小弟入伙，美滋滋。&lt;/p&gt;
&lt;p&gt;这个比喻很好的描述了单机系统和分布式系统之间的关系。所以一种可能的分布式系统就是这个样子的：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-9-25/28278606.jpg"&gt;&lt;/p&gt;
&lt;p&gt;我们将相同功能的服务器组成一个整体，通过一个load balancer对外提供服务。&lt;/p&gt;
&lt;p&gt;这样的系统初步解决了我们的问题，在面对可扩展性和可用性的问题时，我们会：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;容量不足就加机器&lt;/li&gt;
&lt;li&gt;单机挂掉了就把流量调度到其它的节点上&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不过单纯的加机器并不能完全满足我们的需要。对于CPU密集型的服务，增加副本数可以有效的均摊计算压力，但是对于存储密集型的服务，我们需要增加分库逻辑才能有效的增加系统的计算能力。&lt;/p&gt;
&lt;p&gt;例如我们有100G的数据，但是数据库的容量最多只支持50G。这样无论怎么样增加副本都不能解决问题。如果我们将100G的数据均分，存储在两个50G的分库上，我们就可以支持单机系统容纳不了的数据了。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-9-22/14141171.jpg"&gt;&lt;/p&gt;
&lt;p&gt;我们还可以把多个这样的分布式子系统组合起来，就可以组成一个小有规模的分布式系统了。现在我们在使用的一些服务，仍在使用这种模型。&lt;/p&gt;
&lt;p&gt;上面分布式模型虽然有效，但是引入了一个严重的问题：因为节点之间是隔离的，并且只能通过消息传递进行通信与协调，所以基本无法完全保证副本之间保持一致的内部状态。&lt;/p&gt;
&lt;p&gt;这就是所谓的一致性问题。&lt;/p&gt;
&lt;h2 id="_2"&gt;补充一点理论知识&lt;/h2&gt;
&lt;h3 id="cap"&gt;CAP理论&lt;/h3&gt;
&lt;p&gt;CAP理论指的是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;一个分布式系统不可能同时满足一致性（Consistency）、可用性（Availability）和分区容错性（Partition tolerance）这三个基本要求，最多只能同时满足其中的两项。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CAP理论由Eric Brewer在2000年首次提出，并且2年后被Seth Gilbert和Nancy Lynch从理论上证明这个理论。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一致性是指数据的多个副本之间保持一致的特性；&lt;/li&gt;
&lt;li&gt;可用性是指系统的服务必须一直处于可用的状态;&lt;/li&gt;
&lt;li&gt;而分区容错性是指系统在遭遇任何网络分区故障的时候仍然能够保证对外提供满足一致性和可用性的服务，除非是整个网络环境都发生了故障;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;抛开一致性问题不谈，“可用性”和“分区容错性”从某种意义上讲是一个分布式系统的“标配”：单机和网络连接并不可靠，从一堆不可靠的硬件上层建立一个不可靠的系统并没有任何意义。&lt;/p&gt;
&lt;p&gt;所以一致性常常被牺牲，来保证分布式系统的可用性和分区容错性。&lt;/p&gt;
&lt;h3 id="paxos"&gt;Paxos算法&lt;/h3&gt;
&lt;p&gt;Paxos是Leslie Lamport在1990年提出的一种基于消息传递且具有高度容错性的一致性算法。&lt;/p&gt;
&lt;p&gt;Paxos解决的问题是如何在一个可能发生上述异常的分布式系统中，快速且正确地在集群内部对某个数据的值达成一致，并且保证不论发生任何异常，都不会破坏整个系统的一致性。&lt;/p&gt;
&lt;p&gt;Paxos的描述和证明有一些复杂，这里不做展开。简单来说，就是系统中的各个节点使用类似于选举投票的算法来达成一致，选举过程中会有短暂的数据不可用中间状态。&lt;/p&gt;
&lt;h2 id="_3"&gt;“我最讨厌我想做的事情做不成”&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;在分布式环境中，一致性是指数据在多个副本之间是否能够保持一致的特性。在一致性的需求下，当一个系统在数据一致的状态下执行更新操作后，应该保证系统的数据仍然处于一致的状态。    &lt;br&gt;
—— 《从Paxos到ZooKeeper》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;无数的理论和实践证明，解决分布式系统的一致性问题是非常困难的。从最直观上来说，我们找不到两片一样的树叶，也找不到两台状态完全一致的分布式节点。&lt;/p&gt;
&lt;p&gt;但是前人的智慧是无穷的，我们仍然有以下几种方案来保证数据的一致性：&lt;/p&gt;
&lt;h3 id="2pc-and-3pc"&gt;2PC and 3PC&lt;/h3&gt;
&lt;p&gt;2PC（Two-phase Commit，两阶段提交）是用来保证分布式系统一致性的一个协议。其流程可以由这个例子来表示：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;PM（协调者）: 我要加个需求！（阶段1，提交事务请求）     &lt;br&gt;
Dev1（参与者）：你加吧    &lt;br&gt;
Dev2（参与者）：你加吧  &lt;br&gt;
PM（协调者）：我真加了！（阶段2，执行事务提交）   &lt;br&gt;
Dev1（参与者）：加完了  &lt;br&gt;
Dev2（参与者）：加完了    &lt;/p&gt;
&lt;p&gt;注：PM和Dev是程序员老梗而已。各个职业只是分工不同，本质上都是为人民服务。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;整个流程看起来很美好，但是我们会遇到如下问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;同步阻塞    &lt;br&gt;
在提交过程中，系统需要等待所有参与者的响应，所以系统整体处于一种阻塞状态，影响效率。&lt;/li&gt;
&lt;li&gt;单点问题   &lt;br&gt;
协调者是系统的单点，如果当掉，整个系统就处于不可用状态。&lt;/li&gt;
&lt;li&gt;数据不一致    &lt;br&gt;
一个数据一致性协议会导致数据不一致，确实是非常讽刺的事情。在执行事务提交阶段，如果协调者与参与者的通信中断，可能会导致数据的不一致：&lt;ul&gt;
&lt;li&gt;当协调者发往部分参与者的Commit消息丢失，没有收到Commit的参与者会因为超时而认为这次请求失败而进行回滚&lt;/li&gt;
&lt;li&gt;当参与者发往协调者的ACK消息丢失，协调者会认为这次请求失败，但是参与者确实已经Commit了数据&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;3PC（Three-phace Commit，三阶段提交）是2PC协议的改进版，将整个请求分为三部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事务询问&lt;/li&gt;
&lt;li&gt;预提交&lt;/li&gt;
&lt;li&gt;执行提交&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样的改进减少了同步阻塞的粒度，但是仍然没有解决单点问题和数据不一致的问题。所以2PC和3PC都不是非常理想的数据一致性协议。&lt;/p&gt;
&lt;h3 id="paxos_1"&gt;Paxos&lt;/h3&gt;
&lt;p&gt;上文中我们提到Paxos是一种被数学证明过的，具有高度容错性的一致性算法。但是其流程复杂，通信次数较多，并且在提案未被选中之前不能保证数据的可用性。&lt;/p&gt;
&lt;p&gt;所以Paxos的应用场景多为命名服务、配置管理、分布式锁等轻量级但是而又非常核心的服务，从而扬长避短，更好的为人民服务，~~更好的反三俗~~。。&lt;/p&gt;
&lt;h3 id="quorum-like-algorithm-amazon-dynamo"&gt;Quorum-like Algorithm (Amazon Dynamo)&lt;/h3&gt;
&lt;p&gt;对于分布式系统的一致性，最直观的解决方案就是在修改节点状态时，将修改广播到所有节点上。这样从理论上讲，就可以保持节点的一致性了。&lt;/p&gt;
&lt;p&gt;但是在现实工程当中，广播修改是最不可靠的方案，因为通信可能失败，节点可能失效，我们的修改很有可能不会同步到所有的节点上（假设每个节点的可靠性为99.9%，那么10个节点同时可靠概率只有99%，100个节点同时可靠的概率为90%）。&lt;/p&gt;
&lt;p&gt;不过，让所有节点都保持完全一致虽然很完美，但是其付出的代价也许是现有 的系统难以承受的。Amazon Dynamo使用了一种类似选举的算法来保证数据的一致性。&lt;/p&gt;
&lt;p&gt;设我们有N个节点，我们再指定两个数R和W，使得 R + W &amp;gt; N。在写入数据的时候，我们同时向N个节点写入，当有W个（及以上）节点写入成功，就向客户端返回成功；在读取的时候，我们向R个节点请求数据，此时一定会读到刚刚写入新数据的节点，然后我们将最新的数据返回给用户。&lt;/p&gt;
&lt;p&gt;不过这种设计并不完善，当出现网络错误或者大规模节点失效的时候，数据一致性就很难保证了。&lt;/p&gt;
&lt;p&gt;我称这种一致性模型为 —— “尽力一致性”。&lt;/p&gt;
&lt;h3 id="event-stream-for-eventual-consistency-apache-kafka"&gt;Event Stream for Eventual Consistency (Apache Kafka)&lt;/h3&gt;
&lt;p&gt;从Dynamo的经验中我们可以看出，直接将状态的修改广播到不同的节点是不可靠的。那么我们有没有办法解决这个问题呢？&lt;/p&gt;
&lt;p&gt;Apache Kafka使用了类似“预写式日志”的方法来保证一致性。当状态修改请求到来时，先写入一条公共的数据流，这条数据流往往是持久化到磁盘的。然后不同的节点再访问数据流，执行同样的状态修改请求，保证节点状态的一致性。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-9-27/17974300.jpg"&gt;&lt;/p&gt;
&lt;p&gt;这种设计的缺陷是虽然最终所有节点都会依次执行相同的命令，但是节点执行命令的速度有快有慢，所以在瞬时会有不一致的情况。&lt;/p&gt;
&lt;p&gt;这种一致性模型被称为 —— “最终一致性”。&lt;/p&gt;
&lt;h2 id="windows-azure-storage"&gt;主角登场：Windows Azure Storage&lt;/h2&gt;
&lt;p&gt;Windows Azure Storage（以下简称WAS）采用了多种一致性算法，在提供较高性能服务的同时，来努力保证存储系统的CAP性质。&lt;/p&gt;
&lt;p&gt;其中WAS使用了一些创新性的算法，不过我们还是先从它的整体架构谈起。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows Azure Storage的架构&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-9-19/98830090.jpg"&gt;&lt;/p&gt;
&lt;p&gt;WAS从架构上分为三层，分别是前端（FE Layer），分区层（Partition Layer）和数据流层（Stream Layer）。这三层从功能上各有分工，但是又分别解耦，可以部署在不同的机器上。&lt;/p&gt;
&lt;p&gt;下面我们自底向上的讨论一下各层之间的功能与联系。&lt;/p&gt;
&lt;h2 id="was-"&gt;WAS - 数据流层&lt;/h2&gt;
&lt;p&gt;数据流包含着各种数据操作，操作包含插入、修改、删除等基本操作，“流”则可以看做是一条无限长的队列。&lt;/p&gt;
&lt;h3 id="_4"&gt;为什么要使用流结构？&lt;/h3&gt;
&lt;p&gt;为什么要用流结构呢，原因非常简单，因为流中的操作都是有序的，否则会造成不确定的结果。&lt;/p&gt;
&lt;p&gt;例如我们现在有三个操作：&lt;/p&gt;
&lt;p&gt;操作1：插入值x=1   &lt;br&gt;
操作2：修改该值为x=2   &lt;br&gt;
操作3：修改该值为x=5&lt;/p&gt;
&lt;p&gt;如果操作是按照顺序来做的话，那么我们获得的值为x=5。但是如果我们将操作2和操作3调换之后，那么我们获得的值为x=2；如果我们将操作1放置在操作2或操作3之后，我们就在修改一个不存在的值，这势必会造成错误。&lt;/p&gt;
&lt;p&gt;所以，数据流的有序性保证了操作的“回放一致性”，也就是说，相同的数据流应用在不同的机器上，获得的最终状态是一致的。&lt;/p&gt;
&lt;p&gt;同时，由于HDD的顺序读写性能优于随机读写性能。使用流数据结构可以将写入请求顺序化，追加写入磁盘，在廉价的硬件上获得最好的性能。&lt;/p&gt;
&lt;h5 id="hddssd"&gt;科普时间：HDD与SSD&lt;/h5&gt;
&lt;p&gt;&lt;img alt="image" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-10-10/63227271.jpg"&gt;&lt;/p&gt;
&lt;p&gt;HDD指的是Hard Disk Drive，又称Spinning Disk，是计算机使用的一种以磁性碟片存储数据的一种非易失性存储设备（人话就是：断电后不丢数据）。数据存储在同心圆磁道上，工作时碟片会旋转（和CD机一样），磁头会移动到相应的磁道上进行数据的读写（CD机用的是光头）。所以，顺序读写时，HDD的性能会比随机读写要好，因为随机读写带来的大量磁盘寻址会让磁头不断移动，从而拖慢性能。&lt;/p&gt;
&lt;p&gt;与此同时，由于碟片内弧的旋转&lt;strong&gt;线速度&lt;/strong&gt;要小于外弧，所以外弧的读写性能会优于内弧。          &lt;/p&gt;
&lt;p&gt;SSD指的是Solid State Disk，即固态硬盘，也是一种常见的非易失性存储设备。其使用闪存芯片来存储数据。由于其并不像HDD一样需要物理上移动磁头来进行寻址，在顺序写入与HDD或略强于HDD磁盘的同时，随机写入性能要远远强于HDD（这就是为什么我们装电脑都喜欢把系统装到SSD盘上）。          &lt;/p&gt;
&lt;p&gt;但是SSD在成本和质量上弱于HDD磁盘。1TB的SSD的价格约为400刀，而1TB的HHD价格仅为80~100刀（2017年10月&lt;a href="https://pcpartpicker.com/trends/internal-hard-drive/"&gt;数据&lt;/a&gt;）；SSD有写入次数的限制，当闪存芯片损坏时，会影响SSD的性能。相比而言，HDD的技术的性能更稳定，技术更为成熟，质量会更好一些。&lt;/p&gt;
&lt;h3 id="_5"&gt;数据流的一致性算法&lt;/h3&gt;
&lt;p&gt;因为要保证可用性，所以数据流必须要是多机的，而多机系统就要面临一致性问题。WAS提出了一种“链式提交”方法来保证了分布式数据流的一致性。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-10-7/32688212.jpg"&gt;&lt;/p&gt;
&lt;p&gt;与之前提到的分布式一致性的多机并行的算法不同，WAS在数据流层采用了一种“链式”的提交算法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当副本1接受到数据后，会首先将数据持久化到磁盘，之后再将相同的请求转发给副本2；&lt;/li&gt;
&lt;li&gt;副本2获得数据后，持久化到磁盘，再请请求转发给副本3；&lt;/li&gt;
&lt;li&gt;副本3将数据成功持久化后，返回ACK；&lt;/li&gt;
&lt;li&gt;副本2接收到副本3的ACK消息后，同样返回ACK；&lt;/li&gt;
&lt;li&gt;副本1接收到副本2的ACK消息后，向请求方返回ACK。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这样做的好处是，当数据请求返回ACK后，一定有三个（或以上，根据系统的参数而定）副本同时写入并持久化这条请求。此时三个副本一定是“强一致”的。&lt;/p&gt;
&lt;p&gt;不过，如果链式提交当中有任何一个环节出现了问题，比如机器失效、网络超时等，那么我们就要面临数据不一致的情况。WAS为了解决这个问题，引入了被称为“封存”的机制。&lt;/p&gt;
&lt;h3 id="sealing"&gt;封存（sealing）机制&lt;/h3&gt;
&lt;p&gt;上文说到，数据流是一个无限长的队列，只能在尾部追加写入。所以我们如果想要存储这条数据流，就势必要把这条数据流分为多个节，并把它们分别存储在不同的机器上。否则数据流的大小就要受限于单机的存储容量，这并不是我们想要看到的。&lt;/p&gt;
&lt;p&gt;又由于数据流的尾部追加写入特性，所以数据流被分为多个节之后，只有最后一个节是可读写的，其它的所有节都是只读的。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-10-7/46032879.jpg"&gt;&lt;/p&gt;
&lt;p&gt;我们将把可读可追加的数据流转化为只读的数据流的操作称为“封存”。&lt;/p&gt;
&lt;p&gt;封存的作用之一，就是在数据流的一节过大的时候，停止写入该节，使得数据节的大小可控。&lt;/p&gt;
&lt;p&gt;第二个作用，是上面我们提到的，在“链式提交”失败的时候，我们会将所有的数据流副本封存，封存的时候取所有副本的数据的交集。这样就能排除因为写入失败而不一致的数据。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-9-12/93804080.jpg"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;此时有同学会问，如果我们已经成功的写入了三个副本，但是由于网络原因并没能向请求方返回ACK。请求方会认为这段数据写入失败。但是我们在封存的时候，仍然会将这部分数据封存在数据节中。这种情况怎么处理呢？  &lt;br&gt;
这个问题后面会有解答，请耐心阅读哦~&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="_6"&gt;数据流层的架构&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-10-8/29641653.jpg"&gt;&lt;/p&gt;
&lt;p&gt;在前面的文章里，没有提到“数据流管理器”（Stream Manager，简称SM）这个角色。这个角色在整个数据流层扮演了一个很重要的角色。&lt;/p&gt;
&lt;p&gt;SM是由一个小型集群使用paxos选举出来的master节点，其它节点备用。SM只用来管理整个数据流的状态，并不负责具体的读写操作。&lt;/p&gt;
&lt;p&gt;SM的主要功能有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;统计节点状态&lt;/li&gt;
&lt;li&gt;监控节点健康状况&lt;/li&gt;
&lt;li&gt;负载均衡&lt;/li&gt;
&lt;li&gt;封存、创建新的数据节&lt;/li&gt;
&lt;li&gt;备份与垃圾回收&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;SM管理着一批存储着数据节的节点（Extent Node，简称EN），这些节点存储着数据流中的节。这些节点相互通信，以完成提交、备份等功能。&lt;/p&gt;
&lt;p&gt;EN节点中采用了预写入日志。每一次写入操作，EN会并发的&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;追加写入日志文件，并将新数据写入内存缓存&lt;/li&gt;
&lt;li&gt;写入持久化存储&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当二者有一个完成，就返回成功标记。这样做的好处是，由于HDD追加写入的性能非常好并且稳定，所以步骤1的响应时间是稳定的并且可以估计的。保证了系统整体的响应时间不出现大的颠簸。&lt;/p&gt;
&lt;h2 id="was-_1"&gt;WAS - 分区层&lt;/h2&gt;
&lt;p&gt;分区层为我们提供了一个被称为“对象表”（Object Table）的抽象。对象表提供了插入、更新、删除功能。&lt;/p&gt;
&lt;p&gt;为了提供容量支持，一个对象表会被划分为多个分区（这就是“分区层”名字的来源）。分区之间相互独立，不会互相影响。&lt;/p&gt;
&lt;p&gt;对象表构建在数据流层之上。但是从直观上来讲，表结构和流结构是完全不同的，那么分区层是如何将表存储在数据流层的呢？&lt;/p&gt;
&lt;h3 id="lsm-treelog-structed-merge-tree"&gt;LSM Tree（Log-Structed Merge-Tree）&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;段子：   &lt;br&gt;
一个学生背着满书包的书进入图书馆，叮叮叮，图书馆的报警器响了，学生赶紧把书从书包倒出来，准备一本一本的验证，看是哪本书有问题。    &lt;br&gt;
一旁扫地的阿姨看不下去了，过来把书分成了两挪，先检查第一挪，叮叮叮，报警器响了，说明这一挪有问题，又把这一挪分成两挪，先检查其中一挪，要是哪一挪响了，就把这一挪继续分成两挪，继续检查，不到三回合，大妈就把有问题的哪本书找出来了。   &lt;br&gt;
大妈用鄙视的眼神看着那学生，仿佛在说连O（n）跟O（log n）都分不清楚。 &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们上文中提到，HDD磁盘可以在较低成本下提供很好的追加写入性能，但是对于随机读写的性能不佳。&lt;/p&gt;
&lt;p&gt;但是对于表结构来说，必然涉及到大量的随机读写。因为输入数据就像打乱过的扑克牌，很难保证规律性；而我们又要把特定的输入数据放到特定的行上，所以数据的写入位置必然是随机的。所以，直接在磁盘中存储表结构是非常低效的。&lt;/p&gt;
&lt;p&gt;那么LSM Tree是怎么解决问题的呢？&lt;/p&gt;
&lt;p&gt;首先我们把已有的数据根据key进行排序，存储在磁盘中，标记第0代。所有写入磁盘的数据都是有序的、只读的。&lt;/p&gt;
&lt;p&gt;当有新的数据写入时，我们首先将其缓存在内存中。当数据达到一个阈值时，我们将内存中的数据进行排序，并写入磁盘。这一部分数据被标记为第1代。&lt;/p&gt;
&lt;p&gt;之后的数据依次类推，被标记为第2代，第3代&amp;hellip;第n代。代数越高，表示数据越新。并且代数高的数据在逻辑上可以覆盖代数低的数据。&lt;/p&gt;
&lt;p&gt;在查询时，我们首先检索内存中的缓存数据，如果没有找到，就依次从第n代的数据查询到第0代。如果仍然没有找到，就返回未找到。由于所有的查询都使用二分查找，效率较高。同时我们还可以使用[布隆过滤器][6]，快速判定一个key是否在LSM Tree中。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;细心的同学会发现，按照上面描述的算法，LSM Tree的代数会无限膨胀下去，最终导致非常差的的检索效果。在论文中没有明确提到LSM Tree的调教参数，但是我猜测其代数不会太多。并且在冗余数据过多时，会进行垃圾回收，保证检索的效率。    &lt;br&gt;
同时这也提醒我们在使用WAS的时候，尽量不要向某一个或某一些连续的分区连续写入大量数据，否则会导致分区层的性能退化。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="_7"&gt;分区层使用的数据流&lt;/h3&gt;
&lt;p&gt;分区层使用数据流来保存LSM Tree，使用顺序写入代替随机写入以获得性能提升，这条流被称为“行数据流”（Row Data Stream）。&lt;/p&gt;
&lt;p&gt;与此同时，分区层还使用了“二进制数据流”（Blob Data Stream）来保存二进制数据。以及“提交日志流”（Commit Log Stream）来持久化预写入日志。&lt;/p&gt;
&lt;p&gt;分区层向数据流层写入时，只有当数据流层返回ACK后，才认为写入成功。所以，在数据流层写入成功，但未能返回ACK时，虽然数据流层保留了数据，但是分区层并不能访问这部分数据，我们就在分区层保证了数据的正确性。&lt;/p&gt;
&lt;h3 id="_8"&gt;分区层的一致性保证&lt;/h3&gt;
&lt;p&gt;分区层的持久化信息依赖于数据流层，所以如果分区层使用在线多副本，就会遇到节点状态不一致的问题。也就是说，虽然不同的节点加载了相同的数据，但是加载速度有快有慢，很难保证节点之间以一个同样的状态对外服务。同时，在线多副本的写入会引入竞态，如果再加锁，就会大大的影响系统的效率。&lt;/p&gt;
&lt;p&gt;那么WAS是怎么解决这个问题的呢？&lt;/p&gt;
&lt;p&gt;答：不能保证一致性就不要一致性。&lt;/p&gt;
&lt;p&gt;这样的不要一致性并不是放任节点间的状态不同步，而是每一个分区只使用一个在线服务节点。对于唯一一个节点来说，一致性就是不存在的。（是不是非常暴力）&lt;/p&gt;
&lt;p&gt;所以，在同一时间只有一台机器对外提供服务（读+写）。其它的副本是在线备份，在对外提供服务的机器在计划内下线或意外当掉时，就会启用另一台副本对外提供服务。当然这也会造成一致性问题，所以这里牺牲了一点可用性，也就是在旧节点下线后，新节点必须加载完所有的数据才可以对外提供服务。中间的一段时间这个分区是不可用的。&lt;/p&gt;
&lt;h3 id="_9"&gt;分区层的架构&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-10-10/51400577.jpg"&gt;&lt;/p&gt;
&lt;p&gt;图中的PS指的就是上文提到的分区服务，每个PS维护着对象表的一个分区，其持久化信息都储存在数据流层上。&lt;/p&gt;
&lt;p&gt;PM（Partition Manager）也是使用paxos算法选举出来的master节点，用来管理分区服务的负载均衡、灾备等操作。&lt;/p&gt;
&lt;p&gt;Lock Service用来对分区节点进行选举，选出的唯一master节点对外提供服务。&lt;/p&gt;
&lt;p&gt;Partion Map Table用来存储与检索分区所对应的节点。&lt;/p&gt;
&lt;h2 id="was-_2"&gt;WAS - 前端层&lt;/h2&gt;
&lt;p&gt;前端层只是薄薄的一层REST API封装，并没有什么其它特殊功能。这里一笔带过。&lt;/p&gt;
&lt;h2 id="cap_1"&gt;战胜CAP理论？你他娘的真是个天才！&lt;/h2&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-9-20/10049124.jpg"&gt;&lt;/p&gt;
&lt;p&gt;WAS宣称自己战胜了CAP理论，提供了高可用性和强一致性。WAS能做到这点主要是因为数据流层设计的好。&lt;/p&gt;
&lt;p&gt;数据流层使用了只追加写的数据模型，加上链式提交提供的高一致性，所以能应对节点失效（可用性）和网络失效（分区容错性）的故障。&lt;/p&gt;
&lt;p&gt;数据流层之上的分区层利用了其特性，很容易的实现了高可用性和分区容错性。同时，又由于其使用单点向外提供服务，所以一致性也有了保障。&lt;/p&gt;
&lt;p&gt;所以WAS宣称自己战胜了CAP理论，也不是没有道理。但是个人感觉WAS在分区层的单点设定，是以牺牲可用性（A）换取一致性（C）的一种妥协，只是由于机器故障并非多发，触发问题的机率比较小。&lt;/p&gt;
&lt;h2 id="_10"&gt;写在后面&lt;/h2&gt;
&lt;p&gt;本文是《Windows Azure Storage: A Highly Available Cloud Storage Service with Strong Consistency》一文的读后感，删节了一部分不容易理解的细节。想要更详尽的理解WAS的设计思想，请阅读论文原文以及官方文档。一切内容和理解上的冲突，以原文和官方文档为准。&lt;/p&gt;
&lt;p&gt;撰写本文时，我使用Atreus2tap迷之小键盘，在学习前人经验教训的同时，重新学习了打字。&lt;/p&gt;
&lt;p&gt;小键盘的好处是便携，以及避免手指移动带来的劳损。缺点是需要精心设计并练习大量的组合键，同时成套的键帽真是不好买。&lt;/p&gt;
&lt;p&gt;上一张图。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-10-10/71011744.jpg"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;听说用这种奇怪键盘的人都注孤了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_11"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://wetest.qq.com/lab/view/105.html"&gt;分布式系统设计的求生之路&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://waylau.com/talk-about-distributed-system/"&gt;用大白话聊聊分布式系统&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://book.douban.com/subject/26292004/"&gt;《从Paxos到Zookeeper》&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf"&gt;Dynamo: Amazon’s Highly Available Key-value Store&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="Microsoft"/><category term="Azure"/><category term="WAS"/><category term="分布式系统"/><category term="CAP"/><category term="Consistency"/><category term="一致性"/></entry><entry><title>STUP - the Implementation (3)</title><link href="https://wizmann.top/stup-3.html" rel="alternate"/><published>2017-05-08T22:15:58+08:00</published><updated>2017-05-08T22:15:58+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2017-05-08:/stup-3.html</id><summary type="html">&lt;h2 id="throughput-and-window-size"&gt;throughput and window size&lt;/h2&gt;
&lt;p&gt;The wisdom of STUP protocol is all about the window size. The throughput of a TCP communication is limited by two windows: the congestion window and the receive window. The congestion window can determine how many bytes that can be send a simple piece of time …&lt;/p&gt;</summary><content type="html">&lt;h2 id="throughput-and-window-size"&gt;throughput and window size&lt;/h2&gt;
&lt;p&gt;The wisdom of STUP protocol is all about the window size. The throughput of a TCP communication is limited by two windows: the congestion window and the receive window. The congestion window can determine how many bytes that can be send a simple piece of time, and the receive window indicates the capacity of the receiver to process data.&lt;/p&gt;
&lt;p&gt;Both windows influence the throughput of our connection. As the size of receive window is already set after 3-way handshake process, the congestion window is the critical influence. But why?&lt;/p&gt;
&lt;p&gt;TCP use congestion control to achieve high performance (really?) and avoid congestion collapse. But here in STUP, we have different situations.&lt;/p&gt;
&lt;p&gt;Firstly, we need real high performance. We don&amp;rsquo;t want the window size cut into half when there is a lost / timeout packet, which is very normal in our &amp;ldquo;long thin pipe&amp;rdquo;. Secondly, STUP is not a protocol for general usage, by the initial  design, it should be used in an exclusive, non-production environment. So we don&amp;rsquo;t need to care about our neighbors, we can just use up a reserved, reasonable bandwidth.&lt;/p&gt;
&lt;p&gt;However, be aware of the number in &lt;code&gt;Config.py&lt;/code&gt;. Our router was down once because of a wrong configuration. :)&lt;/p&gt;
&lt;h2 id="other-mechanisms-and-algorithms-in-stup"&gt;other mechanisms and algorithms in STUP&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Keep Alive&lt;/li&gt;
&lt;li&gt;Nagle algorithm&lt;/li&gt;
&lt;li&gt;Piggybacking&lt;/li&gt;
&lt;li&gt;Fast retransmission&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These features are copied from TCP protocol and absolutely a cliché to have a discuss here. If you have any problem about these, just look it up in Wikipedia.&lt;/p&gt;
&lt;h2 id="twisted-twisted-framework"&gt;twisted Twisted Framework&lt;/h2&gt;
&lt;p&gt;STUP protocol takes me about a whole year to do the development work (and it&amp;rsquo;s not finished yet). But for more than half of the time, I was struggling with the Twisted framework. For people who want to learn more about Twisted Framework, you can read the &lt;a href="http://twistedmatrix.com/trac/wiki/Documentation"&gt;official manual&lt;/a&gt; or look through &lt;a href="/twisted-defer-and-deferredqueue.html"&gt;this blog&lt;/a&gt; for a quick start.&lt;/p&gt;
&lt;p&gt;What a pun!&lt;/p&gt;
&lt;h2 id="future-of-stup"&gt;future of STUP&lt;/h2&gt;
&lt;p&gt;Since STUP protocol is written in Python, one of the main problem is the performance. As a result, I&amp;rsquo;m planning to rewrite this with C++ (and golang, perhaps) to gain a better performance. I call it: STUPP (STUP in cpp).&lt;/p&gt;
&lt;p&gt;In STUPP, several features are to be added:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Selective ACK&lt;/li&gt;
&lt;li&gt;Monotonic strictly increasing sequence number to prevent replay attacks&lt;/li&gt;
&lt;li&gt;Multiple socks5 connections share a single STUP connection&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="STUP"/><category term="TCP"/><category term="UDP"/><category term="networking"/><category term="protocol"/></entry><entry><title>STUP - Packet Structure and State Machine (2)</title><link href="https://wizmann.top/stup-2.html" rel="alternate"/><published>2017-05-04T00:53:03+08:00</published><updated>2017-05-04T00:53:03+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2017-05-04:/stup-2.html</id><summary type="html">&lt;h2 id="stup-packet-structure"&gt;STUP Packet Structure&lt;/h2&gt;
&lt;h3 id="brief-introduction-of-tcp-udp-packet-structure"&gt;Brief Introduction of TCP &amp;amp; UDP Packet Structure&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-4-24/73808256-file_1493006773118_a335.png"&gt;&lt;/p&gt;
&lt;p&gt;STUP pretend itself as a protocol at the Transmission Layer, but actually it&amp;rsquo;s absolutely an Application Layer protocol. So before we start, I&amp;rsquo;d like to recall some knowledge of two important Transmission Layer protocol: TCP &amp;amp; UDP.&lt;/p&gt;
&lt;p&gt;It is …&lt;/p&gt;</summary><content type="html">&lt;h2 id="stup-packet-structure"&gt;STUP Packet Structure&lt;/h2&gt;
&lt;h3 id="brief-introduction-of-tcp-udp-packet-structure"&gt;Brief Introduction of TCP &amp;amp; UDP Packet Structure&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-4-24/73808256-file_1493006773118_a335.png"&gt;&lt;/p&gt;
&lt;p&gt;STUP pretend itself as a protocol at the Transmission Layer, but actually it&amp;rsquo;s absolutely an Application Layer protocol. So before we start, I&amp;rsquo;d like to recall some knowledge of two important Transmission Layer protocol: TCP &amp;amp; UDP.&lt;/p&gt;
&lt;p&gt;It is well known that TCP is a &amp;ldquo;connection-oriented&amp;rdquo;, &amp;ldquo;reliable&amp;rdquo;, &amp;ldquo;ordered&amp;rdquo;. To make an analogy (a little bit inappropriate), TCP is like a phone call (good cell signal strength):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;you are keeping a connection&lt;/li&gt;
&lt;li&gt;your words and sentences are well-received and well-ordered&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As a result, each TCP packet has a unique and ordered sequence number, and your partner has to reply an &amp;ldquo;ACK&amp;rdquo; (short of &amp;ldquo;ACKnowledgement&amp;rdquo;) when it receive a packet. And it has to keep a connection and control the flow, a lot of control header is added to the header, so as the &amp;ldquo;window size&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;In a word, TCP is a heavy-weight protocol which offers high reliability. But the performance is highly depend on the network condition.&lt;/p&gt;
&lt;p&gt;UDP is on the other way around, it&amp;rsquo;s &amp;ldquo;connectionless&amp;rdquo;, &amp;ldquo;unreliable&amp;rdquo; and &amp;ldquo;unordered&amp;rdquo;. To make another analogy, UDP is like a SMS message:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;there is no connection&lt;/li&gt;
&lt;li&gt;there is no guarantee that your partner will receive the message&lt;/li&gt;
&lt;li&gt;there is no guarantee of the order of messages, espiecially on a bad network&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;UDP is a lightweight protocol who doesn&amp;rsquo;t care about the connection and reliability, it just does it best to serve. And, of course, the performance is better than TCP.&lt;/p&gt;
&lt;h3 id="stup-packet-structure-why"&gt;STUP Packet Structure &amp;amp; Why?&lt;/h3&gt;
&lt;p&gt;As I mentioned before, the only problem for me in TCP is the flow control. But that part is deep in the kernel, it is unnecessarily complicated to hack the kernel, a user application is good enough here for me.&lt;/p&gt;
&lt;p&gt;So, I build STUP over UDP to make everything simple. Firstly, UDP is a commonly used and well-known protocol, we can take advantages of existing infrastructure, framwork and libs. Secondly, UDP is lightweighted protocol, the overhead to build a new protocol over it is almost nothing. &lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-5-2/38201062-file_1493708415970_dc40.png"&gt;&lt;/p&gt;
&lt;p&gt;The chart above shows STUP packet structure. And the bits in green are plain-text and the others in red are encrypted.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Random IV (16bits): plain text, used to assemble the encrypt key&lt;/li&gt;
&lt;li&gt;Version (3 bits): for compatibility use, currently is &amp;ldquo;000&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Nonce (6 bits): indicate the length of random trail padding data, used for data confusion&lt;/li&gt;
&lt;li&gt;URG (1 bit): urgent flag, internal use&lt;/li&gt;
&lt;li&gt;LIV (1 bit): keep-alive flag&lt;/li&gt;
&lt;li&gt;ACK (1 bit): acknowledgement flag&lt;/li&gt;
&lt;li&gt;PSH (1 bit): temporarily prohibit nagle algorithm for this packet&lt;/li&gt;
&lt;li&gt;RST (1 bit): reset flag&lt;/li&gt;
&lt;li&gt;SYN (1 bit): sync flag&lt;/li&gt;
&lt;li&gt;FIN (1 bit): finalize flag&lt;/li&gt;
&lt;li&gt;Seq number (32 bits): same as TCP&lt;/li&gt;
&lt;li&gt;Ack number (32 bits): same as TCP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The structure of STUP packet is quite similar to TCP packet, because we are imitating TCP, literally.&lt;/p&gt;
&lt;h3 id="data-obfuscation-of-stup-packets"&gt;Data obfuscation of STUP packets&lt;/h3&gt;
&lt;p&gt;One of the most important part of STUP protocol is obfuscation. We try to hide our intend of the network traffic to bypass the G*W. Except obfuscate the data, we also need to hide some patterns, for example, the handshack process, ack mechanism, etc.&lt;/p&gt;
&lt;p&gt;The first step is encryption, of course. It can help us the hide the feature inside data, for example, the pattern of a HTTP request can be easily detected. We use AES-ECB to encrypt the content of our packet.&lt;/p&gt;
&lt;p&gt;But why AES-ECB? There are a lot of saying on the internet that AES-ECB sucks, because it leaks plaintext data patterns. &lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-5-2/19737252-file_1493708926479_15add.png"&gt;&lt;/p&gt;
&lt;p&gt;It is because we ecrypt the STUP packet &lt;strong&gt;as a whole&lt;/strong&gt;, it means there is no way to get the sequence number to order the packets before we decrypt it. As a solution, we add a &amp;ldquo;random IV&amp;rdquo; as a plain text in the STUP header. So the key to ecrypt is a combination of 48 bits pre-defined key and 16 bits random key. It might lead to a risk of small key space, but actually it&amp;rsquo;s more than enough to keep out traffic safe as we are not VIP who worth a brute force hacking.&lt;/p&gt;
&lt;p&gt;And still, there is another problem that we can&amp;rsquo;t hide the length information of our packet with a symmetric encryption. The solution is to append random padding bytes at the tail of every packets for data obfuscation, and use the &lt;code&gt;nonce&lt;/code&gt; field to mark the length of the paddings, then enrypt it. When receiver get the packets, firstly decrypt the packet, then drop the useless padding bytes and get the real data.&lt;/p&gt;
&lt;h2 id="stup-state-machine"&gt;STUP State Machine&lt;/h2&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-4-24/70104484-file_1493025532333_338c.png"&gt;&lt;/p&gt;
&lt;p&gt;STUP state machine is also a simplify TCP state machine. And, in essence, they behave exactly the same. &lt;/p&gt;
&lt;h2 id="whats-next"&gt;What&amp;rsquo;s next?&lt;/h2&gt;
&lt;p&gt;In next blog (maybe the last one for STUP series), we will talk about some details about the implementation, and future plan for this protocol.&lt;/p&gt;</content><category term="Blog"/><category term="STUP"/><category term="TCP"/><category term="UDP"/><category term="networking"/><category term="protocol"/></entry><entry><title>STUP - another (stupid) TCP over UDP protocol (1)</title><link href="https://wizmann.top/stup-1.html" rel="alternate"/><published>2017-04-20T23:17:45+08:00</published><updated>2017-04-20T23:17:45+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2017-04-20:/stup-1.html</id><summary type="html">&lt;h2 id="what-is-stup"&gt;What is STUP?&lt;/h2&gt;
&lt;p&gt;STUP is the abbreviation of &amp;ldquo;Speeded/Secure Tcp-like Udp Protocol&amp;rdquo;, which means that it&amp;rsquo;s another TCP over UDP protocol.&lt;/p&gt;
&lt;p&gt;Why TCP over UDP?&lt;/p&gt;
&lt;p&gt;TCP is a network protocol for general purpose, and it&amp;rsquo;s one of the most commonly used internet protocol on this planet. It …&lt;/p&gt;</summary><content type="html">&lt;h2 id="what-is-stup"&gt;What is STUP?&lt;/h2&gt;
&lt;p&gt;STUP is the abbreviation of &amp;ldquo;Speeded/Secure Tcp-like Udp Protocol&amp;rdquo;, which means that it&amp;rsquo;s another TCP over UDP protocol.&lt;/p&gt;
&lt;p&gt;Why TCP over UDP?&lt;/p&gt;
&lt;p&gt;TCP is a network protocol for general purpose, and it&amp;rsquo;s one of the most commonly used internet protocol on this planet. It is reliable, ordered and well optimized with decades of efforts.&lt;/p&gt;
&lt;p&gt;But, there&amp;rsquo;s plenty of reasons to replace that protocol for my scenario.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;~~Firstly, create my own network protocol is something geeky-nerdy, yep, suits me perfectly.~~&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Firstly, TCP is not &amp;ldquo;secure&amp;rdquo; (enough to bypass G*W).  &lt;br&gt;
Of course, it&amp;rsquo;s not TCP&amp;rsquo;s fault, because the security job is for the application layer. But &amp;ldquo;大清自有国情在&amp;rdquo;, we are in urgent need for a secure network protocol to obfuscate our network packet to bypass the firewall to get access to the &amp;ldquo;free internet&amp;rdquo;.   &lt;br&gt;
Shado*socks is one of the commonly used &amp;ldquo;secure&amp;rdquo; network protocol which based on socks5 proxy protocol and TCP.  But still, it has its own problem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Secondly, TCP performs badly on harsh transmission condition.   &lt;br&gt;
Because of the flow control and congestion control, the sliding window of TCP will be cut into half when packet is lost or timeout, which is very common on a harsh network connection as the jitter is inevitable.   &lt;br&gt;
It&amp;rsquo;s understandble that TCP has to negotiate the sliding window size with zero knowledge to achieve intra- and inter- protocol fairness, and make a stable network. But for us, we may have enough knowledge for our network, and we may not have too many connections at the same time, so here we don&amp;rsquo;t need control, we need speed. We come up with our own control mechanism - no control is best the control.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-it-works"&gt;How it works?&lt;/h2&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-4-20/98249887-file_1492687602713_f658.png"&gt;&lt;/p&gt;
&lt;p&gt;Our local application behavess like a socks5 proxy client, and send its data to a local adapter which will translate socks5 packet into STUP packet. The adapter doesn&amp;rsquo;t need to understand the &amp;ldquo;meaning&amp;rdquo; of socks5 packets, it just take it as a byte-flow, then encapsulate the data into the STUP packet.&lt;/p&gt;
&lt;p&gt;The local STUP client will encrypt the outgoing UDP packet. More precisely, the job of the encryption is to obfuscate the packet to bypass the detector of the G*W. We will talk about this later.&lt;/p&gt;
&lt;p&gt;Then the remote STUP protocol server received the encrypted packet, then it unpack the data and translate it back into the same byte-flow. After that, the socks5 server will get the message and retrieve what we want from the free internet.&lt;/p&gt;
&lt;p&gt;In a word, STUP procotol is a secure tunnel between the socks5 client and socks5 server. This design reduces the complexity of the whole system, and make it easy to implement.&lt;/p&gt;
&lt;h2 id="how-we-implement-it-big-picture"&gt;How we implement it? (Big picture)&lt;/h2&gt;
&lt;p&gt;We use Twisted framework to implement our protocol. The good parts of twisted is it hides the details of network programming and turn everything into events. But twisted is aptly named and it is really &amp;ldquo;twisted&amp;rdquo;, especially for the new comers.&lt;/p&gt;
&lt;p&gt;We implemented our simplfied &amp;ldquo;TCP stack&amp;rdquo; with fixed-size sliding window, nagle algorithm, retry mechanism, encrypting, etc. But with the help of Python, one of my favorite programming language &amp;hellip; it&amp;rsquo;s still a complex task to do. And it takes me a year to make it work.&lt;/p&gt;
&lt;p&gt;I say thankya.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-4-20/89638264-file_1492701304939_10484.png"&gt;&lt;/p&gt;</content><category term="Blog"/><category term="STUP"/><category term="TCP"/><category term="UDP"/><category term="networking"/><category term="protocol"/></entry><entry><title>WorkflowyMd Release Note</title><link href="https://wizmann.top/workflowymd.html" rel="alternate"/><published>2017-01-26T21:07:28+08:00</published><updated>2017-01-26T21:07:28+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2017-01-26:/workflowymd.html</id><summary type="html">&lt;h2 id="what-is-it"&gt;What is it?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve writen several workflowy enhance plugins by UserScript. The very first one is show the full content of the note of a bullet. The second one is to show images under the bullet. Then I worked on the background image to make a more colorful workflowy …&lt;/p&gt;</summary><content type="html">&lt;h2 id="what-is-it"&gt;What is it?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve writen several workflowy enhance plugins by UserScript. The very first one is show the full content of the note of a bullet. The second one is to show images under the bullet. Then I worked on the background image to make a more colorful workflowy.&lt;/p&gt;
&lt;p&gt;Yeah, workflowy is a powerful tool for noting and orgainizing your knowledge. And it is &lt;strong&gt;FREE&lt;/strong&gt;! (Say thankee) And the only drawback of this tool is the text format. &lt;/p&gt;
&lt;p&gt;In the original version of workflowy (without any plugins), we can only add plain text as note for a bullet. It&amp;rsquo;s, of course, less expressive than the rich text notes which we&amp;rsquo;re used to. But now, WorkflowyMd solve that problem.&lt;/p&gt;
&lt;p&gt;WorkflowyMd is a suite of usersciprt and stylesheet to enhance the original workflowy with Markdown support. As we know, markdown is one of the most popular lightweight markup language which can create rich text from plain text. We can add headers, images, table, list in the notes, and the original plain text can be fully synced to the server of workflowy. &lt;/p&gt;
&lt;p&gt;Here follows the detail and usage of WorkflowyMd.&lt;/p&gt;
&lt;h2 id="markdown-support"&gt;Markdown support&lt;/h2&gt;
&lt;p&gt;You have to add &lt;code&gt;[md]&lt;/code&gt; tag at the end of the bullet to let the plugin render your markdown note. If you delete the tag, your note will return to the plain text note.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-1-26/48097654-file_1485411968675_15abe.gif"&gt;&lt;/p&gt;
&lt;h2 id="edit-mode"&gt;Edit mode&lt;/h2&gt;
&lt;p&gt;If you want to edit your markdown note. There is no need to type and delete the &lt;code&gt;[md]&lt;/code&gt; tag every time. Just double click on the note, the notes will toggle between the markdown style (read-only) and plain text style (editable).&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-1-26/59010877-file_1485412203554_8eea.gif"&gt;&lt;/p&gt;
&lt;h2 id="better-image-support"&gt;Better image support&lt;/h2&gt;
&lt;p&gt;There always one annoy stuff about the image - the size. Sometimes the image size is too large for the page, and some oter time we need an image with full size so we can see every details in the image.&lt;/p&gt;
&lt;p&gt;Workflowy solve the problem. The image will be displayed in the style &lt;code&gt;max-width: 20%&lt;/code&gt; by default. And on a double click, the image will scale to &lt;code&gt;max-width: 100%&lt;/code&gt; for us to show the details.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-1-26/95527913-file_1485412578590_104ab.gif"&gt;&lt;/p&gt;
&lt;h2 id="syntax-highlight"&gt;Syntax Highlight&lt;/h2&gt;
&lt;p&gt;This is the killer feature for this plugin. Syntax highlight! No more explain, let me show you!&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-1-26/104624-file_1485412763869_931a.gif"&gt;&lt;/p&gt;
&lt;h2 id="get-the-code"&gt;Get the code&lt;/h2&gt;
&lt;p&gt;JS: https://github.com/Wizmann/Utils/blob/master/UserScript/WorkflowyMd.js&lt;/p&gt;
&lt;p&gt;CSS: https://github.com/Wizmann/Utils/blob/master/UserScript/WorkflowyMd.css&lt;/p&gt;
&lt;p&gt;This plugin might conflict with my previous plugins, and I strongly recommand you to drop the previous versions.&lt;/p&gt;
&lt;p&gt;If there are bugs in the plguin, please feel free to contact me. (Or you can fix it yourself, it&amp;rsquo;s easy)&lt;/p&gt;
&lt;h2 id="thanks"&gt;Thanks&lt;/h2&gt;
&lt;p&gt;This work based on TamperMonkey and Stylish. These two are both commonly used Chrome extension which are easy to get in Chrome App Store. Also, &amp;ldquo;Markdown-it&amp;rdquo; is used here for render the markdown notes and &amp;ldquo;Highlight.js&amp;rdquo; is used to highlight the source code. And of course, thanks to jQuery to make everything simple.&lt;/p&gt;
&lt;p&gt;Have fun with workflowy and WorkflowyMd!&lt;/p&gt;
&lt;h2 id="special-thanks"&gt;Special Thanks&lt;/h2&gt;
&lt;p&gt;Special thanks to Bach and Glenn Gould. :)&lt;/p&gt;</content><category term="Blog"/><category term="workflowy"/><category term="userscript"/></entry><entry><title>Parallel patterns in C#</title><link href="https://wizmann.top/parallel-in-csharp.html" rel="alternate"/><published>2017-01-22T22:52:28+08:00</published><updated>2017-01-22T22:52:28+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2017-01-22:/parallel-in-csharp.html</id><summary type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;与C/C++所使用的，传统的基于线程的并行模式不同，C#实现了丰富的并发编程模型，其中以异步模型最为流行。&lt;/p&gt;
&lt;p&gt;本 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;与C/C++所使用的，传统的基于线程的并行模式不同，C#实现了丰富的并发编程模型，其中以异步模型最为流行。&lt;/p&gt;
&lt;p&gt;本文中我们重点讨论C#在发展过程中出现的几种异步编程模型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Async Programming Model（APM）&lt;/li&gt;
&lt;li&gt;Event-based Async Pattern (EAP)&lt;/li&gt;
&lt;li&gt;Task-based Async Pattern（TAP）&lt;/li&gt;
&lt;li&gt;async/await语法糖&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_2"&gt;异步编程入门&lt;/h2&gt;
&lt;p&gt;同步模式是最常见，也是最被人熟知的编程模型，每一个任务按顺序执行，前一个任务执行完之后才会执行下一个任务。&lt;/p&gt;
&lt;p&gt;异步编程和同步编程不同，程序的执行流程是由“事件”所驱动的。异步编程有两种实现方式，回调与future模式。&lt;/p&gt;
&lt;p&gt;回调函数在Javascript中被大量使用，相信大家也都不会陌生。但是大量的回调函数会让代码失去可读性，陷入“Callback hell”。&lt;/p&gt;
&lt;p&gt;Promise模式是回调函数的一种“包装”。我们使用一个占位符来表示“未来”将会产生的一个异步处理结果。&lt;/p&gt;
&lt;p&gt;这个占位符在不同的语言/框架里面有不同的名字，其定义也不尽相同：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Task - C#&lt;/li&gt;
&lt;li&gt;Deferred - Python Twisted&lt;/li&gt;
&lt;li&gt;Promise - Javascript&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在任务结束后，会触发绑定在这个占位符上定义的回调函数，继续预定义好的逻辑。&lt;/p&gt;
&lt;p&gt;举个例子，同步模型就是你：&lt;/p&gt;
&lt;p&gt;宅家想吃饭 -&amp;gt; 下楼买饭 -&amp;gt; 上楼 -&amp;gt; 吃饭 -&amp;gt; 打游戏看漂亮小姐姐。&lt;/p&gt;
&lt;p&gt;而异步模型呢，就是：&lt;/p&gt;
&lt;p&gt;宅家想吃饭 -&amp;gt; 手机叫外卖 -&amp;gt; 拿到了外卖定单（拿到占位符 或 注册回调）-&amp;gt; 打游戏看漂亮小姐姐 -&amp;gt; 外卖小哥把饭送上门（启动回调） -&amp;gt; 吃饭 -&amp;gt; 继续打游戏看漂亮小姐姐。&lt;/p&gt;
&lt;p&gt;虽然从上面看，异步模型比同步模型要复杂一些。但是它却节省了耗时的“上下楼买饭”的时间，让你可以分配更多的时间用来看漂亮小姐姐。这和我们写程序时的思路是一致的，节省动辄十几几十毫秒耗时的IO时间，将更多的时间用在CPU上。&lt;/p&gt;
&lt;h2 id="thread-based-parallel"&gt;Thread Based Parallel&lt;/h2&gt;
&lt;p&gt;基于线程的并发模型是比较传统的并发模型了，基本上所有的现代编程语言都会支持。C#中Thread的用法与Java类似，这里就不做展开。&lt;/p&gt;
&lt;p&gt;与此同时，C#还支持Thread pool，用来运行&amp;rdquo;long-running processor-bound tasks&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;直接操作线程也许是中年程序员的必修课，但是手动管理线程会给程序带来额外的负担。所以各种模型与框架应运而生，试图降低并发编程的复杂度。&lt;/p&gt;
&lt;h2 id="async-programming-model-apm"&gt;Async Programming Model (APM)&lt;/h2&gt;
&lt;p&gt;在我们熟悉的async/await语法糖出现之前，C#中使用APM来表示异步操作。虽然这是一种上古时期的回调模式语法，但是现在有很多库仍旧支持这种风格。如Azure Storage SDK中的&lt;code&gt;CloudTable.BeginExecute&lt;/code&gt;等一系列函数。&lt;/p&gt;
&lt;p&gt;下面是一个简单的使用APM模式的代码范例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Runtime.Remoting.Messaging&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Runtime.Remoting.Proxies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Threading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;ConsoleApplication6&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;delegate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;AsyncInvoke&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AsyncInvoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyCall&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BeginInvoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Main()&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsyncWaitHandle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Main() waiting...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Main() done&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;MyCall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;running...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;done&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;MyCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IAsyncResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AsyncResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AsyncInvoke&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsyncDelegate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;si&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EndInvoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;运行结果如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-1-19/26234044-file_1484828912411_150f3.gif"&gt;&lt;/p&gt;
&lt;p&gt;我们可以看到：&lt;br&gt;
1. 我们将&lt;code&gt;MyCall()&lt;/code&gt;“包装”在一个&lt;code&gt;delegate&lt;/code&gt;中，然后调用&lt;code&gt;BeginInvoke&lt;/code&gt;函数实现异步执行。这个delegate的执行不会阻塞main thread。&lt;br&gt;
2. 一个异步执行的&lt;code&gt;delegate&lt;/code&gt;可以有一个回调，这个回调在delegate执行完后被触发。&lt;br&gt;
3. 我们可以&amp;rdquo;long-polling&amp;rdquo;等待一个异步调用执行完。这里的“执行完”不包括条目2提到的回调（小心race condition！）。&lt;br&gt;
4. 异步执行的结果可以通过&lt;code&gt;delegate.EndInvoke(IAsyncResult)&lt;/code&gt;函数获取到异步调用的结果。&lt;br&gt;
5. 由条目3我们可以知道，在callback函数中获取异步调用的结果是最合适的。&lt;/p&gt;
&lt;p&gt;所以APM风格的代码写起来非常像javascript中的回调写法，如果逻辑复杂的话，维护起来会是一个大坑。&lt;/p&gt;
&lt;h2 id="event-asynchronous-pattern-eap"&gt;Event Asynchronous Pattern (EAP)&lt;/h2&gt;
&lt;p&gt;EAP是回调函数的另一种封装。&lt;/p&gt;
&lt;p&gt;我们来看下面的代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.ComponentModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Threading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;ConsoleApplication2&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;StringEventArgs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EventArgs&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Solution&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;event&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EventHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StringEventArgs&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_eventHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_eventHandler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Handle1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_eventHandler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Handle2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_eventHandler&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StringEventArgs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;123&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Handle1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StringEventArgs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Handle1 &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Handle2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StringEventArgs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Handle2 &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Solution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;sol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Done&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;运行结果如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/17-1-20/46892581-file_1484911655343_68ae.gif"&gt;&lt;/p&gt;
&lt;p&gt;我们可以看出，所有的函数都执行在同一个线程上。并且&lt;code&gt;Handle1&lt;/code&gt;和&lt;code&gt;Handle2&lt;/code&gt;顺序执行。&lt;/p&gt;
&lt;p&gt;在实际工程中，我们fire event的代码可以在不同的线程，之后&lt;code&gt;EventHandler&lt;/code&gt;，也就是callback函数会被调用。&lt;/p&gt;
&lt;p&gt;Event同时支持&lt;code&gt;BeginInvoke&lt;/code&gt;和&lt;code&gt;EndInvoke&lt;/code&gt;函数，也就意味着我们可以异步的fire相应的回调。但是注意此时我们只能注册唯一的回调，因为&lt;code&gt;BeginInvoke&lt;/code&gt;只能有一个目标回调（原理：在同一时间同一线程只能有一个函数调用）。&lt;/p&gt;
&lt;h2 id="task-asynchronous-pattern-tap"&gt;Task Asynchronous Pattern (TAP)&lt;/h2&gt;
&lt;p&gt;在.NET 4.0（现在已经到6.0了哦），C#引入了TPL，Task Parallel Library。Task的目标是统一C#中的不同异步编程风格。&lt;/p&gt;
&lt;p&gt;TPL中的Task非常像JS中的promise和twisted中的deferred，是“未来会完成的操作的结果”的占位符。&lt;/p&gt;
&lt;p&gt;我们来看一段简单代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Threading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;ConsoleApplication3&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Task start&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Task end&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsCompleted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Main(): Task is running...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Done&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这段代码我们前面提到的APM和EAP风格的代码有明显的不同，TAP更易读，并且保持了控制流的完整性。不像APM需要在&lt;code&gt;EndInvoke&lt;/code&gt;函数中获取返回值以及进行后续操作，也不像EAP一样需要根据不同的event声明不同的回调。&lt;/p&gt;
&lt;p&gt;Task也可能“串起来”，实现多级回调的机制。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;ConsoleApplication4&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContinueWith&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;antecedent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;antecedent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;antecedent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContinueWith&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;antecedent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;antecedent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;antecedent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContinueWith&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;antecedent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;antecedent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;antecedent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;当然我们还可以把回调写成一棵树状结构，然后一层一层的执行，不过生命是如此宝贵，我们并没有充分的理由要这么做。&lt;/p&gt;
&lt;h2 id="asyncawait"&gt;async/await语法糖&lt;/h2&gt;
&lt;p&gt;async/await语法糖在C# 5.0中被引入，其目的是为了避免回调带来的代码复杂度。就像Twisted中的&lt;code&gt;@inlineCallbacks&lt;/code&gt;一样，省去了defer复杂的回调链。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;await&lt;/code&gt;中有一个&amp;rdquo;wait&amp;rdquo;，说明这是一个“等待”操作。它等待的是相应的Task执行完成。&lt;/p&gt;
&lt;p&gt;我们来看一段代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;DumpWebPageAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;WebClient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;webClient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WebClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;webClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DownloadStringTaskAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;当代码执行到&lt;code&gt;await&lt;/code&gt;一行时，当前函数会主动放弃当前的控制流。当使用&lt;code&gt;await&lt;/code&gt;修饰的Task完成后，当前函数会从之前中断的地方继续执行。&lt;/p&gt;
&lt;p&gt;这样做的好处是我们可以写出和同步版本非常相似的异步代码，只需要在必须的地方加上&lt;code&gt;await&lt;/code&gt;关键字，提醒编译器这里是一个异步函数，需要额外的处理逻辑，但这一切都是对开发者透明的。&lt;/p&gt;
&lt;h3 id="asyncawait_1"&gt;async/await干了什么&lt;/h3&gt;
&lt;p&gt;想弄清楚async/await到底干了什么，首先我们要想明白线程到底是什么、干了什么。&lt;/p&gt;
&lt;p&gt;线程是进程内一条执行流的状态，其中包括了硬件状态（IP、Registers等）以及堆栈（栈上的局部变量和堆上的进程级内存）。那么如果我们想实现挂起/启动（Hibernating and Resuming），那么我们就要有一个机制来保存当前线程的运行状态。&lt;/p&gt;
&lt;p&gt;所以当你写下了async/await关键字后，编译器在后面帮助你生成了状态保存和恢复运行上下文的代码。&lt;/p&gt;
&lt;h3 id="asyncawait_2"&gt;async/await到底干了什么&lt;/h3&gt;
&lt;p&gt;想像我们有一个复杂的async函数，里面有很多个await调用，那就意味着这个函数中会有多次挂起/继续操作。同时我们还要维护这个函数的状态。如果我们是这个语法糖的设计者，我们会选择怎么样的手段来处理这个问题呢？&lt;/p&gt;
&lt;p&gt;是的，状态机。async/await避免了代码的碎片化，它的解决方案并不是消灭了回调函数和Continuation Tasks，而是使用工具（编译器）来帮助人类进行重复劳动。当async函数从挂起中恢复时，会调用&lt;code&gt;MoveNext&lt;/code&gt;函数（相信看过async函数那一长串的traceback的同学肯定对这个函数非常眼熟），&lt;code&gt;MoveNext&lt;/code&gt;函数会在async函数第一次被调用以及从挂起中恢复时被调用。状态机保存了当前函数的执行状态，当&lt;code&gt;MoveNext&lt;/code&gt;函数被调用时，会根据当前状态来判断接下来执行什么代码。&lt;/p&gt;
&lt;h3 id="asycnawaittmd"&gt;asycn/await到底TMD干了什么&lt;/h3&gt;
&lt;p&gt;由于async/awaic语法糖是在编译期才被翻译成相应的程序代码，所以我们只能使用IL反编译器来窥探编译器到底做了怎样的处理与优化。不过反编译器你懂得，生成的代码基本没法看，讲解起来也会非常晦涩。&lt;/p&gt;
&lt;p&gt;幸好在99%的情况下，我们并不需要知道async/await是怎样被展开的。如果你确实对这个问题感兴趣，可以参考这篇文章：&lt;a href="https://www.codeproject.com/Articles/535635/Async-Await-and-the-Generated-StateMachine"&gt;Async Await and the Generated StateMachine&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="_3"&gt;几个常见的坑&lt;/h2&gt;
&lt;h3 id="await"&gt;await 与 锁&lt;/h3&gt;
&lt;p&gt;由于await会中断当前函数在当前线程的执行流，并且可能在恢复时，被指派到另外的线程。所以对await加锁明显是多此一举的。并且如果操作不当，还会造成死锁。&lt;/p&gt;
&lt;p&gt;所以我们应该把await放到加锁的区域外。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Prepare for async operation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myNum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AlexsMethodAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Use result of async operation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="there-is-an-unfired-task-between-us"&gt;&amp;ldquo;There is an &amp;hellip; unfired Task between us&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;一个async函数如果返回的是Task，那么它返回的一定是一个hot task，即已经被启动了的Task。&lt;/p&gt;
&lt;p&gt;并且await只可能等待一个启动了的Task，否则await操作将会hang住，破坏程序既定的执行流。&lt;/p&gt;
&lt;h3 id="tpl-task-parallel-library"&gt;使用TPL (Task parallel library)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Async methods are synchronous util needed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果我们想同时执行几个异步操作，使用for来遍历执行可不是一个好主意。因为这样函数执行流仍然是顺序执行相应的函数。&lt;/p&gt;
&lt;p&gt;TPL提供了&lt;code&gt;WhenAll&lt;/code&gt;、&lt;code&gt;WhenAny&lt;/code&gt;等函数，让我们可以有弹性的并发执行Task。&lt;/p&gt;
&lt;p&gt;当然我们还可以使用PLINQ，不过这就是另外一个话题了。&lt;/p&gt;
&lt;h2 id="_4"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.codeproject.com/Articles/535635/Async-Await-and-the-Generated-StateMachine"&gt;Async Await and the Generated StateMachine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.stephencleary.com/2012/07/async-interop-with-iasyncresult.html"&gt;Async Interop with IAsyncResult&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://msdn.microsoft.com/en-us/library/wewwczdw(v=vs.110).aspx"&gt;Event-based Asynchronous Pattern Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.safaribooksonline.com/library/view/async-in-c/9781449337155/"&gt;Async in C# 5.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.safaribooksonline.com/library/view/essential-c-60/9780134176147/"&gt;Essential C# 6.0&lt;/a&gt; Cpt18&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="csharp"/><category term="parallel"/><category term="thread"/><category term="async"/></entry><entry><title>Twisted Defer and DeferredQueue</title><link href="https://wizmann.top/twisted-defer-and-deferredqueue.html" rel="alternate"/><published>2016-12-10T11:34:38+08:00</published><updated>2016-12-10T11:34:38+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2016-12-10:/twisted-defer-and-deferredqueue.html</id><summary type="html">&lt;h2 id="_1"&gt;写在最前面&lt;/h2&gt;
&lt;p&gt;这篇文章本来是想用英文写的，但是最近英文水平下降的和狗一样。还是怂一波吧。&lt;/p&gt;
&lt;h2 id="_2"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;最近在用Twisted库写一个诡异的项目，具体 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;写在最前面&lt;/h2&gt;
&lt;p&gt;这篇文章本来是想用英文写的，但是最近英文水平下降的和狗一样。还是怂一波吧。&lt;/p&gt;
&lt;h2 id="_2"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;最近在用Twisted库写一个诡异的项目，具体内容暂且不在这里讨论。在写的过程中，被Twisted里面的一个重要概念 —— defer，折腾的不行。最终通过阅读twisted的部分源码，以及与代码做斗争的丰富经验，最终算是解决了问题。&lt;/p&gt;
&lt;p&gt;本文算是使用twisted开发踩坑的一个小小总结，如果一切顺利，后面会有大菜。：）&lt;/p&gt;
&lt;h2 id="twisted"&gt;Twisted介绍&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Twisted is an event-driven networking engine written in Python.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Twisted是一个基于事件驱动的网络框架。那么什么是“事件驱动”呢？&lt;/p&gt;
&lt;p&gt;事件驱动指的是将事件与事件回调绑定起来，在程序运行时根据实时的事件触发相应的响应的一种机制。&lt;/p&gt;
&lt;p&gt;例如select/poll/epoll这些IO复用函数，在文件描述符（fd）可读/可写/出错时，会立即返回，由相应的处理函数来对新事件进行处理。事实上，twisted的事件驱动功能，正是由这些IO复用函数提供的。&lt;/p&gt;
&lt;p&gt;但与IO复用函数不同的是，twisted中的事件可以是“更高层次的事件”，即对网络的读/写/错等基础事件进行更进一步的封装。&lt;/p&gt;
&lt;p&gt;这里我们以&lt;code&gt;LineReceiver&lt;/code&gt;为例（&lt;a href="http://twistedmatrix.com/documents/current/api/twisted.protocols.basic.LineReceiver.html"&gt;API文档&lt;/a&gt;）。&lt;code&gt;LineReceiver&lt;/code&gt;是对传输层协议的二次封装，当我们读完一整行之后，就触发&lt;code&gt;lineReceived&lt;/code&gt;事件，对获取的数据进行处理。&lt;/p&gt;
&lt;p&gt;这种封装，将开发者与底层的网络交互隔离开来。利用这些“高级事件”，开发者可以将更多的精力放到程序本身逻辑的开发之中。&lt;/p&gt;
&lt;p&gt;还有一点，正如Python语言本身的一大优点一样，Twisted现成的协议实现的非常丰富，同时在工业界也较为广泛的使用。虽然赶不上golang这种“明星语言”，但是也还是可以“自成一派”，搞点事情。&lt;/p&gt;
&lt;h2 id="defer"&gt;Defer与回调&lt;/h2&gt;
&lt;p&gt;Twisted使用Defer来管理callback链，如果你写过js，就可能对被回调链（callback chains）所支配的恐惧记忆深刻。当然，Twisted的defer也并没有好到哪里去。（蛤！）&lt;/p&gt;
&lt;p&gt;Seriously，defer允许我们使用一般的顺序型编程模型来编写回调代码。我们只需要把函数按照顺序注册到defer当中，就可以完整的实现一个回调链了。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/public/16-12-9/90670835.jpg"&gt;&lt;/p&gt;
&lt;p&gt;本文不会对defer进行过多讲解，如果想要了解更多的话，可以参考twisted的&lt;a href="https://twistedmatrix.com/documents/current/core/howto/defer.html"&gt;官方文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;defer做为一个回调链的抽象，有一个非常重要的性质，就是你不fire它，它是不会调用它的callbacks的。正像俗话说的一样：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;事不说不知，木不钻不透，砂锅不打一辈子不漏&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;又有人说过（异步发卡）：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A: There&amp;rsquo;s something between us.   &lt;br&gt;
B: What is it?    &lt;br&gt;
A: An unfired defer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你想激活defer中的callbacks，就需要手动的fire它。那么什么时候来fire它呢？当然是在需要的时候啦。&lt;/p&gt;
&lt;h3 id="defer-txmongo"&gt;一个典型的defer使用场景 - txmongo&lt;/h3&gt;
&lt;p&gt;txmongo是一个异步的mongodb python sdk。而我们常用的pymongo库则是同步的，所有的请求都要同步等待数据库返回结果。&lt;/p&gt;
&lt;p&gt;由于是异步的sdk，所以在同一时间，txmongo会同时持有多个mongodb连接（连接池）。并且由于我们不能预测mongodb的响应时间，所以需要在收到mongodb响应后，启动相应的回调函数，以触发更高级别的消息事件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# txmongo/protocol.py#L368&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;handle_REPLY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response_to&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__deferreds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__deferreds&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response_to&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response_flags&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;REPLY_QUERY_FAILURE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# some error handling code&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;我们从这段代码中看出，当txmongo收到响应后，会先从&lt;code&gt;self.__deferreds&lt;/code&gt;字典中取出相应的defer，之后使用&lt;code&gt;request&lt;/code&gt;做为参数，启动defer中的callbacks，将查到的数据返回给调用者。&lt;/p&gt;
&lt;h3 id="defer_1"&gt;新手会遇到的defer坑 —— 测试&lt;/h3&gt;
&lt;p&gt;做为一个马上就要步入中年的程序员，我最大的一个优点就是不相信自己（汗）。所以在开发时会及时写单元测试来尽可能保证代码的正确性。于是在开发的很早就踩到了defer的坑，包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;测试hang住&lt;/li&gt;
&lt;li&gt;测试通过，但是报错&amp;rdquo;reactor was unclean&amp;rdquo;&lt;/li&gt;
&lt;li&gt;由于回调没有执行，测试挂掉&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;坑1比较好解决，defer没有callback，hang住了只能怪自己。不过查哪里hang住了会比较麻烦，最直接的方法是多打log，从log里很容易就知道哪里有问题。&lt;/p&gt;
&lt;p&gt;坑2和坑3都属于我们使用defer的姿势不对。defer是“延时”的，我们不能像调用函数一样的直接调用，测试代码需要defer执行完最后一个callback函数后再继续执行。那么我们需要把测试代码也写成callbacks，然后附在需要测试的defer后面吗？&lt;/p&gt;
&lt;p&gt;答案是否定的，twisted为我们提供了一个神奇的工具&lt;code&gt;@defer.inlineCallbacks&lt;/code&gt;。这个装饰器可以用于开发环境与测试环境。我们可以使用yield等待defer执行完成，并且可以获得defer的返回值。这类似于C#的async/await语法，使用起来非常方便。&lt;/p&gt;
&lt;p&gt;所以在我们的测试当中如果使用了defer，就需要将测试case使用&lt;code&gt;inlineCallbacks&lt;/code&gt;装饰起来，在等待defer时，需要使用yield语法，等待异步代码的执行。在case的最后，将不需要的defer cancel掉即可。&lt;/p&gt;
&lt;h2 id="deferredqueue"&gt;DeferredQueue与循环&lt;/h2&gt;
&lt;p&gt;Queue的一个重要用法就是循环。包括线程/进程通信的Queue，BFS中使用的Queue，都是需要循环读取数据。&lt;/p&gt;
&lt;p&gt;DeferredQueue是Twisted中通信的一个重要数据结构，其使用方法和一般的Queue从逻辑上是一样的，接口也只有两个：&lt;code&gt;put&lt;/code&gt;和&lt;code&gt;get&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;DeferredQueue之所以有一个Deferred前辍，是因为它的get函数返回的是一个defer。我们可以在这个defer上绑定callbacks，即有数据可读时，触发相应的回调函数。&lt;/p&gt;
&lt;p&gt;所以我们很容易就把代码写成了这样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeferredQueue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_and_print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_and_print&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_and_print&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;一眼看上去，这个代码没有什么问题，我们会循环的从队列中获取数据并打印。但实际上，这段代码有一个神奇的坑。&lt;/p&gt;
&lt;p&gt;说一下这个坑是怎么发现的吧，我把代码写的差不多之后，就想跑benchmark来测性能。然后发现CPython的性能一般，就想试试pypy。然后却怎么也得不到正确的结果，最后发现是因为DeferredQueue引发了递归过深的异常。但是为什么CPython没有这个问题呢。原因在于CPython的递归栈是按深度算的，而pypy的递归栈是按大小算的，但是这两个参数的标量是一样的，所以pypy的递归栈就远小于CPython的。这才暴露了这个问题。不过单纯的扩栈也是不合理的，因为我们很难估计极端情况，并且Python的递归性能非常差。&lt;/p&gt;
&lt;p&gt;感兴趣的同学可以去参考&lt;a href="https://github.com/twisted/twisted/blob/twisted-16.5.0/src/twisted/internet/defer.py#L1600"&gt;源码&lt;/a&gt;，这里就直接说结论了。当队列中有元素时，&lt;code&gt;q.get().addCallback(get_and_print)&lt;/code&gt;会直接调用&lt;code&gt;get_and_print&lt;/code&gt;函数本身，如果队列中的元素非常多，那么我们就有递归过深的危险了。&lt;/p&gt;
&lt;p&gt;解决方案也很简单，与其让Twisted把我们的循环写成递归，还不如我们自己实现Queue的循环。至于方法，看看DeferredQueue的内部实现就清楚了，然后我们就发现了另外一个坑。&lt;/p&gt;
&lt;h2 id="deferredqueue_1"&gt;DeferredQueue与性能&lt;/h2&gt;
&lt;p&gt;我啥都不说，就贴一行&lt;a href="https://github.com/twisted/twisted/blob/twisted-16.5.0/src/twisted/internet/defer.py#L1665"&gt;代码&lt;/a&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pending&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;您这就是在逗我。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/public/16-12-9/36902015.jpg"&gt;&lt;/p&gt;
&lt;p&gt;再贴个性能对比，使用&lt;code&gt;list.pop(0)&lt;/code&gt;弹出10^5个数据需要2.23s，而使用&lt;code&gt;deque.popleft()&lt;/code&gt;只需要0.12s。&lt;/p&gt;
&lt;p&gt;不要功能实现了就不管性能了嘛同学。&lt;/p&gt;</content><category term="Blog"/><category term="twisted"/><category term="defer"/><category term="async"/></entry><entry><title>Mosca源码阅读</title><link href="https://wizmann.top/mosca.html" rel="alternate"/><published>2016-11-11T22:04:13+08:00</published><updated>2016-11-11T22:04:13+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2016-11-11:/mosca.html</id><summary type="html">&lt;h2 id="_1"&gt;先在前面&lt;/h2&gt;
&lt;p&gt;最近心血来潮看了看一个比较有名的开源MQTT broker —— Mosca。不读不知道，读完才恍然大悟 —— 这是啥破玩意（哈哈）。&lt;/p&gt;
&lt;p&gt;由于我是nodejs的超级初学者 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;先在前面&lt;/h2&gt;
&lt;p&gt;最近心血来潮看了看一个比较有名的开源MQTT broker —— Mosca。不读不知道，读完才恍然大悟 —— 这是啥破玩意（哈哈）。&lt;/p&gt;
&lt;p&gt;由于我是nodejs的超级初学者，所以本文会比较浅显，并且只关注big picture，不陷入细节。&lt;/p&gt;
&lt;p&gt;这里先规定几个缩写，让后面行文时少打一点字：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MQ - MessageQueue&lt;/li&gt;
&lt;li&gt;Asco - Ascoltatori&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ascoltatori-"&gt;Ascoltatori - 听者&lt;/h2&gt;
&lt;p&gt;Ascoltatori是一个意大利语单词，翻译成英文就是listener。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里严重吐槽作者取名字的方式，mosca这种短小的外语单词我们是可以接受的，你说ascoltatori这么长的意大利语单词，你让我们怎么记。    &lt;br&gt;
差评，退款，邮费也要退！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Asco模块的作用是提供一个一致的MQ的抽象，供上层broker使用。&lt;/p&gt;
&lt;p&gt;这里我们只分析基于Redis的实现，原因是Redis我相对比较熟悉，功能也比较简单。&lt;/p&gt;
&lt;h3 id="_2"&gt;接口分析&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;RedisAscoltatore&lt;/code&gt;有三个半接口：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;subscribe&lt;/li&gt;
&lt;li&gt;unsubscribe&lt;/li&gt;
&lt;li&gt;publish&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;剩下的那半个是模块的构造函数。接下来我们分别分析接口的功能及其实现。&lt;/p&gt;
&lt;h3 id="subscribe"&gt;Subscribe接口&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;this._sub&lt;/code&gt;是&lt;code&gt;RedisAscoltatore&lt;/code&gt;用来subscribe的连接。首先我们要向MQ订阅指定的topic。&lt;/p&gt;
&lt;p&gt;之后我们要在本地维护一个&lt;code&gt;topic&lt;/code&gt;到&lt;code&gt;callback&lt;/code&gt;s的映射关系。因为Mosca是一个broker，需要将end user订阅的topic的内容完整的发送到用户那里去，每一个用户在Asco里，用一个callback函数来代表。&lt;/p&gt;
&lt;p&gt;用户可以订阅一个特定的topic，也可以使用一个pattern来订阅一系列的topic。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/public/16-11-10/27730251.jpg"&gt;&lt;/p&gt;
&lt;p&gt;从图中我们可以看出，右上方的client订阅了&lt;code&gt;h?llo&lt;/code&gt;（相当于regex中的&lt;code&gt;h.llo&lt;/code&gt;）。右下方的client订阅了&lt;code&gt;h[abcde]llo&lt;/code&gt;。而左边的client向&lt;code&gt;hello&lt;/code&gt; topic发布了一个消息。此时右边的两个client都收到了这条消息，其中pmessage代表这条消息是有pattern的，第二个参数代表了client订阅的pattern topic，而第三个参数代表了这条消息的实际topic，最后一个参数是消息的正文。&lt;/p&gt;
&lt;p&gt;所以我们在维护topic-client列表时，只需要维护pattern topic（没有pattern的topic可以视做只匹配当前topic的patter）。当有消息到来时，我们使用pattern topic映射到clients，之后再进行下一步操作。&lt;/p&gt;
&lt;p&gt;这里Asco使用了一个叫做&lt;a href="https://github.com/davedoesdev/qlobber"&gt;&lt;code&gt;qlobber&lt;/code&gt;&lt;/a&gt;的库，它使用Trie树对topic进行匹配。我们在上文已经说到，Asco是一个统一化的MQ抽象层，所以在不同的MQ中所使用的不同的pattern，我们都需要将其统一成同一种语法进行匹配。而qlobber，在Asco中被封装成&lt;code&gt;RedisAscoltatore&lt;/code&gt;，就是用来统一不同的语法的。&lt;/p&gt;
&lt;h3 id="unsubscribe"&gt;Unsubscribe接口&lt;/h3&gt;
&lt;p&gt;有订阅就有退订，这个接口与上面的是对应的关系。我们只需要将订阅的顺序反过来做一遍就可以了。这个函数相对简单，就不多说了。&lt;/p&gt;
&lt;h3 id="publish"&gt;Publish接口&lt;/h3&gt;
&lt;p&gt;这里的publish，代表是用户的publish的操作。用户数据在“去MQ特色化”之后，会经由&lt;code&gt;this._client&lt;/code&gt;发布到相应的redis服务。最后调用用户的callback。&lt;/p&gt;
&lt;p&gt;这里再吐一个槽，为啥订阅连接叫&lt;code&gt;this._sub&lt;/code&gt;，发布连接叫&lt;code&gt;this._client&lt;/code&gt;。难道你不造pub/sub才是真正的对应吗？&lt;/p&gt;
&lt;h3 id="_3"&gt;构造函数&lt;/h3&gt;
&lt;p&gt;构造函数虽然说是“半个接口”，但是代码量和重要性，却高于上面的接口。因为redis的pub/sub模型是单工的，需要两个连接才可以完成。所以两条连接需要单独初始化。&lt;/p&gt;
&lt;h4 id="this_startpub"&gt;this._startPub&lt;/h4&gt;
&lt;p&gt;我们先从简单的开始。&lt;/p&gt;
&lt;p&gt;这个太简单了，没的可说。就是拉一条电话线，成功了之后改一下状态。&lt;/p&gt;
&lt;p&gt;没了。&lt;/p&gt;
&lt;h4 id="this_startsub"&gt;this._startSub&lt;/h4&gt;
&lt;p&gt;这个比pub要复杂一点。首先，我们还是要拉一条到redis的电话线（连接）。之后注册消息到来时的回调。&lt;/p&gt;
&lt;p&gt;我们来看一看这个回调是怎样的流程。&lt;/p&gt;
&lt;p&gt;首先还是“去MQ特色化”，将Redis的pattern语法化归成Asco的内部语法。再通过pattern取出相应的callbacks，将消息通过callbacks传递给相应的用户。&lt;/p&gt;
&lt;p&gt;这里补充一下，&lt;code&gt;(sub, topic, payload)&lt;/code&gt;三个参数如果命名为&lt;code&gt;(pattern, topic, payload)&lt;/code&gt;其实会更清晰。&lt;/p&gt;
&lt;p&gt;这个类其实原理上并不复杂，但是由于其需要将不同MQ的pattern转换为统一的语法，所以在中间加了一层，导致复杂性的提升。如果我们只做一个专用的broker，代码其实可以写的更明朗的。&lt;/p&gt;
&lt;h2 id="mosca-"&gt;Mosca - 苍蝇&lt;/h2&gt;
&lt;p&gt;与Mosquito相对，Mosca是苍蝇的意思。Mosca是Asco的上层封装，与其一起组成了一个MQTT broker，与end user直接交互。&lt;/p&gt;
&lt;p&gt;MQ的单一职责是负责消息的发布/订阅，Mosca在其上添加了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在线离线状态检测&lt;/li&gt;
&lt;li&gt;离线消息的支持&lt;/li&gt;
&lt;li&gt;客户端持久化&lt;/li&gt;
&lt;li&gt;一些权限检测接口&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在这里，我们从Mosca的工作流程出发，主要关注离线消息和客户端持久化这两个broker中非常重要的特性。&lt;/p&gt;
&lt;h3 id="_4"&gt;持久化&lt;/h3&gt;
&lt;p&gt;这里我们还是只看Redis的实现。其实Redis并不是真正的持久化，不过who cares。&lt;/p&gt;
&lt;p&gt;这里的持久化就包括了离线消息和客户端持久化两个概念。&lt;/p&gt;
&lt;p&gt;离线消息使用&lt;code&gt;packet:{client_id}&lt;/code&gt;为key进行保存，当用户离线时，broker会将消息先保存在redis中，当用户重新上线时，就将保存好的消息一口气推送过去。&lt;/p&gt;
&lt;p&gt;客户端持久化稍微复杂一点。客户端在broker中的状态是其订阅的topic，一般情况下，broker会一直保存用户所订阅的topic，以便保存用户的离线信息。当broker掉电或重启时，我们需要从持久化层将用户的状态重新load到内存。此时，我们使用&lt;code&gt;client:sub:{client_id}&lt;/code&gt;为key进行保存。&lt;/p&gt;
&lt;h3 id="_5"&gt;整体工作流程&lt;/h3&gt;
&lt;p&gt;在Mosca启动时，先会注册一些事件，比如“用户登录”，“用户下线”，“用户订阅”等。这些消息由配置文件决定是否下发。&lt;/p&gt;
&lt;p&gt;这种设计是为了方便broker的scale out，我们可以在一个MQ上面部署多个broker，这些broker通过MQ的&lt;code&gt;$SYS&lt;/code&gt;信道进行通信。&lt;/p&gt;
&lt;p&gt;当Mosca启动完成后，我们像上面一样，重点关注broker的三个重要事件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;subscribe&lt;/li&gt;
&lt;li&gt;publish&lt;/li&gt;
&lt;li&gt;unsubscribe&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些事件理论上是Asco的封装，添加了权限控制接口、更复杂的事件，当然还有持久化的支持。例如&lt;code&gt;subscribe&lt;/code&gt;事件，除了调用Asco之外，还将用户的这次订阅记录在了持久层里。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;publish&lt;/code&gt;事件则是先将数据包存放在持久层，再调用Asco的publish函数。&lt;code&gt;unsubscribe&lt;/code&gt;也是同样的道理。&lt;/p&gt;
&lt;h3 id="_6"&gt;补一张结构图&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/public/16-11-11/55787779.jpg"&gt;&lt;/p&gt;
&lt;h3 id="mosca"&gt;Mosca的可扩展性&lt;/h3&gt;
&lt;p&gt;根据我浅薄的理解，Mosca是可以支持scale out的。也就是我们可以在同一个MQ（或同一个MQ抽象）上部署多个Mosca，以服务更多的用户。但是一个用户必须严格对应一个shard，否则会出现消息的重复。这个问题可以在Client端解决，但是不应该是一种常态，只应该在用户迁移或者比较大的系统变动的时候才出现。&lt;/p&gt;
&lt;p&gt;由于Mosca的持久化层是以Client为Key的，所以不支持多MQ的模式。MQ的扩展需要由MQ自己来完成，对外提供一个统一的抽象即可。不过这种功能，并不被所有MQ所支持。&lt;/p&gt;
&lt;h2 id="disclaimer"&gt;Disclaimer&lt;/h2&gt;
&lt;p&gt;真是nodejs小白以及MQ小白，上面说的哪里不对，请帮忙提出来。强烈建议不要以本文中的任何观点不加测试的应用到生产环境当中去。&lt;/p&gt;</content><category term="Blog"/><category term="mosca"/><category term="mq"/><category term="message queue"/></entry><entry><title>总结 - phxrpc代码阅读(8)</title><link href="https://wizmann.top/phxrpc-8.html" rel="alternate"/><published>2016-10-23T15:50:44+08:00</published><updated>2016-10-23T15:50:44+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2016-10-23:/phxrpc-8.html</id><summary type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;这应该是phxrpc代码阅读系列正文的最后一篇。通过阅读代码，发现了自己在知识上的若干不足。&lt;/p&gt;
&lt;p&gt;临渊羡鱼，不如退而结网。接下来可能会在网络编程 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;这应该是phxrpc代码阅读系列正文的最后一篇。通过阅读代码，发现了自己在知识上的若干不足。&lt;/p&gt;
&lt;p&gt;临渊羡鱼，不如退而结网。接下来可能会在网络编程方面再下一点工夫。请大家期待下一个系列吧。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;其实真没人读，我就是在骗自己。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="-"&gt;先补充一点 - 代码生成&lt;/h2&gt;
&lt;p&gt;protobuf并不包含RPC的实现，但是它可以声明rpc。客户端和服务端需要实现RPC接口，来实现通信。&lt;/p&gt;
&lt;p&gt;phxrpc使用proto文件来定义接口，然后解析并使用代码模板进行生成。&lt;/p&gt;
&lt;p&gt;这里我们不讨论代码生成的细节，因为pb实在太过流行，代码生成的方法也有不少的流派。并且用C++来做代码生成，真心不是我的菜。&lt;/p&gt;
&lt;p&gt;想了解更多，可以参考&lt;a href="http://codemacro.com/2014/08/31/protobuf-rpc/"&gt;这篇博客&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="-_1"&gt;工作流程 - 客户端&lt;/h2&gt;
&lt;p&gt;客户端与服务器的通信有如下的特点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;连接少&lt;/li&gt;
&lt;li&gt;负载少&lt;/li&gt;
&lt;li&gt;通信的主动方&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以，所有的网络交互相关的内容可以托管给网络库中的协程。每个协程主动运行一段时间后，主动放弃CPU时间，将控制权交还给主控制流的epoll。&lt;/p&gt;
&lt;p&gt;所以协程中不能有CPU密集的运算，幸好面对开发者，phxrpc并不暴露内部函数，而是将CPU密集的运算分配给工作线程来完成。&lt;/p&gt;
&lt;h2 id="-_2"&gt;工作流程 - 服务端&lt;/h2&gt;
&lt;p&gt;服务器的通信有以下的特点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;连接多&lt;/li&gt;
&lt;li&gt;负载多&lt;/li&gt;
&lt;li&gt;通信的被动方&lt;/li&gt;
&lt;li&gt;响应时间敏感&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这里说一下响应时间的问题，响应时间是和负载多对应的。客户端一般只负责发请求，其响应时间并不在整个系统中占主导地位，换句话说，客户端发请求是完全有主动权的。而服务端负责响应请求，需要经过CPU运算，或者有一些服务的级联或扇出操作，所以响应时间是不可控的。&lt;/p&gt;
&lt;p&gt;由上面我们可以了解到，服务器端肯定需要与客户端不同的策略来处理连接与响应。&lt;/p&gt;
&lt;p&gt;首先，一个独立的线程来&lt;strong&gt;同步&lt;/strong&gt;accept请求，这个线程大部分的时间都block在&lt;code&gt;accept()&lt;/code&gt;里，负载比较低。&lt;/p&gt;
&lt;p&gt;在accept到fd后，将其压入到调度器中。之后fd会hang在IO循环上，直到有请求到来。与此同时，协程会调度其它的fd。&lt;/p&gt;
&lt;p&gt;请求到来后，IO线程会把请求加入队列中，把自己从epoll调度中删除。之后就开始睡觉觉。睡醒了之后，发现响应没到碗里来，就shutdown连接。(我觉得这里应该加入重试，例如三次失败再断线)&lt;/p&gt;
&lt;p&gt;如果响应来了，先会调用一个激活fd的操作，将响应放到封装fd的结构体中，再将自己放回到epoll调度，最后顺手给epoll发一个信号。当fd可写时，再把响应返回给客户端。&lt;/p&gt;
&lt;p&gt;由于phxrpc使用的通信协议是HTTP，所以不需要考虑分包的问题。&lt;/p&gt;
&lt;h2 id="_2"&gt;可能的改进&lt;/h2&gt;
&lt;h3 id="_3"&gt;调度器的超时&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nfds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;epoll_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;epoll_fd_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_task_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这段调度器中的代码，生生的把IO复用模型改成了轮询。猜测这是为了照顾超时定时器，但实际上这个并无必要。我们可以使用&lt;code&gt;timerfd&lt;/code&gt;和&lt;code&gt;eventfd&lt;/code&gt;来取代定时器。但是这只是一种猜测，这种写法可能也是有性能上的考虑吧。&lt;/p&gt;
&lt;h3 id="_4"&gt;代码风格&lt;/h3&gt;
&lt;p&gt;代码风格可能是一个比较泛的问题，但是phxrpc的代码我能明显的感觉到编码风格的不同。以及元素层次不明朗，上下级模块相互耦合的情况。&lt;/p&gt;
&lt;h3 id="_5"&gt;没有测试！没有测试！没有测试！&lt;/h3&gt;
&lt;p&gt;因为phxrpc没有测试代码，所以我严重怀疑这就是一个玩票的项目，没有（或暂时没有）在生产环境上运行。&lt;/p&gt;
&lt;p&gt;如果有可能的话，请加上性能测试！请加上功能测试！请加上性功能测试！&lt;/p&gt;
&lt;h2 id="_6"&gt;写在后面&lt;/h2&gt;
&lt;p&gt;时间仓促，水平有限。写点东西，方便大家学习交流。&lt;/p&gt;
&lt;p&gt;如果我写的哪里不对，99%的锅归我傻逼，1%的锅归phxrpc代码没写测试。欢迎大家多做自我批评。&lt;/p&gt;
&lt;p&gt;好啦好啦，就到这里吧。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-23/91802175.jpg"&gt;&lt;/p&gt;</content><category term="Blog"/><category term="phxrpc"/><category term="rpc"/></entry><entry><title>RPC - phxrpc代码阅读(7)</title><link href="https://wizmann.top/phxrpc-7.html" rel="alternate"/><published>2016-10-22T23:03:36+08:00</published><updated>2016-10-22T23:03:36+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2016-10-22:/phxrpc-7.html</id><summary type="html">&lt;h2 id="_1"&gt;前言&lt;/h2&gt;
&lt;p&gt;看了这么久代码，终于我们要接近phxrpc的核心部分了。&lt;/p&gt;
&lt;p&gt;但是出人意料的是，rpc部分并没有过多的概念和magic trick。而且因为ucontext已经被封装好了，所以在rpc里的操作，可以完全按照同步的写法来搞，开 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;前言&lt;/h2&gt;
&lt;p&gt;看了这么久代码，终于我们要接近phxrpc的核心部分了。&lt;/p&gt;
&lt;p&gt;但是出人意料的是，rpc部分并没有过多的概念和magic trick。而且因为ucontext已经被封装好了，所以在rpc里的操作，可以完全按照同步的写法来搞，开发者们不需要切换同步异步的思维模式，就可以在底层的封装之上，做自己想做的事了。&lt;/p&gt;
&lt;h2 id="-threadqueue"&gt;线程安全(?)的队列 - ThreadQueue&lt;/h2&gt;
&lt;p&gt;我不知道开发者为啥要起&lt;code&gt;ThdQueue&lt;/code&gt;这样令人迷惑的名字，这种诡异的命名风格贯穿了整个代码。咋一看这个类是maintain一堆线程的，类似于线程池，但其实这个类就是一个&lt;code&gt;BlockingQueue&lt;/code&gt;的实现。&lt;/p&gt;
&lt;p&gt;之后，这个队列有三种操作，&lt;code&gt;push&lt;/code&gt;、&lt;code&gt;pluck&lt;/code&gt;和&lt;code&gt;break_out&lt;/code&gt;。push操作不用多说，pluck对应的我们所理解的pop操作，即从队列中弹出元素（pluck这个词貌似是从grpc里面来的，那我就不吐槽了，毕竟Google爸爸）。&lt;/p&gt;
&lt;p&gt;更令人疑惑的是&lt;code&gt;break_out&lt;/code&gt;这个操作。从代码来看，像是清空队列，并且在dtor中也显式的调用了这个函数。&lt;/p&gt;
&lt;p&gt;但是有以下的几个问题。&lt;/p&gt;
&lt;p&gt;一，&lt;code&gt;break_out_&lt;/code&gt;是一个bool变量，且在不同线程间共享，问题在于这个变量可能被cache住，直接访问可能会造成非预期的结果，可能需要&lt;code&gt;volitaile&lt;/code&gt;，或者在&lt;code&gt;pluck&lt;/code&gt;函数里加一个mem barrier。&lt;/p&gt;
&lt;p&gt;二来，在析构函数中调用&lt;code&gt;break_out_&lt;/code&gt;，有可能的一种情况是有其它线程还在&lt;code&gt;pluck&lt;/code&gt;函数中，而&lt;code&gt;ThdQueue&lt;/code&gt;对象已经被析构了，我们就需要承担这种不安全行为的后果（此处有广告：大铁棍子医院捅主任，张姐去了都说好）。&lt;/p&gt;
&lt;p&gt;当然，如果这个函数只在结束进程时使用，其实写的糙一点也无所谓，因为毕竟线上服务是没有“退出”这种状态的。当我们要清空队列时，已经不需要对外提供服务，之后直接&lt;code&gt;kill -9&lt;/code&gt;就好，不会触发多线程的坑。不过，这里我觉得应该还是要加小心。&lt;/p&gt;
&lt;h2 id="uthreadcaller"&gt;UThreadCaller&lt;/h2&gt;
&lt;p&gt;这个破类让我看了一小时，分析它的keepalive是怎么实现的。结果发现这个类被没有被调用。&lt;/p&gt;
&lt;p&gt;GG。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-22/54117736.jpg"&gt;&lt;/p&gt;
&lt;h2 id="-hshaserver"&gt;一个超级文件 - HshaServer&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;不知道为啥开发者要把这么多文件写一块，拆开不好吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="dataflow"&gt;DataFlow&lt;/h3&gt;
&lt;p&gt;DataFlow包含了Request和Response两个Queue，还附加了入队的时间戳和一个args参数指针。&lt;/p&gt;
&lt;h3 id="hshaserverstat"&gt;HshaServerStat&lt;/h3&gt;
&lt;p&gt;一个统计类。会在后台新建一个线程，约每一秒打印一次统计日志。&lt;/p&gt;
&lt;p&gt;这个类里有一个技巧，在&lt;code&gt;CallFunc()&lt;/code&gt;函数中，每一秒循环一次并没有使用sleep家族的函数，也没有使用select的超时。而是使用了&lt;code&gt;condtional variable&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;std::condition_variable::wait_for&lt;/code&gt;函数，实质是就是带超时的等待。而这里，在一般状态下，是没有线程会notify的，所以wait_for函数会睡满1s。但是在退出时，会显式的notify统计线程，破坏等待状态，使统计线程退出。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wait_for&lt;/code&gt;函数的具体用法，可以参考&lt;a href="http://en.cppreference.com/w/cpp/thread/condition_variable/wait_for"&gt;文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;下面的&lt;code&gt;HshaServerQos&lt;/code&gt;也是一样的思路，Qos即“Quality of service”。&lt;/p&gt;
&lt;h3 id="workerworkerpool"&gt;Worker和WorkerPool&lt;/h3&gt;
&lt;p&gt;这两个类其实是一个和一堆的关系，不过由于这里的诡异的写法，导致一个依赖一堆，一堆调用一个。&lt;/p&gt;
&lt;p&gt;WorkerPool是一个全局的线程池，里面有线程（废话），输入输出队列，Disipatcher和调度器。所以Worker要反过来依赖WorkerPool里面的数据。造成了很大的耦合性。&lt;/p&gt;
&lt;p&gt;Worker从输入队列中获取信息，并且使用&lt;code&gt;dispatcher&lt;/code&gt;进行CPU密集的处理（我觉得&lt;code&gt;dispatcher&lt;/code&gt;这个名字起的也有问题）。之后将结果放入输出队列，由后面的&lt;code&gt;HshaServerIO::ActiveSocketFunc&lt;/code&gt;驱动协程库进行之后的IO操作。&lt;/p&gt;
&lt;h3 id="-hshaserverio"&gt;完成调度器 - HshaServerIO&lt;/h3&gt;
&lt;p&gt;这个类的主要作用就是补全调度器缺少的函数，并提供了一个IO的工作函数&lt;code&gt;HshaServerIO::IOFunc&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;调度器的工作流程前面已经说过了，我们现在就从更具体化的实现上来阅读一下。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HshaServerIO :: AddAcceptedFd&lt;/code&gt;，这个函数由外部调用，传入已经accept的fd，之后&lt;code&gt;HshaServerIO::HandlerAcceptedFd&lt;/code&gt;将这个fd，和IO工作函数&lt;code&gt;IOFunc&lt;/code&gt;一起放入调度器中进行调度。&lt;/p&gt;
&lt;p&gt;工作函数&lt;code&gt;IOFunc&lt;/code&gt;只负责将请求放入队列，而并不负责从输出队列中取出响应。这个事情由&lt;code&gt;HshaServerIO::ActiveSocketFunc&lt;/code&gt;负责。&lt;/p&gt;
&lt;p&gt;换句话说，在调度器的工作循环中，&lt;code&gt;epoll_wait&lt;/code&gt;中等待的只有在进行IO的两种fd，一是读还没读完的，二是写还没写完的。&lt;/p&gt;
&lt;p&gt;进行完CPU操作的fd，由&lt;code&gt;active_socket_func_&lt;/code&gt;函数重新激活，向客户端写回响应。所以这个函数应该叫&lt;code&gt;activate_socket_with_resp_func_&lt;/code&gt;更合适一些。（至少第一个单词得是个动词好不。）&lt;/p&gt;
&lt;p&gt;后面的keepalive的处理也是非常浅显的，这里就不多说了。&lt;/p&gt;
&lt;h3 id="io-hshaserverunithshaserver"&gt;多线程IO - HshaServerUnit和HshaServer&lt;/h3&gt;
&lt;p&gt;前面我们说了不少协程的事，但这并不代表我们不使用多线程带来的红利。或者至少在性能不符合预期的时候，用多线程来tuning一下。&lt;/p&gt;
&lt;p&gt;HashServerUnit包装了一组线程，其中包括一个IO线程和若干CPU线程。我们在HshaServer中，还可以配置多个Unit，使得我们有多个IO线程，充分榨干CPU和IO的每一滴汗水。&lt;/p&gt;
&lt;p&gt;由于手里也没有测试数据，也就不能更详细的来说配置服务参数的策略。但是无责任猜测，IO线程应该不超过3个。CPU线程数目应该略多于CPU核数。&lt;/p&gt;
&lt;h3 id="acceptor"&gt;一个独立的Acceptor&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;HshaServerAcceptor&lt;/code&gt;类相对比较独立，它是用来接受访问请求。是主线程的工作循环。&lt;/p&gt;
&lt;p&gt;这里比较奇怪的是，&lt;code&gt;LoopAccept&lt;/code&gt;函数设置了CPU亲和性。使得控制线程只在CPU0上运行。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;cpu_set_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CPU_ZERO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CPU_SET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;pid_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sched_setaffinity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;具体原因有待探讨，可能是和中断亲和性有关。&lt;/p&gt;
&lt;h2 id="_2"&gt;写在后面&lt;/h2&gt;
&lt;p&gt;总算囫囵吞枣的把这RPC读完了，其实这里还是有好多疑问的。但是由于phxrpc的文档实在是。。。基本算是没有吧。所以可能还要去Github上提一波Issue。&lt;/p&gt;
&lt;p&gt;在学习过程中，真的感觉自己懂的还是太少。简直药丸。&lt;/p&gt;
&lt;p&gt;还需要更加努力才好。&lt;/p&gt;</content><category term="Blog"/><category term="phxrpc"/><category term="rpc"/></entry><entry><title>非阻塞TCP流和HttpClient - phxrpc代码阅读(6)</title><link href="https://wizmann.top/phxrpc-6.html" rel="alternate"/><published>2016-10-19T00:03:12+08:00</published><updated>2016-10-19T00:03:12+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2016-10-19:/phxrpc-6.html</id><summary type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;其实这点东西有点鸡肋。因为TCP流在前面已经讲过，难点在于“流”和“流缓冲区”部分。而HttpClient只是TCP流的一个应用，代码不多，且重点在于HTTP协议的调教上面。&lt;/p&gt;
&lt;p&gt;不过因为前面有写阻 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;其实这点东西有点鸡肋。因为TCP流在前面已经讲过，难点在于“流”和“流缓冲区”部分。而HttpClient只是TCP流的一个应用，代码不多，且重点在于HTTP协议的调教上面。&lt;/p&gt;
&lt;p&gt;不过因为前面有写阻塞TCP流，还是前后呼应，把非阻塞TCP流也小小的讲解一下。顺便饶一段HttpClient的讲解，算是充实一下内容吧。&lt;/p&gt;
&lt;h2 id="tcp-uthreadtcpstreambuf"&gt;非阻塞TCP流缓冲区 - &lt;code&gt;UThreadTcpStreamBuf&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;这个其实没啥可讲的，传入一个&lt;code&gt;socket&lt;/code&gt;，然后读写分别调用&lt;code&gt;UThreadRecv&lt;/code&gt;和&lt;code&gt;UThreadSend&lt;/code&gt;，IO复用和协程切换的复杂操作都被封装在里面了。剩下的操作都由基类函数来解决。&lt;/p&gt;
&lt;h2 id="tcp-uthreadtcpstream"&gt;非阻塞TCP流 - &lt;code&gt;UThreadTcpStream&lt;/code&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;确实没啥可说的，你们自己去读代码吧。。。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;非阻塞TCP流和阻塞TCP流的区别是~~它不阻塞~~，在阻塞TCP流中，我们传入的是一个TCP流，而非阻塞TCP流传入的是一个协程调度器和一个TCP流。&lt;/p&gt;
&lt;p&gt;这个很好理解，一个阻塞流自然会占满一个线程的IO和CPU —— 在阻塞流IO读写时，CPU空闲；在CPU忙时，IO空闲。&lt;/p&gt;
&lt;p&gt;而非阻塞流会将自己IO wait的时间托管给epoll，把剩下的时间用于CPU计算（和一些overhead上）。所以一个线程可以handle多个socket，协程调度器就是必须的了。之后的读写操作就交由我们前面讨论过的epoll和ucontext协程来共同完成了。&lt;/p&gt;
&lt;h2 id="httpclient"&gt;HttpClient&lt;/h2&gt;
&lt;p&gt;其实这里分析HttpClient的意义不是很大，因为Http毕竟是一个成熟的协议，然后相应的设置含义虽然明确，但是放到相应的上下文中分析比较好。&lt;/p&gt;
&lt;p&gt;这篇博文&lt;a href="https://www.byvoid.com/blog/http-keep-alive-header"&gt;《HTTP协议头部与Keep-Alive模式详解》&lt;/a&gt;中有一部分背景知识，感兴趣的同学可以简单了解一下。&lt;/p&gt;
&lt;h3 id="httpdispatcher"&gt;在HttpDispatcher中使用的一个小技巧&lt;/h3&gt;
&lt;p&gt;在&lt;code&gt;http_dispatcher.h&lt;/code&gt;文件中，作者使用了一个比较新奇的技巧：“&lt;a href="http://tipsandtricks.runicsoft.com/Cpp/MemberFunctionPointers.html"&gt;Function Pointers to Member Functions&lt;/a&gt;”。&lt;/p&gt;
&lt;p&gt;我们来看代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Dispatcher&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;URIFunc_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这行代码的意思是，为一个参数为&lt;code&gt;(const HttpRequest&amp;amp;, HttpResponse*)&lt;/code&gt;且返回值为&lt;code&gt;int&lt;/code&gt;的函数声明一个别名&lt;code&gt;URIFunc_t&lt;/code&gt;，并且这个函数，一定是&lt;code&gt;Dispatcher&lt;/code&gt;类的成员函数。&lt;/p&gt;
&lt;p&gt;到目前为止，一切都还是正常的样子，语法也是我们常见的类型。但是下面这种写法，确实是我第一次见。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;if (uri_func_map_.end() != iter) {
    ret = (dispatcher_.*iter-&amp;gt;second)(request, response);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这里的&lt;code&gt;(dispatcher_.*iter-&amp;gt;second)&lt;/code&gt;，&lt;code&gt;iter-&amp;gt;second&lt;/code&gt;是从map中拿出来的，在&lt;code&gt;dispatcher_&lt;/code&gt;对象中的成员函数的指针。我们使用星号解引用，再把它和&lt;code&gt;dispatcher_&lt;/code&gt;对象拼接在一起，像正常调用成员函数一样调用就可以了。&lt;/p&gt;
&lt;h2 id="-epoll"&gt;貌似写的有点少，再饶一段吧 - epoll测试服务端/客户端&lt;/h2&gt;
&lt;p&gt;我们翻篇回到&lt;code&gt;network&lt;/code&gt;文件夹下面，看一下&lt;code&gt;test_epoll_[server|client].[h|cpp]&lt;/code&gt;文件。&lt;/p&gt;
&lt;h3 id="epoll"&gt;epoll测试客户端&lt;/h3&gt;
&lt;p&gt;首先，我们读取命令行参数，新建一个调度器，由参数决定调度器的woker协程数量。之后新建&lt;code&gt;UThreadEpollArgs_t&lt;/code&gt;，把调度器指针塞进去。再之后把&lt;code&gt;echoclient&lt;/code&gt;工作函数和&lt;code&gt;args&lt;/code&gt;参数放由调度器中进行调度。&lt;/p&gt;
&lt;p&gt;接下来我们看看工作函数&lt;code&gt;echoclient&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;工作函数的第一步是申请一个socket fd：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;int fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这里我解释一下最后一个参数&lt;code&gt;IPPROTO_IP&lt;/code&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the in.h file, the comment says: Dummy protocol for TCP.    &lt;br&gt;
This constant has the value 0. It&amp;rsquo;s actually an automatic choice depending on socket type and family.    &lt;br&gt;
If you use it, and if the socket type is SOCK_STREAM and the family is AF_INET, then the protocol will automatically be TCP (exactly the same as if you&amp;rsquo;d used IPPROTO_TCP). Buf if you use IPPROTO_IP together with AF_INET and SOCK_RAW, you will have an error, because the kernel cannot choose a protocol automatically in this case.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个参数的意义是告诉内核，如果只有一个选项的话，你特么爱用哪个协议就用哪个吧。所以有一些时候，我们会直接把最后一个参数写成0，这就是&lt;code&gt;IPPROTO_IP&lt;/code&gt;宏的字面值。&lt;/p&gt;
&lt;p&gt;更多信息，可以参考这个&lt;a href="http://stackoverflow.com/questions/24590818/what-is-the-difference-between-ipproto-ip-and-ipproto-raw"&gt;问题&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;后面的流程非常简单，先接收server发来的欢迎信息，之后ping pong十次，发送“quit”包后结束协程。&lt;/p&gt;
&lt;h3 id="epoll_1"&gt;epoll测试服务端&lt;/h3&gt;
&lt;p&gt;服务端和客户端区别不大，主要区别在于客户端在一开始只有一个协程。之后在accept连接时，会主动新建工作协程。&lt;/p&gt;
&lt;p&gt;这里解释一下&lt;code&gt;listen(fd, backlog)&lt;/code&gt;函数的第二个参数&lt;code&gt;backlog&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;backlog意为内核为相应套接字排队的最大连接个数。内核为任何一个给定的监听套接字维护两个队列：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;未完成连接队列(incomplete connection queue)        &lt;br&gt;
已由某个客户发出并到达服务器，而服务器正在等待完成相应的TCP三路握手过程。这些套接字处于SYN_RCVD状态&lt;/li&gt;
&lt;li&gt;已完成连接队列(completed connection queue)     &lt;br&gt;
每个已完成TCP三路握手过程的客户对应其中一项。这些套接字处于ESTABLISHED状态&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当队列满时，TCP会忽略改分节，但是不发送RST。服务端会期望客户端重发SYN，采用正常的重传机制来处理&lt;/p&gt;
&lt;p&gt;队列的真实大小往往比设定backlog值要大一些（~1.5倍）&lt;/p&gt;
&lt;p&gt;我们继续看工作函数&lt;code&gt;echoaccept&lt;/code&gt;。第一步是新建一个&lt;code&gt;UThreadSocket_t&lt;/code&gt;对象，用来监听accept事件。当有新的连接进入时，我们就将新的连接，以及连接所用的工作函数&lt;code&gt;echoserver&lt;/code&gt;加入到调度器中。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;echoserver&lt;/code&gt;函数首先发送一个欢迎信息，之后就和客户端打起乒乓球来，直到客户端发来quit，就结束这个工作协程。&lt;/p&gt;
&lt;p&gt;其实这里有一个问题，如果发生了一个字符串拆成两半发的现象，比如第一个包是“blahblahquitq”，之后一个包是“uit”，那么这个协程永远就不会停止了。由于TCP是一个流协议，我们不能保证每一次recv回来的信息都是一个完整的“包”。不做不必要的假设，不给自己找麻烦。&lt;/p&gt;
&lt;p&gt;不过因为这里ping pong的消息都比较短，可以强行认为每一个包都包含着一个完整的字符串。当然，这种假设也是无意义的。所以我们要留意phxrpc在真正的生产环境，是怎样处理这种“粘包”的问题的。&lt;/p&gt;
&lt;h2 id="_2"&gt;写在最后&lt;/h2&gt;
&lt;p&gt;上一张女神的图：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-19/89151689.jpg"&gt;&lt;/p&gt;
&lt;p&gt;没啦~&lt;/p&gt;</content><category term="Blog"/><category term="phxrpc"/></entry><entry><title>使用epoll驱动ucontext - phxrpc代码阅读(5)</title><link href="https://wizmann.top/phxrpc-5.html" rel="alternate"/><published>2016-10-17T01:28:40+08:00</published><updated>2016-10-17T01:28:40+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2016-10-17:/phxrpc-5.html</id><summary type="html">&lt;h2 id="pipe-epollnotifier"&gt;用pipe叫醒你 — EpollNotifier&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;class EpollNotifier&lt;/code&gt;类型封装了一个使用pipe传递信号的Notifier类。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Run()&lt;/code&gt;函数（其实我觉得叫Register或Activate会更好）首先声明了两个单向的pipe：&lt;code&gt;pipe_fds_&lt;/code&gt;，从&lt;a href="http://man7.org/linux/man-pages/man2fpipe.2.html"&gt;文档&lt;/a&gt;中我们可以知道&lt;code&gt;pipe_fds_[0]&lt;/code&gt;是 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="pipe-epollnotifier"&gt;用pipe叫醒你 — EpollNotifier&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;class EpollNotifier&lt;/code&gt;类型封装了一个使用pipe传递信号的Notifier类。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Run()&lt;/code&gt;函数（其实我觉得叫Register或Activate会更好）首先声明了两个单向的pipe：&lt;code&gt;pipe_fds_&lt;/code&gt;，从&lt;a href="http://man7.org/linux/man-pages/man2fpipe.2.html"&gt;文档&lt;/a&gt;中我们可以知道&lt;code&gt;pipe_fds_[0]&lt;/code&gt;是读管道，而&lt;code&gt;pipe_fds_[1]&lt;/code&gt;是写管道。这里有一丁点反直觉，就是pipe拿了两个fd，但是仍旧是单工的。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-16/2335602.jpg"&gt;&lt;/p&gt;
&lt;p&gt;然后将读fd设为&lt;code&gt;O_NONBLOCK&lt;/code&gt;以供epoll调度，最后将&lt;code&gt;Func()&lt;/code&gt;函数传入&lt;code&gt;scheduler_&lt;/code&gt;中。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里跑个题，想起了当年我大一的时候上过的通信导论的选修课。那会我还没有沉迷代码，还是一个积极乐观好好学习的新时代大学生。自从开始写了代码，人就越来越废物了，连女朋友都找不到了。     &lt;br&gt;
年轻人们啊，有饭辙干点啥都行，千万别写码啊。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;Func()&lt;/code&gt;函数做的事情很简单，就是从管道里尝试poll一段数据，拿到数据后直接扔掉。因为管道里传来的数据并没有实际意义，这样设计的主要意义在于唤醒epoll。&lt;/p&gt;
&lt;p&gt;我们可以从&lt;code&gt;Notify()&lt;/code&gt;函数中看出，传入管道的是一个字符&amp;rdquo;a&amp;rdquo;。&lt;/p&gt;
&lt;h2 id="uthreadepollscheduler"&gt;调度器类 — UThreadEpollScheduler&lt;/h2&gt;
&lt;p&gt;调试器类在初始化时，声明了协程栈的大小以及调试器所调度的最大任务数。不过这个最大任务数是一个“软线”，因为在最新的Linux内核中，epoll使用动态内存管理fd，&lt;code&gt;epoll_create&lt;/code&gt;中的&lt;code&gt;size&lt;/code&gt;参数已经失去了作用。而后面&lt;code&gt;epoll_wait&lt;/code&gt;中的&lt;code&gt;max_event&lt;/code&gt;参数只是每次返回的最多event数，也就是如果我们向调度器中加入了超过限制的fd，也不会有什么恶劣的后果。（参考&lt;a href="http://man7.org/linux/man-pages/man2/epoll_create.2.html"&gt;epoll文档&lt;/a&gt;和&lt;a href="http://man7.org/linux/man-pages/man2/epoll_wait.2.html"&gt;epoll_wait文档&lt;/a&gt;）&lt;/p&gt;
&lt;h3 id="instance"&gt;让人搞不懂的Instance函数&lt;/h3&gt;
&lt;p&gt;这个函数看起来像一个Singleton的实现，但是明明&lt;code&gt;UThreadEpollScheduler&lt;/code&gt;类的构造函数是public的。也就是这个函数像是一个单例，但它又不是一个单例。&lt;/p&gt;
&lt;p&gt;在其它的代码中，也没有调用个函数的地方，我觉得这个函数是开发者忘记删了。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-16/85921046.jpg"&gt;&lt;/p&gt;
&lt;h3 id="createsocket"&gt;远古智慧 — CreateSocket&lt;/h3&gt;
&lt;p&gt;这个函数其实没啥可说的，算是对&lt;code&gt;UThreadSocket_t&lt;/code&gt;构造的封装，但是这里面有一个小技巧，就是&lt;code&gt;calloc&lt;/code&gt;的使用。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;calloc&lt;/code&gt;的作用是向内核申请一段栈空间（和&lt;code&gt;malloc&lt;/code&gt;行为一致），然后将这一段内存清0。&lt;/p&gt;
&lt;p&gt;个人感觉这样做的目的是防止指针没有初始化带来的一系列诡异的问题。把指针清零，可以让问题在第一时间出现，方便出错时的调试。但是我觉得还是用测试覆盖这种问题已经好，因为空指针在特定的情况下，仍可能是导致诡异行为的源头。&lt;/p&gt;
&lt;h3 id="run"&gt;跑 — Run&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Run()&lt;/code&gt;函数是调度器的核心函数（当然啦），简单来说就是一个循环获取event，用适当的协程处理event。&lt;/p&gt;
&lt;p&gt;函数的一开始，先调用&lt;code&gt;ConsumeTodoList()&lt;/code&gt;函数，将列表中的协程全部激活，并hang在epoll上。&lt;/p&gt;
&lt;p&gt;之后进入一个“死循环”，通过&lt;code&gt;epoll_wait&lt;/code&gt;将有数据可读的fd取出，并调用相应的协程进行处理。这里我们看到，&lt;code&gt;epoll_wait&lt;/code&gt;的超时时间是写死的4ms，并没有使用&lt;code&gt;next_timeout&lt;/code&gt;给出的下次超时时间。这是因为这里支持了“active socket”，即服务器对活动连接操作，例如发送响应甚至新建一个socket。&lt;/p&gt;
&lt;p&gt;后面的&lt;code&gt;handler_accepted_fd_func_&lt;/code&gt;和&lt;code&gt;active socket&lt;/code&gt;是类似的，不过这个函数是用来处理已经建立好的连接，为其分配相应的协程。&lt;/p&gt;
&lt;p&gt;所以，由此可见，这个循环即是事件驱动的，又是轮询的。然而这两种模型，居然能写在一个函数里，真是令人印象深刻。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-16/4157866.jpg"&gt;&lt;/p&gt;
&lt;p&gt;下面的&lt;code&gt;DealwithTimeout&lt;/code&gt;函数处理了一下超时的协程，并且更新了&lt;code&gt;next_timeout&lt;/code&gt;变量。然而这个变量因为众所周知的原因，并没有什么卵用。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-16/4157866.jpg"&gt;&lt;/p&gt;
&lt;h2 id="pollpoll-epoll"&gt;Poll来Poll去 — 一堆epoll函数的封装&lt;/h2&gt;
&lt;h3 id="uthreadpoll1"&gt;UThreadPoll(1)&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;UThreadPoll&lt;/code&gt;函数有两个版本，一个是poll单个socket，另外一个是poll一堆socket。我们先从单个socket的看起。&lt;/p&gt;
&lt;p&gt;第一步是注册一个超时时间，第二步将这个socket放到epoll的监听列表上。之后调用yield，把控制权交还给主控制流。&lt;/p&gt;
&lt;p&gt;当epoll收到相应的事件时，主控制流会将控制权交还给协程，协程将socket从epoll监听列表中移除，之后进行后面的操作。&lt;/p&gt;
&lt;p&gt;整体的工作流可以参考下图。&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="http://7lrx26.com1.z0.glb.clouddn.com/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202016-10-16%2021.33.48.png"&gt;&lt;/p&gt;
&lt;h3 id="uthreadpoll2-"&gt;UThreadPoll(2) - 边缘触发和水平触发&lt;/h3&gt;
&lt;p&gt;epoll有两种触发模式，边缘触发(edge-trigger, ET)和水平触发(level-trigger, LT)。&lt;/p&gt;
&lt;p&gt;简单解释一下epoll的这两种触发模式。ET意味着只要有fd可读或可写，&lt;code&gt;epoll_wait&lt;/code&gt;就返回这个fd，而LT意味着当且仅当fd由“不可读变为可读”或由“不可写变为可写”时，&lt;code&gt;epoll_wait&lt;/code&gt;才会返回。（这有可能出现所谓的“粘包”现象，详见&lt;a href="http://man7.org/linux/man-pages/man7/epoll.7.html"&gt;这里&lt;/a&gt;）&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;第一次听到“粘包”这个词，我一直以为这是啥好吃的。。。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这意味着，当我们使用LT时，我们必须清理干净fd中的数据，即只要可读，就一直读；只要可写，就一直写。否则就会出现问题。&lt;/p&gt;
&lt;p&gt;在这里，我们使用的是比较常用的ET模式。并且我们利用了ET的特性实现了“监听多个fd，返回最早响应的那一个”。&lt;/p&gt;
&lt;p&gt;首先，我们新建了一个epoll fd（简称内部epoll），将列表中的所有socket放到里面监听。之后将这个socket fd放到&lt;code&gt;list[0]-&amp;gt;epollfd&lt;/code&gt;所对应的epoll（简称外部epoll，通常是主工作循环的那个epoll）监听列表中。&lt;/p&gt;
&lt;p&gt;当列表中的socket有返回时，内部的epoll会返回一个&lt;code&gt;EPOLLIN&lt;/code&gt;事件，外部的epoll接收到这个事件后，进行协程切换，回到当前函数中。&lt;/p&gt;
&lt;p&gt;下一步我们&lt;code&gt;epoll_wait&lt;/code&gt;内部的epoll fd，因为我们确定此时一定有可操作的fd，所以我们将&lt;code&gt;epoll_wait&lt;/code&gt;的timeout参数设为0。之后我们将返回的fd的&lt;code&gt;waited_events&lt;/code&gt;参数填好，最后返回操作成功的fd的数目。&lt;/p&gt;
&lt;p&gt;这个函数比较绕，不过有一个好消息 —— 这个函数也没有被其它地方调用过。不过这种&lt;code&gt;cascaded epoll&lt;/code&gt;的技巧确实是让人耳目一新。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-16/4157866.jpg"&gt;&lt;/p&gt;
&lt;h3 id="-uthreadwait"&gt;延时执行 - UThreadWait&lt;/h3&gt;
&lt;p&gt;剩下的几个函数基本都是无脑封装，顺着看一遍代码基本就知道是啥意思了。不过&lt;code&gt;UThreadWait&lt;/code&gt;这个函数比较有意思，可以用来复习一下&lt;code&gt;uthread + epoll&lt;/code&gt;的工作流程。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;UThreadWait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UThreadSocket_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timeout_ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uthread_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetCurrUThread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;AddTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timeout_ms&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;YieldTask&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;RemoveTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timer_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;首先，获取当前uthread的ID，当我们调用&lt;code&gt;Resume()&lt;/code&gt;函数时，让代码知道我们要返回到哪个协程上面。&lt;/p&gt;
&lt;p&gt;然后我们向调度器中添加一个定时器。之后&lt;code&gt;Yield()&lt;/code&gt;，离开当前协程。&lt;/p&gt;
&lt;p&gt;主工作循环运行到超时时间后，会在这个协程打上一个“超时”标签，然后&lt;code&gt;Resume()&lt;/code&gt;切换回这个协程上来。&lt;/p&gt;
&lt;p&gt;剩下的工作，就交由协程内部绑定的函数来进行处理。&lt;/p&gt;
&lt;h2 id="_1"&gt;写在最后&lt;/h2&gt;
&lt;p&gt;在网络编程方面，真心是一个初学者。很多用词可能不恰当，也有一些是自己生造的。大家阅读的时候，尽量以代码和更专业的术语为准。&lt;/p&gt;
&lt;p&gt;然后因为在行文中，可能追求了过多的逗比感，对原代码调侃了几句。并没有什么恶意，如果哪里说的不对，欢迎拍砖。&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="http://7lrx26.com1.z0.glb.clouddn.com/IMG_20161017_012107.jpg"&gt;&lt;/p&gt;
&lt;p&gt;佛祖保佑，永无Bug。&lt;/p&gt;</content><category term="Blog"/><category term="phxrpc"/><category term="ucontext"/><category term="epoll"/></entry><entry><title>ucontext - phxrpc代码阅读(4)</title><link href="https://wizmann.top/phxrpc-4.html" rel="alternate"/><published>2016-10-13T23:45:24+08:00</published><updated>2016-10-13T23:45:24+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2016-10-13:/phxrpc-4.html</id><summary type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;国庆假期过半，phxrpc的代码阅读大概要小小告一段落啦。因为这两天还要读工作相关的代码，以及最后几天还有一次短途旅行。&lt;/p&gt;
&lt;p&gt;所以非阻塞TCP流可能要留到下一篇了，这一篇只 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;国庆假期过半，phxrpc的代码阅读大概要小小告一段落啦。因为这两天还要读工作相关的代码，以及最后几天还有一次短途旅行。&lt;/p&gt;
&lt;p&gt;所以非阻塞TCP流可能要留到下一篇了，这一篇只涉及非阻塞TCP流使用到的ucontext协程库，及其使用的一些框架代码。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;161013更新：这点破东西写到今天才写完，GG。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="ucontext"&gt;什么是ucontext&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Subroutines are special cases of &amp;hellip; coroutines.&amp;rdquo; –Donald Knuth.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先我们来看一下，什么是线程。线程是进程内一条执行流的状态，包含了硬件状态（硬件计数器，寄存器，条件码等）和堆栈中的数据。&lt;/p&gt;
&lt;p&gt;线程通常只有一个入口和一个出口。当线程返回时，线程的生命周期也结束了。所以，通常线程的执行由内核调度。&lt;/p&gt;
&lt;p&gt;协程的定义与线程类似，也是硬件状态+堆栈的状态组合。但是与线程不同的是，协程可以有多个出口。可以通过yield来暂停自己，调用其它协程。再次启动时，会从上次挂起的地方继续运行。&lt;/p&gt;
&lt;h2 id="phxrpcucontext"&gt;phxrpc中的ucontext&lt;/h2&gt;
&lt;p&gt;phxrpc提供了system和boost两种ucontext的实现，所以提供了一个&lt;code&gt;uthread_context_base&lt;/code&gt;的基类。其实在这里我是有一点怀疑虚函数的性能的，不过好在协程的切换以及网络IO操作还是比较耗性能的，所以虚函数多出来的几次内存寻址也并非不能接受。&lt;/p&gt;
&lt;p&gt;在这篇文章中，我们只看&lt;code&gt;uthread_context_system&lt;/code&gt;这个使用系统ucontext库的实现。&lt;/p&gt;
&lt;h3 id="uthreadcontext"&gt;协程上下文：&lt;code&gt;UThreadContext&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;这个类是协程上下文的虚基类，所以代码很少。并且也没有什么好解释的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;void Make(UThreadFunc_t func, void * args)&lt;/code&gt;函数是&lt;code&gt;makecontext()&lt;/code&gt;的封装。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bool Resume()&lt;/code&gt;和&lt;code&gt;bool Yield()&lt;/code&gt;是&lt;code&gt;swapcontext&lt;/code&gt;的封装。&lt;/p&gt;
&lt;p&gt;个人感觉这个类拆分成一个工厂类（传入一个Create仿函数）和一个上下文基类会更清楚一点。&lt;/p&gt;
&lt;h3 id="ucontextuthreadcontextsystem"&gt;使用系统ucontext库的协程上下文：&lt;code&gt;UThreadContextSystem&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;在phxrpc的文档中，说明使用系统原生的ucontext库的性能要差于boost版本的。但是从数据上来看微乎其微，所以我们先从这个版本看起，力求举一反三。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;UThreadContextSystem&lt;/code&gt;在构造函数中传入了协程栈大小，协程要执行的函数（及参数），协程执行后的回调，以及调试用的&lt;code&gt;need_stack_protect&lt;/code&gt; flag。&lt;/p&gt;
&lt;p&gt;每一个上下文对象都维护了两个context，&lt;code&gt;main_context&lt;/code&gt;用来表示主程序执行流的上下文，而&lt;code&gt;context_&lt;/code&gt;则用来表示协程的上下文。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main_context&lt;/code&gt;是&lt;code&gt;static thread_local&lt;/code&gt;修饰的，也就意味着这个静态变量在每一个线程中有且只有一个。执行在同一个线程上的不同协程，都会切换/被切换到这个上下文上。&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;Resume()&lt;/code&gt;函数中，我们激活协程上下文，并将主程序执行流的上下文保存在&lt;code&gt;main_context&lt;/code&gt;上。&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;Yield()&lt;/code&gt;函数中，我们将主程序执行流的上下文激活，将协程上下文保存回&lt;code&gt;context_&lt;/code&gt;中。&lt;/p&gt;
&lt;p&gt;这里的&lt;code&gt;UThreadFuncWrapper()&lt;/code&gt;值得我们特别关注。这个函数包装了我们的工作函数&lt;code&gt;uc-&amp;gt;func_&lt;/code&gt;，并且将&lt;code&gt;this&lt;/code&gt;指针传进去。&lt;/p&gt;
&lt;p&gt;传入指针时，这里使用了一个技巧。首先我们将指针强转为&lt;code&gt;uintptr_t&lt;/code&gt;，这个是编译器内置的一个&lt;code&gt;typeof&lt;/code&gt;，意在将指针类型无损失的转为整型。之后，将一个&lt;code&gt;uintptr_t&lt;/code&gt;拆为两个&lt;code&gt;uint32_t&lt;/code&gt;。最后，在wrapper函数中，将这两个&lt;code&gt;uint32_t&lt;/code&gt;拼回成一个指针类型。&lt;/p&gt;
&lt;p&gt;初看这段代码，我们就有这样的疑问：“这特么不是有病么？” 但是，折腾自然有折腾的道理。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When this context is later activated (using setcontext(3) or swapcontext()) the function func is called, and passed the series of integer (int) arguments that follow argc; the caller must specify the number of these arguments in argc.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;从官方的文档中我们可以看到，用在&lt;code&gt;setcontext&lt;/code&gt;中的函数，只支持int类型的参数，并且需要我们显式声明参数的数目。这里一定要小心，因为变长参数列表并不能有很强的编译期检查支持，搞出UB或core dump来就非常难查。&lt;/p&gt;
&lt;h3 id="ucontextuthreadstackmemory"&gt;ucontext中使用的栈内存：&lt;code&gt;UThreadStackMemory&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;ucontext协程是在同一个线程执行多个上下文，所以就要配备多个栈空间。这里的栈大小我们是可以手动管理的，所以我们可以根据程序的实际情况来调整栈大小，以节省内存使用。&lt;/p&gt;
&lt;p&gt;内存的申请并不是使用&lt;code&gt;malloc&lt;/code&gt;或者&lt;code&gt;new&lt;/code&gt;这种比较高层次的内存操作函数，而是使用的&lt;code&gt;mmap&lt;/code&gt;。这样的好处是我们可以使用参数控制申请出的内存的权限。&lt;/p&gt;
&lt;p&gt;栈内存有两种模式，保护和非保护。保护模式用于调试，会在正常栈内存的两端，各申请一个页大小的保护内存。正常栈内存的权限是读写：&lt;code&gt;PROT_READ | PROT_WRITE&lt;/code&gt;，而保护内存的权限是禁止访问：&lt;code&gt;PROT_NONE&lt;/code&gt;，也就是说，任何试图访问这块内存的请求，都会触发段错误。&lt;/p&gt;
&lt;p&gt;在非保护的运行模式下，栈内存还会使用&lt;code&gt;MAP_ANONYMOUS | MAP_PRIVATE&lt;/code&gt;还进行保护。&lt;code&gt;MAP_ANONYMOUS&lt;/code&gt;表明这段内存是匿名的，即不占用fd，也无需进行写回操作，使mmap的行为类似于malloc。&lt;code&gt;MAP_PRIVATE&lt;/code&gt;意为这段内存不会被其它进程访问，可以使用私有的写时复制映射。（虽然没找到相关资料，但是感觉这两个配置牺牲了可调试性来获取更好的性能）&lt;/p&gt;
&lt;h3 id="ucontextuthreadruntime"&gt;ucontext的运行时：&lt;code&gt;UThreadRuntime&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;这个类其实很简单，但是由于代码的命名过于意识流，所以很容易把人绕晕。&lt;/p&gt;
&lt;p&gt;一个&lt;code&gt;UThreadRuntime&lt;/code&gt;代表着一个线程中运行着的N个ucontext上下文。上下文信息保存在&lt;code&gt;std::vector&amp;lt;ContextSlot&amp;gt; context_list_&lt;/code&gt;中。&lt;/p&gt;
&lt;p&gt;slot是可以复用的，&lt;code&gt;first_done_item_&lt;/code&gt;记录着已执行完的context的下标，然后slot中的&lt;code&gt;next_done_item&lt;/code&gt;记录着下一个执行完的context的下标。简而言之，这就是类似一个“脏池”的设计。不过这个命名啊，一点都不赛艇。&lt;/p&gt;
&lt;p&gt;剩下的代码基本就是&lt;code&gt;UThreadContext&lt;/code&gt;的无脑封装了。需要哪个协程开始工作就&lt;code&gt;Resume&lt;/code&gt;哪个协程，需要暂停就调用&lt;code&gt;Yield&lt;/code&gt;。结束后，调用回调函数，把运行完的协程往脏池一扔，完活。&lt;/p&gt;
&lt;h2 id="_2"&gt;写在最后&lt;/h2&gt;
&lt;p&gt;上面我们分析了phxrpc对ucontext协程库的封装，下一篇，我们就来正式看一看ucontext是如何与IO多路复用的技术连接在一起的。&lt;/p&gt;
&lt;p&gt;最后上几张皂片：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-13/31415098.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-13/1208386.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-13/97556242.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-13/44196833.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-13/20763058.jpg"&gt;&lt;/p&gt;</content><category term="Blog"/><category term="phxrpc"/><category term="ucontext"/><category term="协程"/></entry><entry><title>打造你的专属键盘 — ErgoDone</title><link href="https://wizmann.top/ergodone.html" rel="alternate"/><published>2016-10-05T21:38:58+08:00</published><updated>2016-10-05T21:38:58+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2016-10-05:/ergodone.html</id><summary type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;低能预警：这是最没有技术含量的一篇博客，无关人员可以撤离。&lt;/p&gt;
&lt;p&gt;部分图片来自网络，侵删&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个十一假期，亲手DIY了一把键盘。当 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;低能预警：这是最没有技术含量的一篇博客，无关人员可以撤离。&lt;/p&gt;
&lt;p&gt;部分图片来自网络，侵删&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个十一假期，亲手DIY了一把键盘。当然，我只搞定了焊接部分，把不同的组件拼在了一起。&lt;/p&gt;
&lt;p&gt;在焊接的过程中，也学习到了一些新知识。写在这里，记录下来。&lt;/p&gt;
&lt;h2 id="ergodone"&gt;ErgoDone介绍&lt;/h2&gt;
&lt;p&gt;ErgoDone是著名开源硬件ErgoDox的中国特色版本，精简了一些硬件以控制成本。总体价格在500RMB左右，是工薪阶级装逼界的一颗新星。&lt;/p&gt;
&lt;p&gt;Ergodox的一个版本：&lt;br&gt;
&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-2/41980975.jpg"&gt;&lt;/p&gt;
&lt;p&gt;ErgoDone明显就屌丝了许多：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-5/28663395.jpg"&gt;&lt;/p&gt;
&lt;h2 id="_2"&gt;键盘主控&lt;/h2&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-2/32662639.jpg"&gt;&lt;/p&gt;
&lt;p&gt;ErgoDone使用了Arduino pro micro做为主控，基中使用了mega32u4做为芯片，提供了模拟USB输入设备的相关函数（包括键盘、鼠标）。网上有许多现成的范例，用这款芯片（以及另一版使用mega32u4的Arduino开发版，Arduino Leonardo）制作体感鼠标（搭配陀螺仪）、游戏摇杆（搭配相关硬件）以及各种专用输入设备。&lt;/p&gt;
&lt;p&gt;Arduino pro micro淘宝价不到20块钱，相对来说算是非常超值了。&lt;/p&gt;
&lt;h2 id="_3"&gt;焊接&lt;/h2&gt;
&lt;p&gt;由于本人算是菜的抠脚的业余选手，在这个键盘上的主要工作就是焊接。然而，就在焊接这样一件相对简单的工作上，我也是踩了不少坑。&lt;/p&gt;
&lt;h3 id="miniusbmicrousb"&gt;MiniUSB转MicroUSB&lt;/h3&gt;
&lt;p&gt;在ErgoDone的设计中，整块键盘的供电，都是通过MiniUSB线来完成的。然而，pro micro的接口是MicroUSB的，这里我们需要一个转换工作。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-2/388124.jpg"&gt;&lt;/p&gt;
&lt;p&gt;MiniUSB，俗称T口USB。其中有五颗线，代表供电，D+，D-，ID与接地。&lt;/p&gt;
&lt;p&gt;MicroUSB就是现在市面上绝大多数安卓手机的充电/数据接口。其中的线序与MiniUSB中的类似，只是多数情况下，我们不使用ID线。&lt;/p&gt;
&lt;p&gt;在焊接键盘的过程中，我们需要完成一个自制MicroUSB接口，把导线连接到MicroUSB头上去。这个任务相对难度高一些，不过我们也有偷懒的方式。&lt;/p&gt;
&lt;p&gt;因为MicroUSB线实在过于流行，现在无论谁手里都会有那么两三条。那么我们可以拆掉手机充电线的MicroUSB公头，把其中的线引出来，连到应该连的位置上，就可以正常的使用了。&lt;/p&gt;
&lt;p&gt;如果你的MicroUSB线是良心厂家出产的话，其中会有四颗线：红绿白黑。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;红：供电，5V&lt;/li&gt;
&lt;li&gt;绿：Data+&lt;/li&gt;
&lt;li&gt;白：Data-&lt;/li&gt;
&lt;li&gt;黑：接地&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在ErgoDone这里，我们不需要接地线也可以正常工作。然后在焊接的时候要注意线不要留的过长，否则会很难看（不要问我为什么知道）。&lt;/p&gt;
&lt;h3 id="_4"&gt;一些打磨工作&lt;/h3&gt;
&lt;p&gt;ErgoDone的两片键盘是通过3.5mm的音频线连接的，然后音频接口不出意料的比外壳预留的接口要厚一些。所以一些打磨工作是必须的。&lt;/p&gt;
&lt;p&gt;这里推荐打磨神器 —— 磨刀石。好的磨刀石有粗细两面，方便控制粒度，同时打磨的效率也比较高。如果真的啥都没有，可以强行试一波指甲钳上面的小挫。&lt;/p&gt;
&lt;h3 id="_5"&gt;卫星轴的安装&lt;/h3&gt;
&lt;p&gt;可以参考&lt;a href="http://tieba.baidu.com/p/3703634467"&gt;这篇帖子&lt;/a&gt;，上面已经说的很好了，我就不重复了。记得重要的一点是要把钢丝入扣，否则可能会卡键什么的。情况允许，还可以加一点润滑脂，让摩擦力小一点。&lt;/p&gt;
&lt;h3 id="_6"&gt;焊轴&lt;/h3&gt;
&lt;p&gt;焊轴相对是最简单的一步了，因为焊点的距离足够远，而且也足够大。只是注意别在焊盘上停留太多时间，把焊盘弄掉了就好。&lt;/p&gt;
&lt;h3 id="tdd"&gt;飞线与TDD&lt;/h3&gt;
&lt;p&gt;这两个放在一起写的原因是因为这两个技术都需要一样工具 —— 万用表。当然这里只是用来测连通性的，所以如果你愿意折腾，自己用发光二级管自己搞一把也不是不可以。&lt;/p&gt;
&lt;p&gt;如果我们操作不当，不小心把焊盘搞下来了，有什么方法可以补救呢。答案是飞线，就是不借助电路板上的电路，而是显式的用导线来导通某两个或多个管脚。&lt;/p&gt;
&lt;p&gt;ErgoDone由于是对称的两块，所以在焊崩了之后，可以依样找一个可用的焊盘来找可以飞线的焊点。如果手里只有一块板子而且情况不允许的话，就只好在焊之前，尤其是比较高难度的操作之前，先留好plan B，想想万一搞砸了有没有回滚方案（蛤）。&lt;/p&gt;
&lt;p&gt;TDD，又称测试驱动开发。就是在焊完一部分之后，立刻进行测试。比如集成电路或者主控，在焊完之后，一定要用万用表确认一下是不是有相临管脚短路的情况。在二极管焊完之后，用镊子测试一下是否可以触发相应的按键。&lt;/p&gt;
&lt;p&gt;一个半成品：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-2/35993621.jpg"&gt;&lt;/p&gt;
&lt;h2 id="_7"&gt;对键盘编程&lt;/h2&gt;
&lt;p&gt;这种DIY键盘的一大好处就是可以自定义配列，通过Fn键做一些很fancy的事情。比如触发组合键，或者是录制一些宏。对于程序员和一些游戏玩家来说，这个功能是非常吸引人的。&lt;/p&gt;
&lt;h3 id="_8"&gt;我的配列&lt;/h3&gt;
&lt;p&gt;默认层：http://www.keyboard-layout-editor.com/#/gists/a9278a768f78adf9d7b019b883678390&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-5/11486899.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Fn层：http://www.keyboard-layout-editor.com/#/gists/79ad8e6c4ac70cfad1ed400355e960a7&lt;/p&gt;
&lt;p&gt;右手的那堆Fn对应着0~9上面的符号&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-5/90976851.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Vim层：http://www.keyboard-layout-editor.com/#/gists/950dc52b3b27c24601661f2fd43a6d69&lt;/p&gt;
&lt;p&gt;模仿vim/bash映射了一些快捷键&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-5/92544582.jpg"&gt;&lt;/p&gt;
&lt;p&gt;魔改层：http://www.keyboard-layout-editor.com/#/gists/8bb13d2439c542a06d99e17fca3a234b&lt;/p&gt;
&lt;p&gt;用来魔改/创造一些不存在的键位和组合&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-5/28220231.jpg"&gt;&lt;/p&gt;
&lt;p&gt;食指多出来的四个键分别对应着四种括号&lt;code&gt;&amp;lt;&amp;gt;(){}[]&lt;/code&gt;。在编程中会比较常用到。&lt;/p&gt;
&lt;h3 id="_9"&gt;魔改举例&lt;/h3&gt;
&lt;p&gt;在食指的扩充键位中，我设计了一个不存在的键位组合：&lt;code&gt;&amp;lt;(&lt;/code&gt;和&lt;code&gt;&amp;gt;)&lt;/code&gt;。即在默认状态下，输入&lt;code&gt;()&lt;/code&gt;；在Shift状态下，输入&lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;。这种设计并没有直接的解决方案。对于圆括号的输入，我们可以使用组合键宏。而Shift输入尖括号，则需要一些技巧。&lt;/p&gt;
&lt;p&gt;幸好之前已经有人提出并解决了&lt;a href="https://github.com/tmk/tmk_keyboard/wiki/FAQ-Keymap#esc-and--on-a-key"&gt;类似的问题&lt;/a&gt;。简而言之，就是将Shift改成“Fn+Shift”，在按下Shift的同时，切换到一个新的层上。新的层上，我们可以用组合键宏输入尖括号。而剩下的键位，我们将其设置为透明。当你按下其它的键时，与平时按下Shift没有区别。&lt;/p&gt;
&lt;h2 id="_10"&gt;最终的代码&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Generated by TKG at 2016-10-05 22:35:43&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;keymap_common.h&amp;quot;&lt;/span&gt;

&lt;span class="cp"&gt;#define KEYMAP_TKG( \&lt;/span&gt;
&lt;span class="cp"&gt;    K0A, K0B, K0C, K0D, K0E, K0F, K0G, K0H, K0I, K0J, K0K, K0L, K0M, K0N, \&lt;/span&gt;
&lt;span class="cp"&gt;    K1A, K1B, K1C, K1D, K1E, K1F, K1G, K1H, K1I, K1J, K1K, K1L, K1M, K1N, \&lt;/span&gt;
&lt;span class="cp"&gt;    K2A, K2B, K2C, K2D, K2E, K2F,           K2I, K2J, K2K, K2L, K2M, K2N, \&lt;/span&gt;
&lt;span class="cp"&gt;    K3A, K3B, K3C, K3D, K3E, K3F, K3G, K3H, K3I, K3J, K3K, K3L, K3M, K3N, \&lt;/span&gt;
&lt;span class="cp"&gt;    K4A, K4B, K4C, K4D, K4E,                     K4J, K4K, K4L, K4M, K4N, \&lt;/span&gt;
&lt;span class="cp"&gt;         K5B, K5C, K5D, K5E, K5F, K5G, K5H, K5I, K5J, K5K, K5L, K5M  \&lt;/span&gt;
&lt;span class="cp"&gt;) { \&lt;/span&gt;
&lt;span class="cp"&gt;    { KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D, KC_##K0E, KC_##K0F, KC_##K0G, KC_##K0H, KC_##K0I, KC_##K0J, KC_##K0K, KC_##K0L, KC_##K0M, KC_##K0N }, \&lt;/span&gt;
&lt;span class="cp"&gt;    { KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_##K1E, KC_##K1F, KC_##K1G, KC_##K1H, KC_##K1I, KC_##K1J, KC_##K1K, KC_##K1L, KC_##K1M, KC_##K1N }, \&lt;/span&gt;
&lt;span class="cp"&gt;    { KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_##K2E, KC_##K2F, KC_NO,    KC_NO,    KC_##K2I, KC_##K2J, KC_##K2K, KC_##K2L, KC_##K2M, KC_##K2N }, \&lt;/span&gt;
&lt;span class="cp"&gt;    { KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_##K3F, KC_##K3G, KC_##K3H, KC_##K3I, KC_##K3J, KC_##K3K, KC_##K3L, KC_##K3M, KC_##K3N }, \&lt;/span&gt;
&lt;span class="cp"&gt;    { KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D, KC_##K4E, KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_##K4J, KC_##K4K, KC_##K4L, KC_##K4M, KC_##K4N }, \&lt;/span&gt;
&lt;span class="cp"&gt;    { KC_NO,    KC_##K5B, KC_##K5C, KC_##K5D, KC_##K5E, KC_##K5F, KC_##K5G, KC_##K5H, KC_##K5I, KC_##K5J, KC_##K5K, KC_##K5L, KC_##K5M, KC_NO    }  \&lt;/span&gt;
&lt;span class="cp"&gt;}&lt;/span&gt;

&lt;span class="cp"&gt;#ifdef KEYMAP_SECTION_ENABLE&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;keymaps&lt;/span&gt;&lt;span class="p"&gt;[][&lt;/span&gt;&lt;span class="n"&gt;MATRIX_ROWS&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;MATRIX_COLS&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__attribute__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.keymap.keymaps&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#else&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;keymaps&lt;/span&gt;&lt;span class="p"&gt;[][&lt;/span&gt;&lt;span class="n"&gt;MATRIX_ROWS&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;MATRIX_COLS&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROGMEM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KEYMAP_TKG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;GRV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;HOME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;BSPC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TAB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;LBRC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;RBRC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;BSLS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;J&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;SCLN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;QUOT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;FN3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;FN7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FN8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;COMM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;DOT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SLSH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;LCTL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;LGUI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;LALT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;DEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="n"&gt;MINS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;EQL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;F10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;F11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;F12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;\
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;LCTL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SPC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FN4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PSCR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;CAPS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PAUS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FN1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LGUI&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KEYMAP_TKG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;F2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;F3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;F4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;F5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;F6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;F7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;F8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;F9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;F10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;FN26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;VOLU&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;VOLD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MPRV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MPLY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MNXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KEYMAP_TKG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;PGUP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;INS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;HOME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;PGDN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;LEFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;DOWN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;UP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;RGHT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;DEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FIND&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KEYMAP_TKG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;FN9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FN10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;BSPC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;TRNS&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cp"&gt;#ifdef KEYMAP_SECTION_ENABLE&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn_actions&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__attribute__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.keymap.fn_actions&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#else&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn_actions&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PROGMEM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_LAYER_MOMENTARY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_LAYER_MOMENTARY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_LAYER_MODS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LGUI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_SPACE&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LGUI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_TAB&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_LAYER_TOGGLE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_9&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_COMMA&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_DOT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LCTL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOD_LALT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOD_LGUI&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_6&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_7&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_9&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ACTION_MODS_KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOD_LSFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KC_0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_11"&gt;成本统计&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PCB板 + 外壳 = 220 RMB （已加邮费）&lt;/li&gt;
&lt;li&gt;轴 + 平衡栏 + 灯 = 100 RMB （包邮）&lt;/li&gt;
&lt;li&gt;键帽 = 119RMB （包邮）&lt;/li&gt;
&lt;li&gt;合计：440RMB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总的看来，这个复刻版本，比国外动辄上百刀的版本更有吸引力。不过高大上程度还是略逊一筹。&lt;/p&gt;
&lt;p&gt;ErgoDone，让你重新定（学）义（习）打字。&lt;/p&gt;</content><category term="Blog"/><category term="ot"/><category term="ergodone"/><category term="keyboard"/></entry><entry><title>阻塞TCP流 - phxrpc代码阅读(3)</title><link href="https://wizmann.top/phxrpc-3.html" rel="alternate"/><published>2016-10-03T22:22:14+08:00</published><updated>2016-10-03T22:22:14+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2016-10-03:/phxrpc-3.html</id><summary type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;phxrpc的流（&lt;code&gt;stream&lt;/code&gt;和&lt;code&gt;streambuf&lt;/code&gt;）与网络访问其实是耦合在一起的，所以本文可以结合着第一篇笔记一起来看。虽然我非常想吐槽这种 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;phxrpc的流（&lt;code&gt;stream&lt;/code&gt;和&lt;code&gt;streambuf&lt;/code&gt;）与网络访问其实是耦合在一起的，所以本文可以结合着第一篇笔记一起来看。虽然我非常想吐槽这种强耦合性的设计，但是我决定还是好好理解phxrpc的设计之后。。。攒一波大的：）&lt;/p&gt;
&lt;h2 id="blocktcpstreambuf"&gt;BlockTcpStreamBuf&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;class BlockTcpStreamBuf&lt;/code&gt;继承自&lt;code&gt;BaseTcpStreamBuf&lt;/code&gt;。其中重写了&lt;code&gt;precv&lt;/code&gt;和&lt;code&gt;psend&lt;/code&gt;两个函数，并且持有了一个文件描述符(file descriptor)：&lt;code&gt;socket_&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;precv&lt;/code&gt;和&lt;code&gt;psend&lt;/code&gt;直接调用了&lt;code&gt;&amp;lt;sys/socket.h&amp;gt;&lt;/code&gt;中的&lt;code&gt;recv(2)&lt;/code&gt;和&lt;code&gt;send(2)&lt;/code&gt;，并没有其它操作。&lt;/p&gt;
&lt;p&gt;网络相关的操作，则由&lt;code&gt;class BlockTcpStream&lt;/code&gt;来负责。&lt;code&gt;BlockTcpStreamBuf&lt;/code&gt;只负责IO部分。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseTcpUtils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SetNonBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BaseTcpUtils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SetNoDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;phxrpc&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LOG_ERR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;set nonblock fail&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在&lt;code&gt;BlockTcpStream&lt;/code&gt;把fd传递给&lt;code&gt;BlockTcpStreambuf&lt;/code&gt;之前，需要把fd设置为&lt;code&gt;block&lt;/code&gt;的。而这段代码最大的槽点就是这个&lt;code&gt;SetNonBlock&lt;/code&gt;函数，和下面的&lt;code&gt;set nonblock fail&lt;/code&gt;日志（想一想）。完全让人摸不到头脑，达到一脸懵逼的最高境界。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-3/87163832.jpg"&gt;&lt;/p&gt;
&lt;p&gt;由于&lt;code&gt;recv&lt;/code&gt;和&lt;code&gt;send&lt;/code&gt;函数是&lt;code&gt;block&lt;/code&gt;的，所以在读取、写入缓冲区时，如果没有足够的数据可读或没有足够的空间可写，则读取写入操作会阻塞住。&lt;/p&gt;
&lt;h2 id="blocktcpstream"&gt;BlockTcpStream&lt;/h2&gt;
&lt;p&gt;在这里我又想吐个槽了，为啥在这里把TCP Server和Client的工作流混为一谈。我觉得至少应该从命名上区分一下，否则极容易误用。&lt;/p&gt;
&lt;h3 id="tcp"&gt;TCP的工作流程&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-3/92621506.jpg"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;图片来源：UNIX网络编程卷一：套接字编程 4.2节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;从图中我们可以看到，TCP的服务端与客户端的工作流程是不同的，相对来说，客户端的程序要简单一些。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;BlockTcpStream&lt;/code&gt;中，客户端应用的函数只有&lt;code&gt;BlockTcpUtils::Open&lt;/code&gt;，而服务端的&lt;code&gt;BlockTCPUtils::Listen&lt;/code&gt;函数包括了&lt;code&gt;bind()&lt;/code&gt;和&lt;code&gt;listen()&lt;/code&gt;两个操作，而&lt;code&gt;accept()&lt;/code&gt;则需要开发者手动调用。&lt;/p&gt;
&lt;h3 id="so_reuseaddr"&gt;SO_REUSEADDR&lt;/h3&gt;
&lt;p&gt;在服务端的&lt;code&gt;Listen()&lt;/code&gt;函数中，phxrpc使用了&lt;code&gt;SO_REUSEADDR&lt;/code&gt;选项，这个选项的意在通知内核：如果端口忙，但是TCP状态位于&lt;code&gt;TIME_WAIT&lt;/code&gt;时，可以重用端口。&lt;/p&gt;
&lt;p&gt;一个套接字其实是一个&lt;code&gt;（协议，源地址，源端口，目标地址，目标端口）&lt;/code&gt;五元组。&lt;code&gt;SO_REUSEADDR&lt;/code&gt;意味着我们可以重用源地址和源端口。当然此时的风险在于如果该原套接字发送了一些错误的数据，此时我们的应用程序的TCP工作流就会产生错乱。但是由于TCP的实现中，通过随机的消息序号规避了这个问题，所以这里的风险可以忽略不计。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;SO_REUSEADDR&lt;/code&gt;的好处是，在服务端程序崩溃和退出时（对于一般的服务端程序来说，崩溃和退出是没有区别的），可以立即重启，而不需要等待2MSL时间。&lt;/p&gt;
&lt;p&gt;那么我们要问了，为什么在这里我们需要等待2MSL时间呢。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-3/33186679.jpg"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;图片来源：Effective TCP/IP 3.8节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;TCP拆除连接使用了四次握手的机制，而主动关闭连接的一方在发送完最后一个ACK之后，需要等待2MSL的时间。这就是上面所说的，当服务器重启后，出现&lt;code&gt;Address already in use&lt;/code&gt;的报错信息，需要额外等待大约1~4分钟的原因。&lt;/p&gt;
&lt;p&gt;究其原因，TIME-WAIT状态的意图在于避免主动关闭连接的一端最后一个ACK发送失败。此时，主机1已经完全关闭，而主机2因为没有收到FIN包的ACK，处于半关闭状态。此时主机2向主机1发送的任何信息（如延迟的ACK包等）都只会收到RST，导致连接的异常关闭。&lt;/p&gt;
&lt;p&gt;为了规避这个问题，主动关闭端需要等待2MSL时间。一个MSL是给最后的ACK包，而另外一个MSL，是为了等待被动关闭端重新发送FIN包。如果在TIME_WAIT期间收到了对端的数据包，会刷新TIME_WAIT状态的时间。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;参考：Effective TCP/IP 3.8 3.9节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="iopoll"&gt;IO复用：Poll&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-3/84501111.jpg"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;图片来源：UNIX网络编程卷一：套接字编程 6.2节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;IO复用是指内核在发现进程指定的一个或多个IO条件就绪，内核就通知进程。通常来讲，常用的IO复用函数有&lt;code&gt;select()&lt;/code&gt;和&lt;code&gt;poll()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;当&lt;code&gt;poll()&lt;/code&gt;返回后，我们需要遍历其中的fd数组找到可操作的fd。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;pollfd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="cm"&gt;/* file descriptor */&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;short&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="cm"&gt;/* requested events */&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;short&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;revents&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* returned events */&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;我们可以从&lt;code&gt;events&lt;/code&gt;和&lt;code&gt;revents&lt;/code&gt;获得该fd的状态，从而判别可读、可写、超时或出错。&lt;/p&gt;
&lt;p&gt;在这里，我们并没有使用poll函数的IO复用能力，而是把它做为另一个阻塞IO调用来使用。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;BlockTcpUtils::Open&lt;/code&gt;函数中，我们使用了poll，用来监视相应的（一个）fd是否可读。这样一来，我们就隐式（为什么说隐式呢，因为他们一不写文档，二不写注释，一切都是潜规则）规定了C/S交互的基本工作流程：当C/S连接建立后，Server端要先说话，Client端接收到消息之后，才可以进行下面的流程。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Client：“不管你们信不信，是Server先动的手。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;具体为什么先用poll，再把fd设为&lt;code&gt;blocking&lt;/code&gt;的，我表示二脸懵逼。在我的实验中，即使把poll删掉，测试代码也是可以work的。可能在后面的代码阅读中，这个问题可以获得解释吧。&lt;/p&gt;
&lt;p&gt;和select一样，poll也存在被中断的情况，在phxrpc的代码里，我们给了中断“a second chance”。当poll被中断后，会重新再poll一次；如果这次再被中断，则直接返回TIMEOUT。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// retry again for EINTR&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timeout_ms&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EINTR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ETIMEDOUT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_2"&gt;写在最后&lt;/h2&gt;
&lt;p&gt;由于这篇文章中的知识点比较杂，写作的顺序也是随机的。所以连贯性不是那么强。如果有什么问题，忍着点吧您就。&lt;/p&gt;
&lt;p&gt;忍不了的话。。。那就留言交流吧~&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-10-3/42112021.jpg"&gt;&lt;/p&gt;</content><category term="Blog"/><category term="phxrpc"/><category term="tcpip"/><category term="poll"/><category term="socket"/></entry><entry><title>定时器以及其它 - phxrpc阅读笔记(2)</title><link href="https://wizmann.top/phxrpc-2.html" rel="alternate"/><published>2016-09-29T01:28:09+08:00</published><updated>2016-09-29T01:28:09+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2016-09-29:/phxrpc-2.html</id><summary type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;phxrpc使用了协程(ucontext)和IO复用技术(epoll)来实现网络通信。定时器在其中起到了非常重要的作用。下面我们就来分析一下phxrpc的&lt;code&gt;timer.[h|cpp]&lt;/code&gt;中的代码 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;phxrpc使用了协程(ucontext)和IO复用技术(epoll)来实现网络通信。定时器在其中起到了非常重要的作用。下面我们就来分析一下phxrpc的&lt;code&gt;timer.[h|cpp]&lt;/code&gt;中的代码。&lt;/p&gt;
&lt;h2 id="system_clock-vs-steady_clock"&gt;system_clock vs steady_clock&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;system_clock&lt;/code&gt;和&lt;code&gt;steadly_clock&lt;/code&gt;都是来自&lt;code&gt;&amp;lt;chrono&amp;gt;&lt;/code&gt;库，都是用来获取当前时间的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;system_clock&lt;/code&gt;用来从系统时钟获取时钟时间(wall clock time)，而&lt;code&gt;steadly_clock&lt;/code&gt;获取的是时钟tick，而且保证随着时间的推移，时钟tick数不会变小。&lt;/p&gt;
&lt;p&gt;然而实际上，在某些系统下，这两个时钟的实现是一致的。详细信息可以参考&lt;a href="http://stackoverflow.com/questions/13263277/difference-between-stdsystem-clock-and-stdsteady-clock"&gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：在clang++ 4.2.1, g++ 5.4 下实验，这两个时钟是不同的。所以个人认为在这里最好不要做任何无意义的假设。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_2"&gt;几毫秒的安睡&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Timer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MsSleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;time_ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;timespec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tv_sec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;time_ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tv_nsec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time_ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;nanosleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EINTR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这里phxrpc使用了&lt;code&gt;nanosleep&lt;/code&gt;实现了高精度的sleep。&lt;/p&gt;
&lt;p&gt;注意这里的用法，由于&lt;code&gt;nanosleep&lt;/code&gt;可能被信号中断，此时errno被设为&lt;code&gt;EINTR&lt;/code&gt;。所以我们需要进行额外的判断。当nanosleep被信号中断时，会把剩余时间写入第二个参数指向的&lt;code&gt;timespec&lt;/code&gt;变量中，之后我们再次调用&lt;code&gt;nanosleep&lt;/code&gt;，就可以把剩余的时间再睡一个回笼觉了。&lt;/p&gt;
&lt;h2 id="_3"&gt;可删除优先队列&lt;/h2&gt;
&lt;p&gt;这个设计一颗赛艇啊。&lt;/p&gt;
&lt;p&gt;对于&lt;code&gt;std::priority_queue&lt;/code&gt;以及大多数手写的优先队列（又称堆，heap）。一般只有&lt;code&gt;top()&lt;/code&gt;, &lt;code&gt;push()&lt;/code&gt;, &lt;code&gt;pop()&lt;/code&gt;这三个操作接口，如果想实现删除操作，大多数情况（为了偷懒）会把&lt;code&gt;std::priority_queue&lt;/code&gt;替换为&lt;code&gt;std::set&lt;/code&gt;。&lt;code&gt;std::set&lt;/code&gt;的内部实现是平衡树（确切的说，红黑树），可以实现获得最大最小值，查找某个值，以及删除某个值的操作。&lt;/p&gt;
&lt;p&gt;但是&lt;code&gt;std::priority_queue&lt;/code&gt;（或者用数组或vector实现的堆）是顺序容器(sequence containers)，而&lt;code&gt;std::set&lt;/code&gt;是关联容器(associative containers)。相对来说，由于cache的原因，顺序容器的性能比关联容器要好。当然我扯得有点远了。对此感兴趣的同学可以去参考《Effective STL》一书。&lt;/p&gt;
&lt;p&gt;在这里，我们的需求是这样的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;堆是小根堆，按超时时间增序&lt;/li&gt;
&lt;li&gt;堆中的元素是socket描述符&lt;code&gt;UThreadSocket_t&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;根据描述符，我们可以删除堆中的任意元素&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果我们有清醒的头脑，就会认为这个需求是不好实现的。删除堆中元素并不复杂，只需要将堆中最后一个元素放到被删除元素的位置上，然后再执行一次&lt;code&gt;heap_down()&lt;/code&gt;操作就可以了。问题在于我们很难确定某一个元素的具体位置。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;想一想，堆中的数据是如何组织的。如果想找到某一个特定的值，除了遍历之外，还有没有其它的方法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这里phxrpc使用了一种侵入式的手段，将下标写入堆中元素。然后堆外持有指针。然后在维护堆性质的时候，同步更新堆中元素，使其中保存的下标与其在堆中的下标一致。&lt;/p&gt;
&lt;p&gt;这样我们就可以通过指针拿到相应元素的下标，删除操作也变得简单了起来。&lt;/p&gt;
&lt;p&gt;那么侵入式堆下标有什么问题吗？一来我们对于元素的查找只能根据容器外持有的指针来进行，并不能像&lt;code&gt;std::set&lt;/code&gt;那样通过比较关系来查找。二来侵入式下标需要额外的内存空间，对于小型对象会造成可观比例的overhead。同时容器内只能持有元素指针，在某种程度上会带来额外的寻址开销。&lt;/p&gt;
&lt;p&gt;不过，这大概也是让堆支持删除的唯一方法了。&lt;/p&gt;
&lt;h2 id="_4"&gt;小小吐槽&lt;/h2&gt;
&lt;p&gt;这段代码写的，貌似耦合的太紧了一点。&lt;code&gt;class Timer&lt;/code&gt;内部提供的功能有&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;得到当前时间&lt;/li&gt;
&lt;li&gt;nanosleep&lt;/li&gt;
&lt;li&gt;封装&lt;code&gt;TimerObj&lt;/code&gt;类&lt;/li&gt;
&lt;li&gt;维护一个定时器堆，提供&lt;code&gt;top()&lt;/code&gt;, &lt;code&gt;push()&lt;/code&gt;, &lt;code&gt;pop()&lt;/code&gt;, &lt;code&gt;erase()&lt;/code&gt;功能，并且大多数操作都是硬编码的&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;至少在我看来，这并不符合“高内聚，低耦合”代码风格。&lt;/p&gt;
&lt;p&gt;你问我为啥不给改改？&lt;/p&gt;
&lt;p&gt;因为他们没写测试啊！&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-9-29/12309965.jpg"&gt;&lt;/p&gt;
&lt;h2 id="_5"&gt;补充&lt;/h2&gt;
&lt;p&gt;其实对于&lt;code&gt;class Timer&lt;/code&gt;，phxrpc是有写测试的(test_timer.cpp)。但是这个代码写的就更迷了。这里再分析一下。&lt;/p&gt;
&lt;p&gt;一开始，先创建100个timer，sleep时间随机。然后将50个timer放入&lt;code&gt;need_remove&lt;/code&gt;数组中。&lt;/p&gt;
&lt;p&gt;之后每删一个timer，就配套睡到超时时间pop一个timer。弹出超时timer后，再判断一下时间误差是否超过10ms，如果是，就报错。&lt;/p&gt;
&lt;p&gt;这。。。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-9-29/43591449.jpg"&gt;&lt;/p&gt;</content><category term="Blog"/><category term="RPC"/><category term="STL"/><category term="priority_queue"/><category term="C++"/><category term="phxrpc"/></entry><entry><title>自定义你的stream buffer - phxrpc阅读笔记(1)</title><link href="https://wizmann.top/phxrpc-1.html" rel="alternate"/><published>2016-09-28T22:35:55+08:00</published><updated>2016-09-28T22:35:55+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2016-09-28:/phxrpc-1.html</id><summary type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/tencent-wechat/phxrpc"&gt;phxrpc&lt;/a&gt;是微信团队开源的一个轻量级RPC框架。&lt;/p&gt;
&lt;p&gt;我对RPC这些东西了解不多，看到phxrpc的代码相对简单，而且还在初步开发阶段（在本文写作时，版本号是0.8）。所以想 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/tencent-wechat/phxrpc"&gt;phxrpc&lt;/a&gt;是微信团队开源的一个轻量级RPC框架。&lt;/p&gt;
&lt;p&gt;我对RPC这些东西了解不多，看到phxrpc的代码相对简单，而且还在初步开发阶段（在本文写作时，版本号是0.8）。所以想读一读，提高一下姿势水平。&lt;/p&gt;
&lt;p&gt;就是这样。&lt;/p&gt;
&lt;h2 id="stream-buffer"&gt;自定义stream buffer&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;network/socket_stream_base.[h|cpp]&lt;/code&gt;中的&lt;code&gt;class BaseTcpStreamBuf&lt;/code&gt;继承了&lt;code&gt;std::streambuf&lt;/code&gt;，自定义了一个流缓冲区，用于接收/发送TCP数据包。&lt;/p&gt;
&lt;p&gt;这个用法比较新颖（或者是我见识少），网上的资料也不多。这里翻译一篇&lt;a href="http://www.mr-edd.co.uk/blog/beginners_guide_streambuf"&gt;介绍文章&lt;/a&gt;，学习一下新姿势。&lt;/p&gt;
&lt;h2 id="a-beginners-guide-to-writing-a-custom-stream-buffer"&gt;A beginner&amp;rsquo;s guide to writing a custom stream buffer&lt;/h2&gt;
&lt;p&gt;流(streams)是STL中提供的一个重要的抽象概念。著名的“Hello world”程序，便是使用了std::cout将字符串写入标准输出流(stdout)。&lt;/p&gt;
&lt;p&gt;流当然可以做比cin/cout更有意思的事。这篇文章我们会研究如何扩展C++流，来实现自定义的流缓冲区(stream buffer)。p.s. 建议本文的读者至少要有基础的C++知识。&lt;/p&gt;
&lt;p&gt;C++标准库为磁盘文件操作提供了基础的接口，如&lt;code&gt;std::fstream&lt;/code&gt;，&lt;code&gt;std::ifstream&lt;/code&gt;和&lt;code&gt;std::ofstream&lt;/code&gt;。我们还有&lt;code&gt;stringstream&lt;/code&gt;，可以像流一样操作字符串。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostringstream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oss&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;oss&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Hello, world!&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;oss&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;\\&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;相似的，我们可以从&lt;code&gt;std::istringstream&lt;/code&gt;中使用&lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;操作符读取数据。&lt;/p&gt;
&lt;p&gt;Boost库中的&lt;code&gt;lexical_cast&lt;/code&gt;正是使用了这种机制，让用户可以使用统一的方式将一个对象(object)转换为字符串表示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;boost&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lexical_cast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexical_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;流缓冲区有着很强的灵活性，可以满足不同的“缓冲并传输字符（串）”需求，比如文件操作、字符串操作、命令行(Console)操作等。我们可以从网络、闪存(Flash memory)等不同设备，使用同样的接口获取流式字符串。“流缓冲区”与“流”是正交的，所以我们可以自由的交换、更改(swap and change)流所使用的缓冲区，或者将其重定向到其它地方。我认为C++中的流，正是“策略模式”(strategy design pattern)的一个良好范例。&lt;/p&gt;
&lt;p&gt;比如，我们可以重定向标准日志流&lt;code&gt;std::clog&lt;/code&gt;到一个字符串流：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iomanip&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;sstream&amp;gt;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostringstream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oss&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Make clog use the buffer from oss&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;streambuf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;former_buff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;clog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rdbuf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rdbuf&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;clog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;This will appear in oss!&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;\\&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Give clog back its previous buffer&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;clog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rdbuf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;former_buff&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;不过，自定义一个流缓冲区却是有一点tricky，或者说有一点吓人，尤其是当你第一次尝试的时候。所以本文意在提供一些流缓冲的实现范例。&lt;/p&gt;
&lt;p&gt;首先我们来看一下流缓冲区的一些基本概念。所有的流缓冲区继承自&lt;code&gt;std::streambuf&lt;/code&gt;，并且需要覆盖一些虚函数来实现自定义功能。&lt;code&gt;std::streambuf&lt;/code&gt;是“顺序读取设备”的一个抽象，即我们可以从中顺序的读取字符序列。在特定的场景下，我们可以重填(re-fill)、冲洗(flush)以及清空(empty)一个缓冲区。&lt;/p&gt;
&lt;p&gt;当我们向一个&lt;code&gt;ostream&lt;/code&gt;中插入数据时，数据将会被写入缓冲区中的一个数组。当数组上溢(overflow)时，数组中的数据将会被冲洗(flush)到目标接受者，之后这个数组的状态将会重置，以便存储后续的字符。&lt;/p&gt;
&lt;p&gt;当我们从一个&lt;code&gt;istream&lt;/code&gt;中获取数据时，数据从缓冲区的数组中读出。当数组下溢时(underflow)，没有数据可读，我们会从数据源重新拉取信息来填充缓冲区，之后这个数组的状态也将被重置。&lt;/p&gt;
&lt;p&gt;我们使用6个指针，来维护缓冲区的内部状态。输入和输出缓冲各使用3个指针。&lt;/p&gt;
&lt;h3 id="_2"&gt;维护输出缓冲区的状态&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;put base pointer   &lt;br&gt;
输出基指针，用来指定缓冲区内部数组的第一个元素。可以使用&lt;code&gt;std::streambuf::pbase()&lt;/code&gt;来获取&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;put pointer   &lt;br&gt;
输出指针，用来指向内部数组下一个写入的地址。可以使用&lt;code&gt;std::streambuf::pptr()&lt;/code&gt;来获取&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;end put pointer   &lt;br&gt;
输出哨兵指针，指向内部数组最后一个再后面一个(one-past-the-last-element)的地址（译注：类似&lt;code&gt;std::vector::end()&lt;/code&gt;）。可以使用&lt;code&gt;std::streambuf:epptr()&lt;/code&gt;来获取&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="http://i1.piimg.com/567571/630a89fe635e1635.png"&gt;&lt;/p&gt;
&lt;p&gt;一般来说，基指针和哨兵指针不会改变，在使用时，以输出指针维护内部状态。&lt;/p&gt;
&lt;h3 id="_3"&gt;维护输入缓冲区的状态&lt;/h3&gt;
&lt;p&gt;输入缓冲区和状态维护和输出缓冲区类似，我们有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;end back pointer  &lt;br&gt;
输入基指针，指向缓冲区数组内的最后一个字符。可以使用&lt;code&gt;std::streambuf::eback()&lt;/code&gt;来获取&lt;/li&gt;
&lt;li&gt;get pointer   &lt;br&gt;
输入指针，指向缓冲区下一个读取的字符地址。可以使用&lt;code&gt;std::streambuf::gptr()&lt;/code&gt;来获取&lt;/li&gt;
&lt;li&gt;end get pointer    &lt;br&gt;
输入哨兵指针，批号向内部数组最后一个再后面一个(one-past-the-last-element)的地址。可以使用&lt;code&gt;std::streambuf::egptr()&lt;/code&gt;来获取&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/16-9-27/33500590.jpg"&gt;&lt;/p&gt;
&lt;p&gt;同样，基指针和哨兵指针在流缓冲区的生命周期中也不会改变。&lt;/p&gt;
&lt;p&gt;由于输入缓冲区要支持&lt;code&gt;putback()&lt;/code&gt;操作，即将读出的字符重新放回缓冲区，所以输入缓冲区比输出缓冲区更复杂一点。通常来说，&lt;code&gt;putback()&lt;/code&gt;操作支持放回一个字符即可。&lt;/p&gt;
&lt;p&gt;一个&lt;code&gt;std::streambuf&lt;/code&gt;可以同时支持输入输出两种操作，所以我们不需要我分别实现&lt;code&gt;std::istreambuf&lt;/code&gt;和&lt;code&gt;std::ostreambuf&lt;/code&gt;。&lt;code&gt;std::fstream&lt;/code&gt;是一个良好的例子。但是，实现一个全功能的缓冲区相对更复杂一些，所以我就不趟浑水啦~ ：）&lt;/p&gt;
&lt;p&gt;同时，流缓冲区也可以支持宽字符(wide character)。&lt;code&gt;std::streambuf&lt;/code&gt;是&lt;code&gt;std::basic_streambuf&amp;lt;char&amp;gt;&lt;/code&gt;的别名，如果你需要宽字符流缓冲区，可以使用&lt;code&gt;std::basic_streambuf&amp;lt;wchar_t&amp;gt;&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="1-c"&gt;例1：文件缓冲区 —— 与C代码集成&lt;/h3&gt;
&lt;p&gt;假设我们需要调用一个历史悠久的库，一个文件操作函数会返回给一个&lt;code&gt;FILE*&lt;/code&gt;指针，但是我们想用C++的流接口来读写数据。我们先从读文件开始，用&lt;code&gt;std::istream&lt;/code&gt;包装&lt;code&gt;FILE*&lt;/code&gt;的读操作。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;streambuf&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;FILE_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;streambuf&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;explicit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buff_sz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put_back&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// overrides base class underflow()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;underflow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// copy ctor and assignment not implemented;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// copying not allowed&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;FILE_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;FILE_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILE_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fptr_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put_back_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buffer_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;由于功能简单，我们只需要实现构造函数以及&lt;code&gt;underflow&lt;/code&gt;接口就可以实现我们的功能。&lt;/p&gt;
&lt;p&gt;构造函数指定了读取文件的&lt;code&gt;FILE*&lt;/code&gt;指针，以及内部缓冲数组的大小。数组大小由两个参数决定：&lt;br&gt;
* put-back area size       &lt;br&gt;
* buffer size&lt;/p&gt;
&lt;p&gt;我们使用&lt;code&gt;std::vector&amp;lt;char&amp;gt;&lt;/code&gt;做为缓冲区域。&lt;code&gt;put_back_&lt;/code&gt;变量用于存储&amp;rdquo;put-back&amp;rdquo;区域的大小。&lt;/p&gt;
&lt;p&gt;以下是构造函数的实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;FILE_buffer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FILE_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buff_sz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put_back&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;fptr_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fptr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;put_back_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;put_back&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;buffer_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buff_sz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put_back_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put_back_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buffer_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buffer_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;setg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在初始化列表中，我们将缓冲区的常量进行赋值。之后使用&lt;code&gt;std::streambuf::setg()&lt;/code&gt;来初始化输出缓冲区。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;setg()&lt;/code&gt;的三个参数分别代表&lt;code&gt;eback()&lt;/code&gt;，&lt;code&gt;gptr()&lt;/code&gt;，&lt;code&gt;egptr()&lt;/code&gt;三个内部指针的值。一开始，我们将它们都指向同一个地址。表明buffer是空的，在下一次读取时，会重新填充缓冲区。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;underflow()&lt;/code&gt;会返回数据源中当前的字符。一般来说，会返回buffer中的下一个可用字符。然后当buffer为空时，&lt;code&gt;underflow()&lt;/code&gt;应该重新填充缓冲区数组，在本例中，即从&lt;code&gt;FILE*&lt;/code&gt;中读取字符。当缓冲区重填后，我们需要再次调用&lt;code&gt;setg()&lt;/code&gt;更新流缓冲区的状态。&lt;/p&gt;
&lt;p&gt;当数据源中的数据读完(depleted)后，&lt;code&gt;underflow()&lt;/code&gt;会返回一个&lt;code&gt;traits_type::eof()&lt;/code&gt;。这里要注意，&lt;code&gt;underflow()&lt;/code&gt;的返回值是&lt;code&gt;int_type&lt;/code&gt;，这个值足够装下&lt;code&gt;eof()&lt;/code&gt;，同时也足够装下任何的字符。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;streambuf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;FILE_buffer::underflow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gptr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;egptr&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// buffer not exhausted&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_int_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gptr&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buffer_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// true when this isn&amp;#39;t the first fill&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Make arrangements for putback characters&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;memmove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;egptr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put_back_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put_back_&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put_back_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// start is now the start of the buffer, proper.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Read from fptr_ in to the provided buffer&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;fread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buffer_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fptr_&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Set buffer pointers&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;setg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_int_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gptr&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;函数的第一行，首先判断buffer是否耗尽。如果否，则返回当前字符，即&lt;code&gt;*gptr()&lt;/code&gt;。如果是，则进行重填(re-fill)操作。&lt;/p&gt;
&lt;p&gt;回想一下我们在构造函数中的实现，三个状态指针全都指向缓冲区的末尾。如果我们调用&lt;code&gt;underflow()&lt;/code&gt;时，发现状态指针并非如此，则说明缓冲区已经被填充了至少一次。&lt;/p&gt;
&lt;p&gt;现在我们考虑重填操作，我们&lt;code&gt;memmove&lt;/code&gt;最后&lt;code&gt;put_back_&lt;/code&gt;个字符到buffer的末尾，用做&amp;rdquo;put-back area&amp;rdquo;。（我们不用&lt;code&gt;memcopy&lt;/code&gt;因为我们的buffer比较小，`memmove()的效率会更高一些）&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;译注：实际上，&lt;code&gt;memcopy&lt;/code&gt;与&lt;code&gt;memmove&lt;/code&gt;各有所长。&lt;code&gt;memcopy&lt;/code&gt;不需要判断内存overlap的情况，即如果源区间与目标区间有重叠，那么得到的结果会是错的。而&lt;code&gt;memmove&lt;/code&gt;由于是移动语义，所以在移动步长较小时，可以只操作cache。所以二者各有所长，要根据具体情况判断优劣。Stackoverflow上有更详细的&lt;a href="http://stackoverflow.com/questions/28623895/why-is-memmove-faster-than-memcpy"&gt;讨论&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们处理完&amp;rdquo;put-back area&amp;rdquo;之后，就可以使用&lt;code&gt;fread()&lt;/code&gt;函数来重填缓冲区了。如果读不到数据，则意味着文件已经读到了结尾（当然这是一种简化情况，但在现实中99.9%的读取失败都是因为文件结束）。&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;fread()&lt;/code&gt;成功读取数据之后，我们通知streambuf更新内部的三个状态指针。之后返回buffer当前的指针。&lt;/p&gt;
&lt;p&gt;这就是我们的流缓冲区的基本实现，希望这并不是太难。当然我们还可以添加更多的功能。特别的是我们可以在缓冲区里面进行查找。如果你想实现它的话，可以试试重写&lt;code&gt;std::streambuf::seekoff()&lt;/code&gt;和&lt;code&gt;std::streambuf::seekpos&lt;/code&gt;虚成员函数。&lt;/p&gt;
&lt;p&gt;我们也可以实现写缓冲区。不过，在你们读完第三个例子之后，你们就可以轻松愉快的实现自己的版本了，不骗你。&lt;/p&gt;
&lt;h3 id="2"&gt;例2：读取内存中的数组&lt;/h3&gt;
&lt;p&gt;本例中，我们要使用&lt;code&gt;std::istream&lt;/code&gt;包装内存中的一个只读数组，并且格式化的进行读入。这个例子和上一个例子有一点不同的是，我们并不需要一个真正的缓冲数组，从源数组一次性读取就好了。&lt;/p&gt;
&lt;p&gt;想象中的实现是这个样式儿的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;char_array_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;streambuf&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;setg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;underflow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;gptr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;egptr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_int_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gptr&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;但是，这并没有什么卵用。因为&lt;code&gt;setg()&lt;/code&gt;函数只接受非常量(non-const)指针参数。这显而易见，如果一个缓冲区不可写，我们就不能提供&amp;rdquo;put-back&amp;rdquo;功能。所以我们要动一动手脚，重新实现一下这个类。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;streambuf&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;char_array_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;streambuf&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;explicit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;underflow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;uflow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;pbackfail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;streamsize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;showmanyc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// copy ctor and assignment not implemented;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// copying not allowed&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;begin_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在这个版本中，我们重写了几个私有函数，这些函数都是从&lt;code&gt;std::streambuf&lt;/code&gt;继承而来。&lt;/p&gt;
&lt;p&gt;第一个构造函数需要用户指定起止指针，而第二个构造函数只需要指定起始指针，之后我们会调用&lt;code&gt;std::strlen()&lt;/code&gt;来判断字符串的大小。&lt;/p&gt;
&lt;p&gt;我们使用&lt;code&gt;uflow()&lt;/code&gt;, &lt;code&gt;pbackfail()&lt;/code&gt;和&lt;code&gt;showmanyc()&lt;/code&gt;来维护缓冲区内部的状态，而不是调用&lt;code&gt;setg()&lt;/code&gt;，因为buffer并不可写。&lt;/p&gt;
&lt;p&gt;在这个版本中，我们要手动维护&lt;code&gt;eback&lt;/code&gt;, &lt;code&gt;gptr&lt;/code&gt;, &lt;code&gt;egptr&lt;/code&gt;三个指针。在构造函数中，我们将对其进行赋值。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;char_array_buffer.hpp&amp;quot;&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;functional&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cassert&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;begin_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;current_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;begin_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;less_equal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;begin_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;begin_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;begin_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;current_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;begin_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;之前我们使用&lt;code&gt;underflow()&lt;/code&gt;来获取当前字符，但这次我们需要使用&lt;code&gt;uflow()&lt;/code&gt;。因为&lt;code&gt;uflow()&lt;/code&gt;需要同时执行两步操作，一是获取当前字符，二是让&lt;code&gt;gptr()&lt;/code&gt;前进一步。但是又因为缓冲区由我们手动管理，&lt;code&gt;std::streambuf&lt;/code&gt;并不能正确的执行管理操作。所以我们需要重写&lt;code&gt;uflow()&lt;/code&gt;而不是&lt;code&gt;underflow()&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;char_array_buffer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;char_array_buffer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;uflow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;to_int_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;current_&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;下一步我们还要实现&lt;code&gt;pbackfail()&lt;/code&gt;。当我们调用&lt;code&gt;std::istream::unget()&lt;/code&gt;或&lt;code&gt;std::istream::putback(ch)&lt;/code&gt;时，我们会把已经读出的数据写回数组中。但是由于数组是只读的，所以我们只能模拟这种操作。&lt;/p&gt;
&lt;p&gt;在默认的实现中&lt;code&gt;pbackfail()&lt;/code&gt;只会返回&lt;code&gt;traits_type::eof()&lt;/code&gt;，而在我们的版本中，如果写回成功，将会返回写回的字符，不成功返回eof。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;char_array_buffer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;char_array_buffer::pbackfail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;begin_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current_&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_int_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*--&lt;/span&gt;&lt;span class="n"&gt;current_&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在&lt;code&gt;FILE_buffer&lt;/code&gt;中，我们也可以考虑重写&lt;code&gt;pbackfail()&lt;/code&gt;，来提供反向查找以及（用前面的数据）重填buffer的功能。&lt;/p&gt;
&lt;p&gt;最后一个重写的函数是&lt;code&gt;showmanyc()&lt;/code&gt;，这个函数被&lt;code&gt;std::streambuf::in_avail()&lt;/code&gt;调用，以判断当前有多少个字符可以返回。由于我们接管了状态指针，所以这个函数也要我们自己来实现啊。（译者：为什么要给自己找麻烦。。。）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;streamsize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;char_array_buffer::showmanyc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;less_equal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;current_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;由此可见，本例中的buffer比前面的要复杂一点点。这是因为我们接管了状态维护的工作。这使得我们更好的理解了&lt;code&gt;std::streambuf&lt;/code&gt;内部是如何工作的。&lt;/p&gt;
&lt;h3 id="3"&gt;例3：句首变大写的缓冲区&lt;/h3&gt;
&lt;p&gt;本例中我们将要实现一个将句首字符变大写的buffer。当然我们只考虑最基本的情况，移植到不同的区域和语言，其实是很琐碎的事情。（译者：文字编码坑的亲妈都不认了）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;streambuf&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iosfwd&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;caps_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;streambuf&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;explicit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;caps_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buff_sz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;protected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;do_caps_and_flush&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// copy ctor and assignment not implemented;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// copying not allowed&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;caps_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;caps_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;caps_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;caps_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cap_next_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sink_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buffer_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这里我们需要重写&lt;code&gt;overflow()&lt;/code&gt;和&lt;code&gt;sync()&lt;/code&gt;函数。&lt;code&gt;overflow()&lt;/code&gt;在输入缓冲区满的时候被调用，并且在成功时返回任意非eof的值。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sync()&lt;/code&gt;的作用是把当前的buffer写入目标，即使当前buffer并未填满。&lt;code&gt;std::flush()&lt;/code&gt;会调用&lt;code&gt;sync()&lt;/code&gt;函数，当失败时返回-1。&lt;/p&gt;
&lt;p&gt;我们编写一个辅助函数&lt;code&gt;do_caps_and_flush()&lt;/code&gt;，用来将小写变大写，并写入&lt;code&gt;sink_&lt;/code&gt;输出流。我们再声明一个哨兵变量&lt;code&gt;cap_next_&lt;/code&gt;来标识下一个字符是否需要小写变大写。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;caps_buffer.hpp&amp;quot;&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cctype&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;ostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;functional&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cassert&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;caps_buffer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;caps_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ostream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buff_sz&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cap_next_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sink_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;buffer_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buff_sz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sink_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buffer_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;setp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buffer_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// -1 to make overflow() easier&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;buffer_&lt;/code&gt;的最小可能大小是1，同时我们也只需要维护两个指针，因为这里不需要像输入缓冲区一样的维护&amp;rdquo;put-back area&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;我们把&lt;code&gt;buffer_&lt;/code&gt;的大小设成&lt;code&gt;buff_sz + 1&lt;/code&gt;，这样是为了&lt;code&gt;overflow()&lt;/code&gt;被调用时，我们有一个额外的空间存储当前的字符。最后将缓冲区数组和最后一个字符一起刷新到&lt;code&gt;ostream&lt;/code&gt;中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;caps_buffer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;caps_buffer::overflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sink_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;less_equal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;pptr&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;epptr&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pptr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;pbump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;do_caps_and_flush&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traits_type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;第一步是把ch写入&lt;code&gt;buffer_&lt;/code&gt;，并且使用&lt;code&gt;pbump(1)&lt;/code&gt;将&lt;code&gt;pptr()&lt;/code&gt;向前移一位。之后调用&lt;code&gt;do_caps_and_flush()&lt;/code&gt;做一些脏活，之后返回一个字符声明调用成功。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sync()&lt;/code&gt;的实现也非常简单:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;caps_buffer::sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;do_caps_and_flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;我们再看一看&lt;code&gt;do_caps_and_flush()&lt;/code&gt;函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;caps_buffer::do_caps_and_flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pbase&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pptr&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;cap_next_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;isalpha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cap_next_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;toupper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;cap_next_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;ptrdiff_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pptr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pbase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;pbump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sink_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pbase&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;对于本例来说，内部的缓冲区并非必要，我们可以一个字符一个字符把数据发到&lt;code&gt;sink&lt;/code&gt;中。但是我的观点是一个内部buffer仍有其用处。&lt;/p&gt;
&lt;h3 id="boost-iostreams"&gt;介绍 Boost IOStreams 库&lt;/h3&gt;
&lt;p&gt;如果你是流缓冲区的新手，希望你已经对它有一点点了解了。本文中的例子都非常基础，但是你可以用它们做更多有意思的事情。但是当我实现更复杂的流缓冲区时，问题的复杂度却上升的很快。这时我发现了&lt;code&gt;Boost IOStreams&lt;/code&gt;库，它为更复杂的缓冲区和流提供了必要的框架支持。&lt;/p&gt;
&lt;p&gt;它允许你解耦数据源，数据输出，过滤器以及其它一些概念。在我们的最后一个例子中，我们硬编码数据输出到&lt;code&gt;std::ostream&lt;/code&gt;中。如果我们要输出到一个没有流接口的类呢？&lt;code&gt;Boost IOStreams&lt;/code&gt;库提供了更多的灵活性，将一坨紧耦合的代码分解成独立的抽象概念。&lt;/p&gt;
&lt;h3 id="_4"&gt;扩展阅读&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The C++ Standard Library by Nicolai M. Josuttis&lt;/li&gt;
&lt;li&gt;The C++ Standard, BS ISO/IEC 14882:2003 (Second Edition)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.dinkumware.com/manuals/"&gt;Dinkum Compleat Reference online&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="System Design"/><category term="RPC"/><category term="streambuf"/><category term="C++"/><category term="phxrpc"/></entry><entry><title>Code Golf - Heapify</title><link href="https://wizmann.top/code-golf-heapify.html" rel="alternate"/><published>2015-08-01T00:00:00+08:00</published><updated>2015-08-01T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2015-08-01:/code-golf-heapify.html</id><content type="html">&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;heapify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;nth_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can implement a &amp;ldquo;heapify&amp;rdquo; by only four lines of code. And the time complexity is &lt;code&gt;O(n)&lt;/code&gt;.&lt;/p&gt;</content><category term="Blog"/><category term="code golf"/></entry><entry><title>Using Set Cover to Optimize a Large-Scale Low Latency Distributed Graph</title><link href="https://wizmann.top/using-set-cover-algorithm-to-optimize-a-large-scale-low-latency-distributed-graph.html" rel="alternate"/><published>2015-07-26T22:48:33+08:00</published><updated>2015-07-26T22:48:33+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2015-07-26:/using-set-cover-algorithm-to-optimize-a-large-scale-low-latency-distributed-graph.html</id><summary type="html">&lt;h2 id="background"&gt;Background&lt;/h2&gt;
&lt;p&gt;Linkedin (or other social networks, such as Facebook and G+) use the &amp;ldquo;social graph information&amp;rdquo; to show the social relationship between you and other members.&lt;/p&gt;
&lt;p&gt;Such as, &amp;ldquo;You and Mr.Obama share 10 mutual friends&amp;rdquo; or &amp;ldquo;You have 1,000 second-degree connections&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;This feature is very common for a …&lt;/p&gt;</summary><content type="html">&lt;h2 id="background"&gt;Background&lt;/h2&gt;
&lt;p&gt;Linkedin (or other social networks, such as Facebook and G+) use the &amp;ldquo;social graph information&amp;rdquo; to show the social relationship between you and other members.&lt;/p&gt;
&lt;p&gt;Such as, &amp;ldquo;You and Mr.Obama share 10 mutual friends&amp;rdquo; or &amp;ldquo;You have 1,000 second-degree connections&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;This feature is very common for a social network. But where does it come from?&lt;/p&gt;
&lt;h2 id="basic-api-for-social-graph-information"&gt;Basic API for Social Graph Information&lt;/h2&gt;
&lt;p&gt;The information about a social relationship can be get from three basic APIs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get Connections&lt;br&gt;
&amp;ldquo;Who does member X know?&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Get Shared Connections&lt;br&gt;
&amp;ldquo;Who do I know in common with member Y?&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Get Graph Distance&lt;br&gt;
&amp;ldquo;What the graph distance between member Z and me?&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="main-components-for-the-system"&gt;Main Components for the System&lt;/h2&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/15-7-25/59618247.jpg"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Graph Database (Graph DB)&lt;/li&gt;
&lt;li&gt;Distributed Network Cache (NCS)&lt;/li&gt;
&lt;li&gt;Graph APIs&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="basic-algorithm-for-social-graph"&gt;Basic Algorithm for Social Graph&lt;/h2&gt;
&lt;p&gt;Because the problems of social graph share the same essence. Here we just talk about the &amp;ldquo;Graph Distance&amp;rdquo; problem.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/15-7-25/24130302.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;Graph DB&lt;/em&gt; stores all the relationship of the members. When we ask for the information of &lt;em&gt;second degree creation&lt;/em&gt;,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Firstly, the web server communicate with GraphDB to get all the 1st degree connections&lt;/li&gt;
&lt;li&gt;Secondly, web server communicate to GraphDB again to get all the 2nd degree connections&lt;/li&gt;
&lt;li&gt;At last, the web server will merge all the results from the GraphDB to make it sorted and unique.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To make the retrieval more effectively, we add a cache level called &lt;em&gt;NCS&lt;/em&gt; to cache the result we get from the GraphDB.&lt;/p&gt;
&lt;h2 id="the-disadvantages-of-the-basic-algorithm"&gt;The Disadvantages of the Basic Algorithm&lt;/h2&gt;
&lt;p&gt;As we know, for a distributed system, there are shards, replica and load balancer to handle large amount of data and queries.&lt;/p&gt;
&lt;p&gt;Consider this scenario.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/15-7-25/4544395.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Two queries are both ask for the data from shard 1 and shard 2.&lt;/p&gt;
&lt;p&gt;The first query (the green one) has to communicate with the database twice, and then do the merging to get the final results.&lt;/p&gt;
&lt;p&gt;And the second query (the red one) only has to talk to database once. And no de-duplicate is needed, because there&amp;rsquo;s definitely no duplicate data in one single node of the database.&lt;/p&gt;
&lt;p&gt;We can make a conclusion that if we have a &lt;strong&gt;wise&lt;/strong&gt; load balancer, we can optimize our retrieval logic remarkably.&lt;/p&gt;
&lt;h2 id="set-cover-problem"&gt;Set Cover Problem&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Given a set of elements {1,2,&amp;hellip;,m} (called the universe) and a set S of n sets whose union equals the universe, the set cover problem is to identify the smallest subset of S whose union equals the universe. (Wikipedia)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This problem is similar to ours. The optimal algorithm for a load balancer is to find the minimal subsets of all sets which union equals to the ones that asked by the query input.&lt;/p&gt;
&lt;p&gt;It seems that we find the key to our problem. But this is NP-complete. There is no effective way to find the optimal solution.&lt;/p&gt;
&lt;p&gt;However, in practice, a greedy algorithm will actually do the trick. The rule of the greedy algorithm is to find the set which contains largest number uncovered elements.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/15-7-26/80102455.jpg"&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We finally find out that the social information and the relationship graph is &lt;strong&gt;not that difficult&lt;/strong&gt;. The basic concepts are quite easy. And the main work for the whole system is to use the cache to reduce the amount of calculation on the fly.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/15-7-26/65691084.jpg"&gt;&lt;/p&gt;
&lt;h2 id="reference"&gt;Reference&lt;/h2&gt;
&lt;p&gt;This post is mainly based on this &lt;a href="https://www.usenix.org/conference/hotcloud13/workshop-program/presentations/wang"&gt;video&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.usenix.org/sites/default/files/conference/protected-files/wang_hotcloud13_slides.pdf"&gt;Slides&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Special thanks to Linkedin for the sharing. :)&lt;/p&gt;</content><category term="Blog"/><category term="System Design"/><category term="Linkedin"/><category term="Social Network"/></entry><entry><title>Workflowy full notes</title><link href="https://wizmann.top/workflowy-full-notes.html" rel="alternate"/><published>2015-05-22T09:51:47+08:00</published><updated>2015-05-22T09:51:47+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2015-05-22:/workflowy-full-notes.html</id><summary type="html">&lt;p&gt;Recently, I&amp;rsquo;m becoming a crazy fan of &lt;a href="workflwoy.com"&gt;workflowy&lt;/a&gt; because its ability to build a personal wiki concisely.&lt;/p&gt;
&lt;p&gt;However, there&amp;rsquo;s only one thing bothers me that workflowy hide all the notes as the screenshot below, and it annoys me a lot.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXsAAAA+CAYAAADK3LtgAAAgAElEQVR4Ae2dD1BUV5b/PzEmTTKZZjIundGhDcY2xGk1DkoMxDiwI0pFDRk1+FMWS/nhjiRUicuvhMVSSjdSurWUpIIhKxbZSGGU0TGM7obEHXGdCGMCvY7Q44y0OtKME7onE7snCf0S4/3V7dd/HtAY4r8wyXtV3e++++4959zvve/cc8+97z7E1/Do/VCIRzuEuDxY2T4TYsF7Qhz4RIh/ahMi7Q9C9AbSHrYL8U+ecMbej4T450tCvHdeiMV/DsQrQpz2CnH6AyFmtQlxwCPE6Y/CNN5XwvllqOaUEP/wYd+4XiUg3+dCbLcJ8YhNiLRTQsyyCTH6tBB7OoRIOy/Ee5+o+Xo/75v/9HkhRr+n5pH5gr8Z7wkx42LftOIzIf5vmxD//ZkQ4nMhauxCPHpKiH/+oxDbO4RY/H6/9J8L8U82IWouCbH9z0LUnBZilobmxYtCxNkD5f1ciH+2CbHHp9L+vcRF85N10OsR4tHTEepDUfP259/7gRCPnBaiv1j9pBzy5VfaHj4TYvEpIU7L+tOGtdL7hEizqWnecwgx+qQQaWeE2OMRQtb79lNCbP9IiN9/KMT7gXYg2+Mmef8jIf7BJsR3TwrxDw4hfuUTQrYNWV+9GrpadgPCnwgx65QQv+/XxvzptPUr5T8pxKM2IWbYhIg7qbapAfX7uRDPvSfEd9uEeC8Szf4CaNrnxUtCPGIX4vLnQlRJHm1CzGjr+0wKTbkkb9nmD8tnTuY5LcSMsxHamobn7y/2bc+aW/6gbO//7BVCtvO0P2ruSr4BnIJ1Iu/+9xkh0i6p6S57hEh7T4hNHwhx2as+d/I5DukibRvQhjVstOXzR8vnUeoZWUafEM/ZhHjufSEWyLj3hZhxWoj/ls+f5tCW8XCHEAtcQozkm3ZchVfPQivQ/jtYOgrKTKBcAUbAjx+BHwO+qxA1AqK+BWXfgvYLGqDuhsl3AwoY7oAJ98HkEeH7D8h7X3BE3Q1RwTQjYM3DsPoe8Hkh5aJ6Y8IomH4PcAXy22HFZJipqbFJY+DtMUEi6vlsF6zqG4VPino1EDkCVv4Apv8JsrvACUy7G94xwkzJK3h8Duvfh9X3wYufQa3kI2mMgPaPINoQTKg5j4CHv625DgQlln2OK/COG/71j+AbBT97QL3ruQLRI6HjQzDcC9F9Mt2ii9vQHhQfzG0FCZl3JGwMFiWAp+djcI0E0wiINsP58Zq2ocHu4e8EMl6FVi94RkHUXfB/HoTK70B0oA2eDdK/2eeR8LPHBhIdUL/A9Hthr08t88AcA2Nk+/QpsP5PMOEuePYsRAtY+hCsuVfFQ7bj0DMj27QC+Q6Y8CDMCzxzq+Oh9TTk/gl+NrofnwDeCOCOfvciXBoMoFyCx3vCNw339JVBPpv/8REsfFBNE30vlI2BZzvhRWDS30H19/u25S/THsKcwfNXmHMBxpqhchRk/hFMo6AeyGyHLiuslDpEljNQRt+n8B+98JP7QKM6tGS/vmHfR/Afn8EvpoLxQ/iXS/Ds++CNUOSf/gDK+iuvK5DbDq2f+3U9rs/haZtamRO+H6GBRaAbMeoKVLTDvytgjoFJd8GLDpgaUNTRRpgsa6sXnraH+Y/r7ktNEapc41ywMh423g2Zv4ETd8E6qQwUyLZDTxSstsCK+6H1fXjRCRMeBr/eHQEbJ8KKz6HwHJRPVDuZ1nMw98/AnbDlwX6Nvq8YoaseNzx+HsZ+L/zgv/57ePEOtYNbagwkvQov2uEV+UTfBZXWodEPMbrOwC1vDw/AUyaoHAdjgdbLMDaglLt64EddattbMSGAfX9DYQRMvgeyO1TMZDFlHZvug9r71M533ncDhf8Unj0NJwJtc6Js1yLc0UyOhV98Dza3w6tKX8BkupRAh+S/Iw2QiVCgNQD6ZvFf9fTA43/oW7/SIJAd14qH+hpBEbL72+PTgfb5E9m2vgf1Y6DrA/h3N7RegLmyPCNg3URVmQXpdL4PLqnsYoIxwN1Q/hA864Ku0SrmwbtnnZDRAy4BP7EEYwc/P/AA/E/AEAmmks+AfN49d8IuA/h6oeceeKIX5pxRjafp34ayeJj0ObzuhuWnofNzeGIs/OLLtocgY8DfkUyE6d9SDUD/rREw9gE49h1QpDXxKWSfgqOyjBOAzyD6flh4D9whLX8NvW9EsL+F8FUX2idHFSNvj3L7qss6HPkPt/YwHDH6sjKd/SuM/fY3q017roZHV18Wr9uR/hup7G8HsDoPHQEdAR2B4YSAxtM8nMTSZdER0BHQEdARuJkI6Mr+ZqKp09IR0BHQERimCOjKfphWjC6WjoCOgI7AzURAV/Y3E02dlo6AjoCOwDBFQFf2w7RidLF0BHQEdARuJgK6sr+ZaOq0dAR0BHQEhikCurIfphWji6UjoCOgI3AzEdCV/c1EU6elI6AjoCMwTBEY9sre4+ygrcNzw/D5nB10uG6YzLAm4HM0Ur2vw78Xzu0X1IfL6fqKeN/+0t4wR08Hb1S/gUO+vvsVHD6XE9dXxPsrKG4Eltr26sPzDQBj+Cl7n4N9RStZNv9JHh03hokzFpBX1oDD1ciiMWMYM+D3CHnNfVutx+XCpf05O6gvWMCCgn04tPH+sKevgnLtY/64NKrlDmGAp3ER456sxBFsLj4XHU37qK7cxxf1QZ62LSxatJGm29XJeJqpLi6mPij7G/Mj4KVi+Ehec99y+zqoXLaS3aGCBgrsa2Pj/EVs6eiLcRCO0NnVSMGsNIoDdeHaN59xj23kWtl8jn0UbWzE5Wuj6LEn2eLw4NhdwMZGCZiLfYseY9m+wcHztRXw6KN5+Fn6mlg2LlL7CMQ9EkgXEvgWBJzVpI2bzzVE1jB181Z5MVuOBQwZZzVPDmjbAdkf29IPRx/NRYvIe6M/Nh6a8tJYNqASNWz9QSe1WbOYXx6obEclT45LY3eg3fRP7b/2dVBdUEmzx0PTskeYv8+Jp62Sgi3NyBI4KtN4LK/JH46cv4lF4x4LtCMX++Zfo67GBNNFpHQdkR4aF43jyeBDLSl4WiiaNYu8Jg+ufVlMTStW21Ek6r5m8h59cuAz4MdtPm84mtmyLI9918IvEt3bHDf8lH1UDGazGWt6KhbDeJ4/foF39yzHIjf5MYyn5O0znD9/Xv2dOUR2bL/tF33NFMyYytSpmt+MORS3KCjH1jJLGy/Ds/IIPm+DYu9uorxgJfOffJQxD01l8cZ6bC4v3e7BFaBU9FmLd9DSUkt5tfpADEr/JtzweVx4zRlkxNqo3t2Gy+XBkF7HqZM1ZBiNzH35OKdOneLUqeO8nNQPM8nfbaOhxY0huDFZQCbPsUrqnSaSzdr9BgcK7GzYQUtMJrkJg6Xz0bG7iC2ani8q1gy2BmzuIDM7+5oMJCeYwOfgmB0s1n4CDWQdjpHt5dAZzpzp+zu1P5v+zSSc6SsI+Ty4FAuZ6QaOVTbQ4fLgicnm8KnjbE8yEJNdx0l/XZ3k7U3WgQL6HDQ12fHJ3fG0h6uR8kYPloRYbeyAsK+jmmqHlfzlg+8GJhV5UXVbWHlHmTErjTTYAzuoKR5a6tuISbUSjYeOJifRCZYvsVOpAevW4wPq6sypOuYaI7TPAaW4sQhXUzUtxnRWJUVjyigknUYqv1ARDMLTaCHZ1EZpUSP9u99Bcnwl0Tdt18uuri56e3u55557GDtW7u93vUc0yfmbSZbW3u6mAUQM0dFEhfSJwb9t7MBEMWTvP8m2aaGEA5L0j/B1bGTB4nqcihevArZZj1Aem0lVoZoyJiGDzOz1WK0WTFHgaVrJ/AInMfs305eND8cbxax8rh4l42XezvVSlrWYNMdWaiqWM+mW7NvrpD5rFsW2wIO4YwFTdyTx8pkDPBMTg9yqFVMsJik4RnV7Yn+ktHAcNNuceO31OAxGvLYmmgwGzEnJWKIc1G45hnnVEZIMHWxZVAqb6lg/qR+unibKKh0klNTR/1YQZ+e+PLKKHWQcKlGj5IhhcYF/1NO0qJnubjeGnAJiDNCQVYRxEzR7u3EvmEp98NmPSafuSAXTvI2snF9Ai1utq6xZHrbuCWzsbDCo5Q0yludgWbVxNxr2dbAlbQ47zg0ktHbqGNZqo2MzOXS8ItBOfHSUz2dOKGMxc6aWMnf/GV5NjsVkkOLGEGMyqdv5GtU2rrZ5Dx3NNtyuJhq7DUxyHqOpyYDRksQ0M7SVl2NPKKRmkkJz0WIqrVXsWW7WSuIfMTWW1eNNryKj/61AStkZ5CwuRyk5Eni+PDQXLGZjmwfa5tPQ7cVry2KjVMrNOURvW0WbzYvdlsYj5QEiBgvZdftZP8nN7kXzKbPLulJoWTyL7qo9pPirRdZVsHI1YkaI0ty9CUEHDTuO4XXD4ofkBsGBI2ci/h3DDQlsOn6YVWb5eLThcDlwKV6w22jDgnVSoG4MBn8dKZhI3VRDjd2L0+nD9AWGUZDd7T7fFGX/8ssv85vf/CYk+6OPPspzzz0Xuv5yAek/86JIpSsbhPQtGo2BRqfgdDhwBLdn9XX7FfNg9D1Ny5iadUzu6hv50DyEUZZVbK/LQHE3UpDTQHJVFZmxJszdBWC0kp6eilU2QsWFy+2kofIY51zZfTsbTwf7SvNYW99NwvN1VK0y4yGWPcdNFGXlMWdWA89XVFCYau6zL3dk4WSsB0ebA4N1GtduP2aWH77Acj8hH20b08iyZ5IsO5ZBBh/B58nn3EdZUT2ObjcKRiqL8nC7Yyg5foSM5iLKlUzqsi1ERfnIsLpYsHYXS47kE7YJfbSVF9HgTaEu3RShKD4c+/JYtNZGwsuH2Twt0NtFWcmv2MNyn5N9a7PY0R1LxrYqMo1gNJlQ9i3Dm7CJ/ZsSMCh2ynNKUfJzsfr7GQsZ+YVMs9dTVguZqzKRA4AG5Rw75jzEjghSYMyIFNsvbqh4y43VLeTvOc4SbeNy7mZlTgtL6qroA4XBSGyof4xi0vpfcWm9ytrTlMesAljuL9gXVZadXaVFNDm7cWPAW15Eo9uNdfsp9lurKag3kHsoA6mKDOkW7HkF7Es/wBJNtXiaSik+ZiDjUFJEK9zTUUnO4jKcmXUcXmUJtNNoEgqr2JPvw1GdQ04tjM+uoCLVgMFkItpZSbVxLtur8rEYFGylWVSac1luUY0La3Y+hd12qssaMGeuIsNiwIOCbe0MHurTKwarI1bTvoJx/c9DrCvnbhbNL8PmVlBaZvFIdQqbCqHcDjGZNdTlW4jydVCeVYyvpI71/vZpIMbfEXqwbckj71hAzxTn0JxQyIGKBJxtduwtjTgVG8UzxrDW3w5iSNl6OEIH21/2r+ha83GT6wpevHhR/OM//uOAn4y/rqPnoFgYN1qMHq39xYulBw+KFYnxIj6+/2+mWNca/M6U/CzSCbEifooa19slOjs7RWd7u2htbQ+Ej4qdKxLF6NFxYt4LreEvyASF7dkr5sXNFju71Ije9g1iZh9ZVLniExeKDW/2BHJdFu0HN4h58aPF6Ph5YsObMnOvaN2QKOLmvSb8pHq7xJvr5om40aPFlIUbxN7WYN4g4wjn3laxJnGmeKFdU74IybRRl09sEDPj54mdnYFYSWNKvFh9IkijVxxdGCemrGsNfZ1LiE7x0sw4MW9vjxBdr4nZcfPEzjc3iNmj48TCF/aKg3tfEztf2CDWLJ3px21pqNxCXG7dIBIlPvGrRYiFEKJn7zwRN2W1eGmDLPMUsWJvl4ZfUOIecXTDTCGxnB0/U2zYu07MTFwjjva0ixcSA/LIpJffFAvjZooXgmUKFW2NmDIlwLf3qFgar2LV29srei+/6b9+qbNX+K+DLK91vg68+5Dr2unHTsI4pKPnTbF6imzbwQy94ujSOJG4oT2EVc9rs0XczJdEuOi9on1doohfcVRc7pU4xYulew+KNYmjxZQVL4mDB/eK1156QaxbvdBfL1PWnAi3cT8/2X4T+7apzpfEzNEzxbqX1vjb+sw1b4qgRNpydB1cLRLjZ4ulsq28tFesTpwpNrT3iBOr40Xc0qMBPl1i52xN3QUJ9B4VC+OCfHvE3nkyTZdaN71d4rVAHn9dBZtqMG+k81DrqrdHdLaeEC/NjhOJ6w6K1hMHxbpE9RlOfKFTxbm3XaxLnCLWaPWIhqfUAYmjp4g1gQbe27pBLF24Qqxes0JMGR0vVuxtFZ09QxFaQ/QrCN6wZf/JJ59E7KYGi4+YWBtpeoYDF54BxxYem7ULy/bj7FkSGG8+84w25ReHo8xYLOBpLmBZjp3k7ARcDbUcc1vJrjnApvRrWdgenNKqnraZX10qwedR/CMEOeyMCvuR/DI4q7OYU+rAmrmdtzctCblqpq1ahSWtnmbXcpaYzKRvO8ypzN2UFpeyNsuN6WQVqTfRreNz7CYvZxdR+cdJ78hj2e5MqkoMKIrWtaGWI/wpEcDZTEO3hcxkEz6XDZfRjNnnxmM04mncRa05FrPFgjVjPTXWcvK21ONIz8fiaqQ4ZxeKNRZDhMkpxd1AWa2V3LojbE7VmJd+1Fy8kZfGc23JvLwnm5ZlRRishWxOLaK5cQf13XKOxY5niQmDowkHZlZpP1LRv/b9lpWC4nXj9RrA6/F/ycjjcuOV7gavF0Vaof3zXde1j7aiBf7JPW12RXHjVhSK0x6jPDh0CiQwr9rDgVXh8RCeNipz8mi0bOX4pEZWLvOSX5Ptl9lgigqN/NSBg8Zd6XNQ3+TGWmIlWrFj9xqxmLzYFSPY97HLa8ZstmBNymbzXDMb15bTWJLMEpOT3Xl5NBisGMOeeI3456gtc5NUcoia/GkDcHLsXsT8UheZdXtIrUyjPCaZksJjlB1roLLRixLThNOXSrTioNlpwGzuN5+g4RQMKl4Pbq8BgyLtfPnlKZesJvk9L7yY/O7SYNrrPkeZsEwzYDGCwTKNackxRG9+GUvlc5TuSGPiLklZ8ePOgok0GMCYsJUjB5YQbLHulhbkWKq+oJiMIxWkTtvMngNy1NxMXpMNg9mM0WujsclOm82JZdVmlmiq+rplv8kZb1jZ33vvvRFFGiw+YuIIkY7GRrpR6F67iCLzEQpdOcx4riWiS8aQUsepPamBBhqoOBTVHSRpWwqp2lROwdpazsVksP1QCakmA16XCy/GgC9bFcLndeNR7FTOn0gpc3m5wkRZVi39PggFjOf5t4/4/dfm7BqOpxsw4sbrduAITjj6kthal0S014Ej+Cms6FQ2HcqkxAumm6N5/IK7mraQk7MD6bY3NGwkx+nAWrWVaKUJl2IkNTrkR/B//k3rKnU11+OIzSDVDO5GO15zLgnPLOHdSH2rz8qh5cbQMNuQvJW6zBayCoKV6KK5upSiUhsYU9h+pIYlEX1QJlKfr+BtcxImWxlvpW+mcJIJ07YqjEWzqI2NRWmspMmVxKSWZtyxS7BEwEtxt1G24DEMmfng7WbX4hn4n9+AOC2LZ6huHUMs2fuPf6l5nGCJBp6jsKzaRIXGM6Q4qskrfsufVHFD8vZtZJrDGt9gDk+a+pxvULrsOWqlv99YS8FKB67UOqxRXmq9EB2jUZTyG3ZRYTp0H6PJnUC+7JidcpWYheUJy9n8G9WJ11fWVCwWL7EBrWUwZfDytnRq04IfRvThbNpFUVEZ54ghs+YIFX38T2FqlvQSqpItJBmaKDXlU5JuxhxdxVbphjKMJ6a7nh0thWw3NmJTLGzyu3DC+YPANBYvoCEmm+WKgr10DjNKNWmK5zC1WF4bsJYc4Uj+rdCYUVjSU3FUG4jNruNAocXvJiybX4BScZhN0ldrMIYUvfz2VGO93T/XZY1upKDgDeoKTThsNmwtTTS73bgXT6XeGEtCwjSs1iSG0M9pCn37gjes7OVk7JQpUzh9+nRIanl9Q5O0vjaqq+WTEEtGZjRN1S0UVtVw8pRq5yi2ItIKoOLINhLkc2DQWGyKtFwNGLyN5MxYS4uaJSQb7gbWzmkIX8fm8vbxzVi6d1NcUEm9Tap1I0mrqjicm0qMvYCy2Gz2HyhUVwTJnIqNovkbwx2PtB5iOtiYtoBd5/ozDLNSQ+MpOf4rBm3HniaWzcjiWLBzkJlCfuhYMg8dp6LvjDC+tiLSshqwPL+V7IZSmrBjN6RSkhCNz3EMh8FMfsgqDoxQQtajD6fNhaI4cMr5kQYHsenTMPnaKJi1gPoBvZzayU2Sgy1TOhVV4Guz+a0jKaqnuYyCSifT5sZwzm7BGhPuZPogIVdNZeX4y6nIj4lSS2OthD6BrYePc7LEQeX8OZSVN5DRfI7Y9BRC6lJaxQXFVL9lx8t4rLkVFCY7yCmzsvX4EfxzknIp5tSNpB75lX+irQ9v7cV14C2zR1uSSQ7qIk8bG4uOYZw7F+NbdqwpCg21dnL35w+csPY0kpf2HLakEjZZqilzKNjPxZBdYSXK00KT04hFmqGBww+NnHQOXHucdtyKF4fTRXdLE25LPgnRcjnkVLKO9W97BhK2HufwJJnZzJKqCvA1IWH2H65Gigp2oyQnYez2kmAN2rLBBMGzi30FORS3eP0ffpVc6hvkTKyRlJrjnDwJttJZLC6rJMXaiNtSyLQQKRdNGwvYWH+McxhISHierfkWGhYZSKo5xYF02YPLpZgzqM09xeFnIvToQTGus66C2QecjSZ1ItznUufwjTF9DD+Z3tdWSbXLSqzBR1JJPkqTl2NlO2g0WEmYlk6Gw0aDdT8nK6x0715LudfKoDAOEOA2R9ws15H00Z85c0Zct69eI0jnztkifuZqsXCK9MH2iJ7Ap9lVf16v6Dm6WsTHrxZHe1R/rCarENL/GDdbvNbf6djbKtZNiRcrQo5l6aceLaRP0+9t63pNLF24Wrywc50/f8hn37pGJCauE0e7ekRPT+DX+aZYMSVRbPgSvvTeztf8cxFTVkf2h4bL0Ct6urpEl/wF+Kw72qled/WIyxFdg5dFZ9dlIXo7xQsz48WKo51i79J4EbfwNfHmmikibuFejQ9W9anOfi0wKeFn3CPeXJMo4uITRdzogG+894RYPSVRrDna9YXl7m3V+M4DBfH77BM3iGtBdLmnUxxcPUXEL90rOnt6RPvOeSIucYMIuk4vy3r2z5fMFi+FndbSiS9a3zwqThxcHfLZ+/2qcq5h52oxe+ZMMXPmFP+8T3yiDM8Us5fu1Pi9w2jLuZUvj7cmf2+72LkwXsTN2ynaOwM++85W8cLsOBG/cGfE8l/ulPMXvaJ1zRSRuOGEaJXljl8tDu5dIeLjV4ijgfYuZWuX8z4L3wz73UWv6Ny7QkyJmyIS4+LEPH89XhZvLowTM19oFV3BNtrT6feLzw425KDIfXzngcjgM6NtEsH0gXPv5R7R/tpCET9ljXizq0d0ybkhObcVrJeuvYG5tjixsN+kRc+JN8XRVnk/4LOXbSs+Xqx47QWxdLasn0S1nqeodTVz9moRmsboI8f11pWKT+KanWLnSwdFl5DX0m8fJ+Li5E/14Qevp4Sely7x2rx4MfuF18QKvy4a+PB1+edUXhBH5XzG6ESx7kSo8vpIPhwubtiyD/ZNN2TJB4nIsxwOl7lIryqBjR0QZVLdHa59LJi6FjmgCh5ZU6WFbiRj/ymqklUL0uNopttg8fvogukinX1t1ezuTqBwT7LqHzUvZ8+B5eDaR0uZtFTDh9JdS9aMkD0UuBFLbjhJOORz0tToxJKeHF5B43yDtYuKsUlf4PZ0zRAxnC0cisJkDsxR+FxEGwwYY2IxR3SFBHNFY/FnCfiPDLEsqdqPyWajOkchqUrD0+fB6ZErXsLWI5hI31pFdvMCdhkySQ2NAsAYo7F2jMaQLznI+Uud5XLaxeWYt9aQL9doOqopa/Bi3WQlRmkir9xJelVdaClrdEIGSYYG3opNISVk1kuO0UxLT8XXJutftWYVhx230UKM0oYjKp2qTakES+i1l1NQ7cQnF7sMGGhcD95qqX3ORkqX5VAb9Tz7969ikrdavWGcxvr9NXjnZzEnzc72V7eyROPWiPZXVnDljRHrqhrqzHZs5Tn+dyOSNMat1+3FYAquRpPko7AsqaDi2AyyGmLISJCVpWIQZTJhNgVNaoO6xFaV6Dr+fTTlLWB3Sg2vLjETpdgoL2vBkJqJxehFLt8ku47s4OjGnEyGFVpsVjKSgzKobE3J6Zh8TVQGpXDbcSgxpBi9NDhNrKoo9K+m8t/22ijNa8Ddf5Div3kddeVpY1/lLnbZFLpbqmnK3YzqfZPvM9RwID/gxllUhG/TATZPk26cGPUZ9XlQLNlsXWVhl2aFZrAY8mxOz8ZaXEzWc0b/SpwSv6tBm2L4hIffS1WWdEq2VrEpRdvApctgCUcuXeLSpUucP5RJTEwG+8/L69+FFL1cqtiyrwWscwNL9AYHOmraNt69cFgd8g+ezH/HMD6Xt/28VP6Xzu8nQ6MQtdl93Y1UFi9mxkOPsWzjPpqbqlmW9hyNlk0cqluO5pnXZrv54WgzSn05x2Lz2Zyi0R6KG4fbiFkuaA8dPjp2FbOrO5YEYwM5eftwRnzYQhmuL6B4cdrtIdrRCflUbM1AKZ/DxBlrsSVtY1NwxtrnYHdeAW8ZrIzv3kFOadM1Xljx4fC/gZWC301unEZScjLJgV9KgjnkBrk+wfvnkvMSeaTNyKHRvIm3D61Xl7lqk0Wnsu3wIUrMjaydNZX5Rdd649qE2VNNuSOBwsKA8eGnJddtK8RYA+u6A/Slq6yoQWF8AuzKKcb/wrGW900Je3E55fxToCGYUlhfVUJyRzGzJs6i1JnOtpJpgb7TR1tlHqW2GKyxNkpzttB8jR1OPPYmHIZJ+PsEgwlrSriuklPkBPJNPNx2Gm2QsnU/J8+/y57NYcPHYDQTazZjjo1FzuFHy4UI8tr/PorsVyexqmI90yIKJOc7qsnLKsVvGlrz2bw8FlveDNIq+7+GfhPLcwOkbpplfwMy9MtqJlWuvubt6NAAABA2SURBVPG19Y33+UJLxr1edRJW8Ybj/CtkXI1UH4OE7cnh1QQ+J80tTgwGdZK0r82hYeFz4XC48LntuOQkp+aW4nXSIieMg1ahz+FXWJH0vVyvf+B3mXS8UU5Z2VoWy9lC6fOvWTXQf6vhETEYNY2Kd38V8da1I704qvPIazRRcijX38H4nE00tikotkpasLA91Ot4aKvOIavMRUbNEaqS7BTML2O3vQQUdcJTrlBQDwW32xh5RBNMEjwbQHE7sNk6iDJF4fO56D6m8s4M8lYUZF16FCPWFCuut3KYv3ITVestNBblsMOWwKZDdWQq5cxfkEWaayt1VcuZFOWirdmBYnfixYxBcVDf7MUiV5EooLQUkfbkllAdKt5zuA0Rx2FBadXzUPF2NVNb7WDS1kNsXT5w5UqIaPQ08vecJGl3McXVNrwsCd0KBxS8bVvIWWsjaXtgvsEj35B14PE2UWkzMKkkPKzxNG8hK6sWQ+5+Dm8207hyEdUNDrJRsJel8WhlqLLwuhUs6WFO1wwpLlqa20iQ68x9HryOBnbZtbwVfB4PHgViElIwO+rJSoOtVflE1+aRU+tk7vYjVKU6KJ6fxeL5bl7es5VnzHKxlw2n0oxLMUCUF9s+GyRUYDU0I+fQ8mZ1+JWtXz7FyznFxBeKPdS6siznVTliH3AodO+YxUO75GqgwAq1BQ/R4F+5ICfzj7C539xYkISsg5y8HbS4YfzcEuq2W2jIymHZSidWm0LMkkiaIZj7qzsPQ2UfCQwn1QtmUKr14QCqG0dO0KZQd2YPSV4FU0Im2X2W+blo2LhYXfkQM5eXg4qmPxv54k5WFg3SE2LNxT86DqZxt7B7hzs8LFY82L2QELw/4BzNpGc2s+eZ/MDKlFqysswcijRhNyDvTYhw2djdoJBZU6e6SyRJVxNlz+2i2xBLSkkN/nkxGe+xUVuvkBlaHmmi4lep6rIyQwwZm2p43r9XhfQW2CnLCr4ieW05TZMySDKWUrz4WCihIWY8Sbnb1OWmnibyZuTQZs2kcP9JlkyTk8lvULZbwdtYTq0zne1HtgfcH+s5vF8hq6iFbu9yJuGisTSLHXaFmLmrkB4sy7RMktJjMDSAwbqKbfJlrABnxV5OXsDDEhLmRgKmZ6iKuFQpEtFopi2v4kgkfSOTK26adh3DKF/CCy4xxkl9aQ4NbgPjM7ZSEnBR+leGVDdiLDxEXWB55JJX32UJHhob5eqSKmoyg4rGS8vaLAbxPvQVNDaJ9IRKdqxdQGjpgiEGa0ohz/u3v3DxxqIZrHUlkVtyhJpnLETJFwjL6zF072ZLg4/smiNsS5c1YabicA0sKqfFqfCM2YCzvoDFcqZ/fLbqIrSkkiknhaWyNyaRv61QfWHRj4ccGYSk6CvnTb3SuHEi0DUOtrBAOhGtqaRmmslfkklqQJ8kHdjO2pXFNJpy2a8dSUeg/VVF3SEnDr4q5t8UvnI3ytoOC9nyIfmmFHoI5ZQ+9H6vLIRyRXSvh+7qgduOwDUq6xq3bruYOsPBEdCV/eDY6Hd0BHQEdAS+NggMvwnarw20ekF0BHQEdASGDwK6sh8+daFLoiOgI6AjcMsQ0JX9LYNWJ6wjoCOgIzB8EBi2yv5sF/yoSwVKG+YqnP0LvPKnQXfv9b9j8p/a7QaGD966JN8wBFq74NWPb7zQPR/DOzeBzo1LolP4W0Vg2Cr7/oC6PJBrh4mtsPyPIPuBiO9tKGq65Q5459P+VK59fdYNr18eJM1VqPhfeDq4ydkgyb5U9Mcw57fX6LS+FLEhJv4Cnr6/wBgbtF8dIr0hJvP1wquXoOsm0x0i+2snU+BHJ+HpHmi/AKNa4Z0rahbPBzD1XRin+Y06CaM01/Je9geRWZhGwmYHnL1WuXvh6d9CD9B6DnL/otLyeeHp/4XHbZD9Bzj4AfRcgcJWGPMujDkZNogic9djdQTCCAy7dfa+v8LTv4eOz9WXwMd9AGXfAcOd8JNYKL8PokeoD+XBj2H1t8KF8Xgh9yx4YuCtuyC3A9ZYYGXEN+DC+WTol52wWW7wNKFvfOhqBCy1wFP3hGJuOOBTwHmbF75+Ec8oI7w1ASbcZDMg6h74sRey7VA+EaYPo5bn+Qg674T6UdD6PkyIgZkB+aJHwalRfav6Ffmdnodhdf+2cBVescO23r7pvQKSWuXGHuFDflHw14+ouze80w0e2a4/hfwPYWlgtwyuQJcBfv0DzS4PV8FzJ9ROBfMfIT9MUg/pCFwTgZv8SF+T15BuRn0b3p4Ox0bDpNFw4YfwhHwb83PovAyvdsPmc+pDMeGuAMmr8MuL8PgZMJmhPAp6RsFbcfD6WXj6HJwNWGqRhOj6ExR+CrXj4YEICdrPqZbdD34L/+/Dvgn+sx2e7oLn7fAjG0z9bV8r7pfnYGqr+nvcHh5t9LhhYie4PoKHpJX2LlRohumvt6vW4iu/VS24UUFr+yrktmrSXoXnbZrrK/DK71R+kuaczrA1fU2en8Kz0mJsg5RO6OxniXb1wJxWGNcKE3+jcU0E5NncBc+2w+Ot8PTFyKOusQ9ApRFyHZHv90X29l21fwATTDD9KvzXZ7Due9fJewSsngwXEuCpkbBGhh+DD2bAB4/BqXEgO71fy3BA0cttbf71Q5j+Heh6H07cCdPvDvN3/RV+GGg/2T0gR0id8tWlwJOriNs8MgyLpof+xhAYdsq+P36+KyD3dqo0QfRIiL4LJhmh0go/vhukNf+sDXK98G9TYMcDEH0V1l+E6O/C25Ph7xVIskFhYHjch8cV2PYneMoMYwdBY/J49aHdHWnr/hFw4kNYPRH+Zyo85YN/CbiC5ChlvRdqE+DUdKi+H/7rryr3B2Lg12PBeB+cfwwuPQYFmlGK3OPlnYvQej+cl8oiASYPIp+2PO+ch1dGwFvT4VICTP8r5Ev/AHBNnnfDz6bD+R/AgMFNL+RehIUT4cJ0eMsEm89qOrWAktw1GX5tBU8P/HIQF9rk78P0j+BFTcemlf+2h6/CUSWg4D8BTzQ8FXz1NiCMrMcftatuliHJNxJWfhv+o7uvIv6lC8x/19egOCsVPCrPF10g96fTbulh+jb873S1/dQ+AF0emBQLD4+AsX8H03sh/2JfPkOSUU/0jUNgGA2m+2Iv96fp9MAPP4AtY+Bfnf0atAFqrTA5ClY8BJX3qfl7PvV/e4At94DnU/DcobpfFvrAE0FZ+z6BE1dhVyB/XymGdjUpJqyIf2yAbZ+p+aKkcv4MXv8Aou+HyWNg8tBIEn0nKHfCltGaIfwX5b0KBz+CpyYEFMpIKJsCviF0Etci3XMZOu+BnwQ6o7GjYLITTnwGD8vR1Qj4e9kZSyIGmDQCuiQGGgs1RH8kLL0X1n8AGzWdW+j+7Q6MgI3BSrkb3v7OEASQxkQ7bAsmvQt+9ihM1+A8fSyMbYdXPlY7cd9l2NwL5f1cQg8/CB88qBL68fQgwfBZWvbSZy/fvJ70fVitwIlLMPGiun+TbCPVli/RRsKk9dA3DIFhp+x9H8PTdugQqoI8JhuyG14cBcfkMFhW0BXVZeDfj+9umPctyD0DHf1cDzKp7zNwSktXWrmahzFYz8pn4LoTTBHuBdN80VnOJ0Q8vgX142HzJXj8PIz9NmwZD7JDGMphujegQIeSWKa5Cl1X4AltWUbeuCLwSMV9p0aWkSpeTukaC7jS+uCn5R9BdpMBPD618/6y20fICdS5LpWo4T51JBHJ9RaB7c2LGgFbJkfw2Ws5GODfxsDc38MECxx0wASzOhrVJvuisLTs/+cRVbH7jYcrMPkyrLDCEwqkONQ5rC+io9/XERh2yl76NHc9Cr4eWCVdDyNU/26nG+Z6w7tRygnc0GFQ84SuAwHZcWSegSfGRVb0MpnhDpWmT3YUX6Ck+tMfyrW0gndJa+4K/PwC5J6DUz/QKM5rERlEnj59xVXwBjs5ObQfCU4NNr5P5XeAYGwkK/tavDX3oiVDj1oPwc7WdRV+fJ2tR7mq4q5hMeTgZDP87/cDyUf0dYkMmchtSvjwGCi/DMvlXNL98Ovr6JXkXNU7H4DzI2i9AhvHw0+/Bev/BBulq+w7N38y/TbBo7O5zQgMok5usxRadlJh9dFm6s2x90PtxMDvYZgewZr++e/g6U74ZS9IP2v2GYj+/sChs5ad7FzGfgad15jA1ab/MmG5bO/Zc4HJyJEw/VsgrbNQ8UaA8ml4AtUzRBkeuBPaAt++kHMWrUHlPgJ+ch/88v2Af/kKbLark9khua+D5wNGmNALBwPzDWf/DJ0GeCI4QR4iPrRA+ycw9jvXOeIYCQ/cHfhdZ2czNClvMNWn8HonFP4V/l7uGvyh6lsf8tJTuRxTTuB/Av/uBpcBVoxR55VmPgimHsj8ENZ9P4yjnGhu/VSdxP25nDeSCxd6wu3rBkukZ/8bR2BYPi5+pSeXJN4RRrdHTnaeD1xfhfYISxYXPgT8SfWndgp4Yiz8bHSYRsTQPeryzRf/DPPGREgh16VLt5LcjVbyPA9jLoDsfI4NmMnsmz86Gp7oUVeoyDvSQv63h8MP5wP3w9JLkPSeWtanxkFtcIfavqTCVyPgp7GQeQF+1A1j74O/vxuC75DNfAhWOyDlXdVNMjkGqjUW5WA83/kdZEoiQl3ymvKeuty1fDIslaOtByG3E16UVvldsOXhwIR2cFQRlvCaIdkJ//tnsOX+ayb7m73p+Rh+fgle/AtERatLJGdKt9VlKLwAP+yBnzwAq78H00O9foTi3gO1D8FcN9Rrl15+Cj/vhlb/ZsLw4h/UFWiSxy+7wDke1n0M6z3w1H3w4kX46ajBFx9E4KxHfU0RGH67XsolgKfgqICfTIBd31VXd8z9ECrHBKziq1B4HsqmDuKeuQKvX4BCmedRWHith0pWrLSizqgTm6u//TWt6eFQrCtQYgfXGNj1RZ3acJD3KpT8Bl7/VO1Mgy4/uW5eGiLadfNRBmiwwtHfw3/dDT8do84l9S9Gu5x/ugSuGPhFJONCk0G+4Pb4+33X2cslua/IznYczLwDXvkDvPIZ/MIKYzV59aCOQH8Ehp+y7y/hDVzLV8yjpetkCDSkxVnYBRO+DwVDWZExBJp6kjACcn345gugxMCWmKHVSTi3HtIR0BG4UQS+1sr+RsHR8+sI6AjoCHxdEBh+E7RfF2T1cugI6AjoCAwjBHRlP4wqQxdFR0BHQEfgViGgK/tbhaxOV0dAR0BHYBghoCv7YVQZuig6AjoCOgK3CgFd2d8qZHW6OgI6AjoCwwgBXdkPo8rQRdER0BHQEbhVCOjK/lYhq9PVEdAR0BEYRgjoyn4YVYYuio6AjoCOwK1CQFf2twpZna6OgI6AjsAwQkBX9sOoMnRRdAR0BHQEbhUCurK/VcjqdHUEdAR0BIYRArqyH0aVoYuiI6AjoCNwqxDQlf2tQlanqyOgI6AjMIwQ0JX9MKoMXRQdAR0BHYFbhYCu7G8VsjpdHQEdAR2BYYSAruyHUWXoougI6AjoCNwqBHRlf6uQ1enqCOgI6AgMIwT+P72V2fgx+MkgAAAAAElFTkSuQmCC"&gt;&lt;/p&gt;
&lt;p&gt;Luckily we can always find a way to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Recently, I&amp;rsquo;m becoming a crazy fan of &lt;a href="workflwoy.com"&gt;workflowy&lt;/a&gt; because its ability to build a personal wiki concisely.&lt;/p&gt;
&lt;p&gt;However, there&amp;rsquo;s only one thing bothers me that workflowy hide all the notes as the screenshot below, and it annoys me a lot.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXsAAAA+CAYAAADK3LtgAAAgAElEQVR4Ae2dD1BUV5b/PzEmTTKZZjIundGhDcY2xGk1DkoMxDiwI0pFDRk1+FMWS/nhjiRUicuvhMVSSjdSurWUpIIhKxbZSGGU0TGM7obEHXGdCGMCvY7Q44y0OtKME7onE7snCf0S4/3V7dd/HtAY4r8wyXtV3e++++4959zvve/cc8+97z7E1/Do/VCIRzuEuDxY2T4TYsF7Qhz4RIh/ahMi7Q9C9AbSHrYL8U+ecMbej4T450tCvHdeiMV/DsQrQpz2CnH6AyFmtQlxwCPE6Y/CNN5XwvllqOaUEP/wYd+4XiUg3+dCbLcJ8YhNiLRTQsyyCTH6tBB7OoRIOy/Ee5+o+Xo/75v/9HkhRr+n5pH5gr8Z7wkx42LftOIzIf5vmxD//ZkQ4nMhauxCPHpKiH/+oxDbO4RY/H6/9J8L8U82IWouCbH9z0LUnBZilobmxYtCxNkD5f1ciH+2CbHHp9L+vcRF85N10OsR4tHTEepDUfP259/7gRCPnBaiv1j9pBzy5VfaHj4TYvEpIU7L+tOGtdL7hEizqWnecwgx+qQQaWeE2OMRQtb79lNCbP9IiN9/KMT7gXYg2+Mmef8jIf7BJsR3TwrxDw4hfuUTQrYNWV+9GrpadgPCnwgx65QQv+/XxvzptPUr5T8pxKM2IWbYhIg7qbapAfX7uRDPvSfEd9uEeC8Szf4CaNrnxUtCPGIX4vLnQlRJHm1CzGjr+0wKTbkkb9nmD8tnTuY5LcSMsxHamobn7y/2bc+aW/6gbO//7BVCtvO0P2ruSr4BnIJ1Iu/+9xkh0i6p6S57hEh7T4hNHwhx2as+d/I5DukibRvQhjVstOXzR8vnUeoZWUafEM/ZhHjufSEWyLj3hZhxWoj/ls+f5tCW8XCHEAtcQozkm3ZchVfPQivQ/jtYOgrKTKBcAUbAjx+BHwO+qxA1AqK+BWXfgvYLGqDuhsl3AwoY7oAJ98HkEeH7D8h7X3BE3Q1RwTQjYM3DsPoe8Hkh5aJ6Y8IomH4PcAXy22HFZJipqbFJY+DtMUEi6vlsF6zqG4VPino1EDkCVv4Apv8JsrvACUy7G94xwkzJK3h8Duvfh9X3wYufQa3kI2mMgPaPINoQTKg5j4CHv625DgQlln2OK/COG/71j+AbBT97QL3ruQLRI6HjQzDcC9F9Mt2ii9vQHhQfzG0FCZl3JGwMFiWAp+djcI0E0wiINsP58Zq2ocHu4e8EMl6FVi94RkHUXfB/HoTK70B0oA2eDdK/2eeR8LPHBhIdUL/A9Hthr08t88AcA2Nk+/QpsP5PMOEuePYsRAtY+hCsuVfFQ7bj0DMj27QC+Q6Y8CDMCzxzq+Oh9TTk/gl+NrofnwDeCOCOfvciXBoMoFyCx3vCNw339JVBPpv/8REsfFBNE30vlI2BZzvhRWDS30H19/u25S/THsKcwfNXmHMBxpqhchRk/hFMo6AeyGyHLiuslDpEljNQRt+n8B+98JP7QKM6tGS/vmHfR/Afn8EvpoLxQ/iXS/Ds++CNUOSf/gDK+iuvK5DbDq2f+3U9rs/haZtamRO+H6GBRaAbMeoKVLTDvytgjoFJd8GLDpgaUNTRRpgsa6sXnraH+Y/r7ktNEapc41ywMh423g2Zv4ETd8E6qQwUyLZDTxSstsCK+6H1fXjRCRMeBr/eHQEbJ8KKz6HwHJRPVDuZ1nMw98/AnbDlwX6Nvq8YoaseNzx+HsZ+L/zgv/57ePEOtYNbagwkvQov2uEV+UTfBZXWodEPMbrOwC1vDw/AUyaoHAdjgdbLMDaglLt64EddattbMSGAfX9DYQRMvgeyO1TMZDFlHZvug9r71M533ncDhf8Unj0NJwJtc6Js1yLc0UyOhV98Dza3w6tKX8BkupRAh+S/Iw2QiVCgNQD6ZvFf9fTA43/oW7/SIJAd14qH+hpBEbL72+PTgfb5E9m2vgf1Y6DrA/h3N7RegLmyPCNg3URVmQXpdL4PLqnsYoIxwN1Q/hA864Ku0SrmwbtnnZDRAy4BP7EEYwc/P/AA/E/AEAmmks+AfN49d8IuA/h6oeceeKIX5pxRjafp34ayeJj0ObzuhuWnofNzeGIs/OLLtocgY8DfkUyE6d9SDUD/rREw9gE49h1QpDXxKWSfgqOyjBOAzyD6flh4D9whLX8NvW9EsL+F8FUX2idHFSNvj3L7qss6HPkPt/YwHDH6sjKd/SuM/fY3q017roZHV18Wr9uR/hup7G8HsDoPHQEdAR2B4YSAxtM8nMTSZdER0BHQEdARuJkI6Mr+ZqKp09IR0BHQERimCOjKfphWjC6WjoCOgI7AzURAV/Y3E02dlo6AjoCOwDBFQFf2w7RidLF0BHQEdARuJgK6sr+ZaOq0dAR0BHQEhikCurIfphWji6UjoCOgI3AzEdCV/c1EU6elI6AjoCMwTBEY9sre4+ygrcNzw/D5nB10uG6YzLAm4HM0Ur2vw78Xzu0X1IfL6fqKeN/+0t4wR08Hb1S/gUO+vvsVHD6XE9dXxPsrKG4Eltr26sPzDQBj+Cl7n4N9RStZNv9JHh03hokzFpBX1oDD1ciiMWMYM+D3CHnNfVutx+XCpf05O6gvWMCCgn04tPH+sKevgnLtY/64NKrlDmGAp3ER456sxBFsLj4XHU37qK7cxxf1QZ62LSxatJGm29XJeJqpLi6mPij7G/Mj4KVi+Ehec99y+zqoXLaS3aGCBgrsa2Pj/EVs6eiLcRCO0NnVSMGsNIoDdeHaN59xj23kWtl8jn0UbWzE5Wuj6LEn2eLw4NhdwMZGCZiLfYseY9m+wcHztRXw6KN5+Fn6mlg2LlL7CMQ9EkgXEvgWBJzVpI2bzzVE1jB181Z5MVuOBQwZZzVPDmjbAdkf29IPRx/NRYvIe6M/Nh6a8tJYNqASNWz9QSe1WbOYXx6obEclT45LY3eg3fRP7b/2dVBdUEmzx0PTskeYv8+Jp62Sgi3NyBI4KtN4LK/JH46cv4lF4x4LtCMX++Zfo67GBNNFpHQdkR4aF43jyeBDLSl4WiiaNYu8Jg+ufVlMTStW21Ek6r5m8h59cuAz4MdtPm84mtmyLI9918IvEt3bHDf8lH1UDGazGWt6KhbDeJ4/foF39yzHIjf5MYyn5O0znD9/Xv2dOUR2bL/tF33NFMyYytSpmt+MORS3KCjH1jJLGy/Ds/IIPm+DYu9uorxgJfOffJQxD01l8cZ6bC4v3e7BFaBU9FmLd9DSUkt5tfpADEr/JtzweVx4zRlkxNqo3t2Gy+XBkF7HqZM1ZBiNzH35OKdOneLUqeO8nNQPM8nfbaOhxY0huDFZQCbPsUrqnSaSzdr9BgcK7GzYQUtMJrkJg6Xz0bG7iC2ani8q1gy2BmzuIDM7+5oMJCeYwOfgmB0s1n4CDWQdjpHt5dAZzpzp+zu1P5v+zSSc6SsI+Ty4FAuZ6QaOVTbQ4fLgicnm8KnjbE8yEJNdx0l/XZ3k7U3WgQL6HDQ12fHJ3fG0h6uR8kYPloRYbeyAsK+jmmqHlfzlg+8GJhV5UXVbWHlHmTErjTTYAzuoKR5a6tuISbUSjYeOJifRCZYvsVOpAevW4wPq6sypOuYaI7TPAaW4sQhXUzUtxnRWJUVjyigknUYqv1ARDMLTaCHZ1EZpUSP9u99Bcnwl0Tdt18uuri56e3u55557GDtW7u93vUc0yfmbSZbW3u6mAUQM0dFEhfSJwb9t7MBEMWTvP8m2aaGEA5L0j/B1bGTB4nqcihevArZZj1Aem0lVoZoyJiGDzOz1WK0WTFHgaVrJ/AInMfs305eND8cbxax8rh4l42XezvVSlrWYNMdWaiqWM+mW7NvrpD5rFsW2wIO4YwFTdyTx8pkDPBMTg9yqFVMsJik4RnV7Yn+ktHAcNNuceO31OAxGvLYmmgwGzEnJWKIc1G45hnnVEZIMHWxZVAqb6lg/qR+unibKKh0klNTR/1YQZ+e+PLKKHWQcKlGj5IhhcYF/1NO0qJnubjeGnAJiDNCQVYRxEzR7u3EvmEp98NmPSafuSAXTvI2snF9Ai1utq6xZHrbuCWzsbDCo5Q0yludgWbVxNxr2dbAlbQ47zg0ktHbqGNZqo2MzOXS8ItBOfHSUz2dOKGMxc6aWMnf/GV5NjsVkkOLGEGMyqdv5GtU2rrZ5Dx3NNtyuJhq7DUxyHqOpyYDRksQ0M7SVl2NPKKRmkkJz0WIqrVXsWW7WSuIfMTWW1eNNryKj/61AStkZ5CwuRyk5Eni+PDQXLGZjmwfa5tPQ7cVry2KjVMrNOURvW0WbzYvdlsYj5QEiBgvZdftZP8nN7kXzKbPLulJoWTyL7qo9pPirRdZVsHI1YkaI0ty9CUEHDTuO4XXD4ofkBsGBI2ci/h3DDQlsOn6YVWb5eLThcDlwKV6w22jDgnVSoG4MBn8dKZhI3VRDjd2L0+nD9AWGUZDd7T7fFGX/8ssv85vf/CYk+6OPPspzzz0Xuv5yAek/86JIpSsbhPQtGo2BRqfgdDhwBLdn9XX7FfNg9D1Ny5iadUzu6hv50DyEUZZVbK/LQHE3UpDTQHJVFZmxJszdBWC0kp6eilU2QsWFy+2kofIY51zZfTsbTwf7SvNYW99NwvN1VK0y4yGWPcdNFGXlMWdWA89XVFCYau6zL3dk4WSsB0ebA4N1GtduP2aWH77Acj8hH20b08iyZ5IsO5ZBBh/B58nn3EdZUT2ObjcKRiqL8nC7Yyg5foSM5iLKlUzqsi1ERfnIsLpYsHYXS47kE7YJfbSVF9HgTaEu3RShKD4c+/JYtNZGwsuH2Twt0NtFWcmv2MNyn5N9a7PY0R1LxrYqMo1gNJlQ9i3Dm7CJ/ZsSMCh2ynNKUfJzsfr7GQsZ+YVMs9dTVguZqzKRA4AG5Rw75jzEjghSYMyIFNsvbqh4y43VLeTvOc4SbeNy7mZlTgtL6qroA4XBSGyof4xi0vpfcWm9ytrTlMesAljuL9gXVZadXaVFNDm7cWPAW15Eo9uNdfsp9lurKag3kHsoA6mKDOkW7HkF7Es/wBJNtXiaSik+ZiDjUFJEK9zTUUnO4jKcmXUcXmUJtNNoEgqr2JPvw1GdQ04tjM+uoCLVgMFkItpZSbVxLtur8rEYFGylWVSac1luUY0La3Y+hd12qssaMGeuIsNiwIOCbe0MHurTKwarI1bTvoJx/c9DrCvnbhbNL8PmVlBaZvFIdQqbCqHcDjGZNdTlW4jydVCeVYyvpI71/vZpIMbfEXqwbckj71hAzxTn0JxQyIGKBJxtduwtjTgVG8UzxrDW3w5iSNl6OEIH21/2r+ha83GT6wpevHhR/OM//uOAn4y/rqPnoFgYN1qMHq39xYulBw+KFYnxIj6+/2+mWNca/M6U/CzSCbEifooa19slOjs7RWd7u2htbQ+Ej4qdKxLF6NFxYt4LreEvyASF7dkr5sXNFju71Ije9g1iZh9ZVLniExeKDW/2BHJdFu0HN4h58aPF6Ph5YsObMnOvaN2QKOLmvSb8pHq7xJvr5om40aPFlIUbxN7WYN4g4wjn3laxJnGmeKFdU74IybRRl09sEDPj54mdnYFYSWNKvFh9IkijVxxdGCemrGsNfZ1LiE7x0sw4MW9vjxBdr4nZcfPEzjc3iNmj48TCF/aKg3tfEztf2CDWLJ3px21pqNxCXG7dIBIlPvGrRYiFEKJn7zwRN2W1eGmDLPMUsWJvl4ZfUOIecXTDTCGxnB0/U2zYu07MTFwjjva0ixcSA/LIpJffFAvjZooXgmUKFW2NmDIlwLf3qFgar2LV29srei+/6b9+qbNX+K+DLK91vg68+5Dr2unHTsI4pKPnTbF6imzbwQy94ujSOJG4oT2EVc9rs0XczJdEuOi9on1doohfcVRc7pU4xYulew+KNYmjxZQVL4mDB/eK1156QaxbvdBfL1PWnAi3cT8/2X4T+7apzpfEzNEzxbqX1vjb+sw1b4qgRNpydB1cLRLjZ4ulsq28tFesTpwpNrT3iBOr40Xc0qMBPl1i52xN3QUJ9B4VC+OCfHvE3nkyTZdaN71d4rVAHn9dBZtqMG+k81DrqrdHdLaeEC/NjhOJ6w6K1hMHxbpE9RlOfKFTxbm3XaxLnCLWaPWIhqfUAYmjp4g1gQbe27pBLF24Qqxes0JMGR0vVuxtFZ09QxFaQ/QrCN6wZf/JJ59E7KYGi4+YWBtpeoYDF54BxxYem7ULy/bj7FkSGG8+84w25ReHo8xYLOBpLmBZjp3k7ARcDbUcc1vJrjnApvRrWdgenNKqnraZX10qwedR/CMEOeyMCvuR/DI4q7OYU+rAmrmdtzctCblqpq1ahSWtnmbXcpaYzKRvO8ypzN2UFpeyNsuN6WQVqTfRreNz7CYvZxdR+cdJ78hj2e5MqkoMKIrWtaGWI/wpEcDZTEO3hcxkEz6XDZfRjNnnxmM04mncRa05FrPFgjVjPTXWcvK21ONIz8fiaqQ4ZxeKNRZDhMkpxd1AWa2V3LojbE7VmJd+1Fy8kZfGc23JvLwnm5ZlRRishWxOLaK5cQf13XKOxY5niQmDowkHZlZpP1LRv/b9lpWC4nXj9RrA6/F/ycjjcuOV7gavF0Vaof3zXde1j7aiBf7JPW12RXHjVhSK0x6jPDh0CiQwr9rDgVXh8RCeNipz8mi0bOX4pEZWLvOSX5Ptl9lgigqN/NSBg8Zd6XNQ3+TGWmIlWrFj9xqxmLzYFSPY97HLa8ZstmBNymbzXDMb15bTWJLMEpOT3Xl5NBisGMOeeI3456gtc5NUcoia/GkDcHLsXsT8UheZdXtIrUyjPCaZksJjlB1roLLRixLThNOXSrTioNlpwGzuN5+g4RQMKl4Pbq8BgyLtfPnlKZesJvk9L7yY/O7SYNrrPkeZsEwzYDGCwTKNackxRG9+GUvlc5TuSGPiLklZ8ePOgok0GMCYsJUjB5YQbLHulhbkWKq+oJiMIxWkTtvMngNy1NxMXpMNg9mM0WujsclOm82JZdVmlmiq+rplv8kZb1jZ33vvvRFFGiw+YuIIkY7GRrpR6F67iCLzEQpdOcx4riWiS8aQUsepPamBBhqoOBTVHSRpWwqp2lROwdpazsVksP1QCakmA16XCy/GgC9bFcLndeNR7FTOn0gpc3m5wkRZVi39PggFjOf5t4/4/dfm7BqOpxsw4sbrduAITjj6kthal0S014Ej+Cms6FQ2HcqkxAumm6N5/IK7mraQk7MD6bY3NGwkx+nAWrWVaKUJl2IkNTrkR/B//k3rKnU11+OIzSDVDO5GO15zLgnPLOHdSH2rz8qh5cbQMNuQvJW6zBayCoKV6KK5upSiUhsYU9h+pIYlEX1QJlKfr+BtcxImWxlvpW+mcJIJ07YqjEWzqI2NRWmspMmVxKSWZtyxS7BEwEtxt1G24DEMmfng7WbX4hn4n9+AOC2LZ6huHUMs2fuPf6l5nGCJBp6jsKzaRIXGM6Q4qskrfsufVHFD8vZtZJrDGt9gDk+a+pxvULrsOWqlv99YS8FKB67UOqxRXmq9EB2jUZTyG3ZRYTp0H6PJnUC+7JidcpWYheUJy9n8G9WJ11fWVCwWL7EBrWUwZfDytnRq04IfRvThbNpFUVEZ54ghs+YIFX38T2FqlvQSqpItJBmaKDXlU5JuxhxdxVbphjKMJ6a7nh0thWw3NmJTLGzyu3DC+YPANBYvoCEmm+WKgr10DjNKNWmK5zC1WF4bsJYc4Uj+rdCYUVjSU3FUG4jNruNAocXvJiybX4BScZhN0ldrMIYUvfz2VGO93T/XZY1upKDgDeoKTThsNmwtTTS73bgXT6XeGEtCwjSs1iSG0M9pCn37gjes7OVk7JQpUzh9+nRIanl9Q5O0vjaqq+WTEEtGZjRN1S0UVtVw8pRq5yi2ItIKoOLINhLkc2DQWGyKtFwNGLyN5MxYS4uaJSQb7gbWzmkIX8fm8vbxzVi6d1NcUEm9Tap1I0mrqjicm0qMvYCy2Gz2HyhUVwTJnIqNovkbwx2PtB5iOtiYtoBd5/ozDLNSQ+MpOf4rBm3HniaWzcjiWLBzkJlCfuhYMg8dp6LvjDC+tiLSshqwPL+V7IZSmrBjN6RSkhCNz3EMh8FMfsgqDoxQQtajD6fNhaI4cMr5kQYHsenTMPnaKJi1gPoBvZzayU2Sgy1TOhVV4Guz+a0jKaqnuYyCSifT5sZwzm7BGhPuZPogIVdNZeX4y6nIj4lSS2OthD6BrYePc7LEQeX8OZSVN5DRfI7Y9BRC6lJaxQXFVL9lx8t4rLkVFCY7yCmzsvX4EfxzknIp5tSNpB75lX+irQ9v7cV14C2zR1uSSQ7qIk8bG4uOYZw7F+NbdqwpCg21dnL35w+csPY0kpf2HLakEjZZqilzKNjPxZBdYSXK00KT04hFmqGBww+NnHQOXHucdtyKF4fTRXdLE25LPgnRcjnkVLKO9W97BhK2HufwJJnZzJKqCvA1IWH2H65Gigp2oyQnYez2kmAN2rLBBMGzi30FORS3eP0ffpVc6hvkTKyRlJrjnDwJttJZLC6rJMXaiNtSyLQQKRdNGwvYWH+McxhISHierfkWGhYZSKo5xYF02YPLpZgzqM09xeFnIvToQTGus66C2QecjSZ1ItznUufwjTF9DD+Z3tdWSbXLSqzBR1JJPkqTl2NlO2g0WEmYlk6Gw0aDdT8nK6x0715LudfKoDAOEOA2R9ws15H00Z85c0Zct69eI0jnztkifuZqsXCK9MH2iJ7Ap9lVf16v6Dm6WsTHrxZHe1R/rCarENL/GDdbvNbf6djbKtZNiRcrQo5l6aceLaRP0+9t63pNLF24Wrywc50/f8hn37pGJCauE0e7ekRPT+DX+aZYMSVRbPgSvvTeztf8cxFTVkf2h4bL0Ct6urpEl/wF+Kw72qled/WIyxFdg5dFZ9dlIXo7xQsz48WKo51i79J4EbfwNfHmmikibuFejQ9W9anOfi0wKeFn3CPeXJMo4uITRdzogG+894RYPSVRrDna9YXl7m3V+M4DBfH77BM3iGtBdLmnUxxcPUXEL90rOnt6RPvOeSIucYMIuk4vy3r2z5fMFi+FndbSiS9a3zwqThxcHfLZ+/2qcq5h52oxe+ZMMXPmFP+8T3yiDM8Us5fu1Pi9w2jLuZUvj7cmf2+72LkwXsTN2ynaOwM++85W8cLsOBG/cGfE8l/ulPMXvaJ1zRSRuOGEaJXljl8tDu5dIeLjV4ijgfYuZWuX8z4L3wz73UWv6Ny7QkyJmyIS4+LEPH89XhZvLowTM19oFV3BNtrT6feLzw425KDIfXzngcjgM6NtEsH0gXPv5R7R/tpCET9ljXizq0d0ybkhObcVrJeuvYG5tjixsN+kRc+JN8XRVnk/4LOXbSs+Xqx47QWxdLasn0S1nqeodTVz9moRmsboI8f11pWKT+KanWLnSwdFl5DX0m8fJ+Li5E/14Qevp4Sely7x2rx4MfuF18QKvy4a+PB1+edUXhBH5XzG6ESx7kSo8vpIPhwubtiyD/ZNN2TJB4nIsxwOl7lIryqBjR0QZVLdHa59LJi6FjmgCh5ZU6WFbiRj/ymqklUL0uNopttg8fvogukinX1t1ezuTqBwT7LqHzUvZ8+B5eDaR0uZtFTDh9JdS9aMkD0UuBFLbjhJOORz0tToxJKeHF5B43yDtYuKsUlf4PZ0zRAxnC0cisJkDsxR+FxEGwwYY2IxR3SFBHNFY/FnCfiPDLEsqdqPyWajOkchqUrD0+fB6ZErXsLWI5hI31pFdvMCdhkySQ2NAsAYo7F2jMaQLznI+Uud5XLaxeWYt9aQL9doOqopa/Bi3WQlRmkir9xJelVdaClrdEIGSYYG3opNISVk1kuO0UxLT8XXJutftWYVhx230UKM0oYjKp2qTakES+i1l1NQ7cQnF7sMGGhcD95qqX3ORkqX5VAb9Tz7969ikrdavWGcxvr9NXjnZzEnzc72V7eyROPWiPZXVnDljRHrqhrqzHZs5Tn+dyOSNMat1+3FYAquRpPko7AsqaDi2AyyGmLISJCVpWIQZTJhNgVNaoO6xFaV6Dr+fTTlLWB3Sg2vLjETpdgoL2vBkJqJxehFLt8ku47s4OjGnEyGFVpsVjKSgzKobE3J6Zh8TVQGpXDbcSgxpBi9NDhNrKoo9K+m8t/22ijNa8Ddf5Div3kddeVpY1/lLnbZFLpbqmnK3YzqfZPvM9RwID/gxllUhG/TATZPk26cGPUZ9XlQLNlsXWVhl2aFZrAY8mxOz8ZaXEzWc0b/SpwSv6tBm2L4hIffS1WWdEq2VrEpRdvApctgCUcuXeLSpUucP5RJTEwG+8/L69+FFL1cqtiyrwWscwNL9AYHOmraNt69cFgd8g+ezH/HMD6Xt/28VP6Xzu8nQ6MQtdl93Y1UFi9mxkOPsWzjPpqbqlmW9hyNlk0cqluO5pnXZrv54WgzSn05x2Lz2Zyi0R6KG4fbiFkuaA8dPjp2FbOrO5YEYwM5eftwRnzYQhmuL6B4cdrtIdrRCflUbM1AKZ/DxBlrsSVtY1NwxtrnYHdeAW8ZrIzv3kFOadM1Xljx4fC/gZWC301unEZScjLJgV9KgjnkBrk+wfvnkvMSeaTNyKHRvIm3D61Xl7lqk0Wnsu3wIUrMjaydNZX5Rdd649qE2VNNuSOBwsKA8eGnJddtK8RYA+u6A/Slq6yoQWF8AuzKKcb/wrGW900Je3E55fxToCGYUlhfVUJyRzGzJs6i1JnOtpJpgb7TR1tlHqW2GKyxNkpzttB8jR1OPPYmHIZJ+PsEgwlrSriuklPkBPJNPNx2Gm2QsnU/J8+/y57NYcPHYDQTazZjjo1FzuFHy4UI8tr/PorsVyexqmI90yIKJOc7qsnLKsVvGlrz2bw8FlveDNIq+7+GfhPLcwOkbpplfwMy9MtqJlWuvubt6NAAABA2SURBVPG19Y33+UJLxr1edRJW8Ybj/CtkXI1UH4OE7cnh1QQ+J80tTgwGdZK0r82hYeFz4XC48LntuOQkp+aW4nXSIieMg1ahz+FXWJH0vVyvf+B3mXS8UU5Z2VoWy9lC6fOvWTXQf6vhETEYNY2Kd38V8da1I704qvPIazRRcijX38H4nE00tikotkpasLA91Ot4aKvOIavMRUbNEaqS7BTML2O3vQQUdcJTrlBQDwW32xh5RBNMEjwbQHE7sNk6iDJF4fO56D6m8s4M8lYUZF16FCPWFCuut3KYv3ITVestNBblsMOWwKZDdWQq5cxfkEWaayt1VcuZFOWirdmBYnfixYxBcVDf7MUiV5EooLQUkfbkllAdKt5zuA0Rx2FBadXzUPF2NVNb7WDS1kNsXT5w5UqIaPQ08vecJGl3McXVNrwsCd0KBxS8bVvIWWsjaXtgvsEj35B14PE2UWkzMKkkPKzxNG8hK6sWQ+5+Dm8207hyEdUNDrJRsJel8WhlqLLwuhUs6WFO1wwpLlqa20iQ68x9HryOBnbZtbwVfB4PHgViElIwO+rJSoOtVflE1+aRU+tk7vYjVKU6KJ6fxeL5bl7es5VnzHKxlw2n0oxLMUCUF9s+GyRUYDU0I+fQ8mZ1+JWtXz7FyznFxBeKPdS6siznVTliH3AodO+YxUO75GqgwAq1BQ/R4F+5ICfzj7C539xYkISsg5y8HbS4YfzcEuq2W2jIymHZSidWm0LMkkiaIZj7qzsPQ2UfCQwn1QtmUKr14QCqG0dO0KZQd2YPSV4FU0Im2X2W+blo2LhYXfkQM5eXg4qmPxv54k5WFg3SE2LNxT86DqZxt7B7hzs8LFY82L2QELw/4BzNpGc2s+eZ/MDKlFqysswcijRhNyDvTYhw2djdoJBZU6e6SyRJVxNlz+2i2xBLSkkN/nkxGe+xUVuvkBlaHmmi4lep6rIyQwwZm2p43r9XhfQW2CnLCr4ieW05TZMySDKWUrz4WCihIWY8Sbnb1OWmnibyZuTQZs2kcP9JlkyTk8lvULZbwdtYTq0zne1HtgfcH+s5vF8hq6iFbu9yJuGisTSLHXaFmLmrkB4sy7RMktJjMDSAwbqKbfJlrABnxV5OXsDDEhLmRgKmZ6iKuFQpEtFopi2v4kgkfSOTK26adh3DKF/CCy4xxkl9aQ4NbgPjM7ZSEnBR+leGVDdiLDxEXWB55JJX32UJHhob5eqSKmoyg4rGS8vaLAbxPvQVNDaJ9IRKdqxdQGjpgiEGa0ohz/u3v3DxxqIZrHUlkVtyhJpnLETJFwjL6zF072ZLg4/smiNsS5c1YabicA0sKqfFqfCM2YCzvoDFcqZ/fLbqIrSkkiknhaWyNyaRv61QfWHRj4ccGYSk6CvnTb3SuHEi0DUOtrBAOhGtqaRmmslfkklqQJ8kHdjO2pXFNJpy2a8dSUeg/VVF3SEnDr4q5t8UvnI3ytoOC9nyIfmmFHoI5ZQ+9H6vLIRyRXSvh+7qgduOwDUq6xq3bruYOsPBEdCV/eDY6Hd0BHQEdAS+NggMvwnarw20ekF0BHQEdASGDwK6sh8+daFLoiOgI6AjcMsQ0JX9LYNWJ6wjoCOgIzB8EBi2yv5sF/yoSwVKG+YqnP0LvPKnQXfv9b9j8p/a7QaGD966JN8wBFq74NWPb7zQPR/DOzeBzo1LolP4W0Vg2Cr7/oC6PJBrh4mtsPyPIPuBiO9tKGq65Q5459P+VK59fdYNr18eJM1VqPhfeDq4ydkgyb5U9Mcw57fX6LS+FLEhJv4Cnr6/wBgbtF8dIr0hJvP1wquXoOsm0x0i+2snU+BHJ+HpHmi/AKNa4Z0rahbPBzD1XRin+Y06CaM01/Je9geRWZhGwmYHnL1WuXvh6d9CD9B6DnL/otLyeeHp/4XHbZD9Bzj4AfRcgcJWGPMujDkZNogic9djdQTCCAy7dfa+v8LTv4eOz9WXwMd9AGXfAcOd8JNYKL8PokeoD+XBj2H1t8KF8Xgh9yx4YuCtuyC3A9ZYYGXEN+DC+WTol52wWW7wNKFvfOhqBCy1wFP3hGJuOOBTwHmbF75+Ec8oI7w1ASbcZDMg6h74sRey7VA+EaYPo5bn+Qg674T6UdD6PkyIgZkB+aJHwalRfav6Ffmdnodhdf+2cBVescO23r7pvQKSWuXGHuFDflHw14+ouze80w0e2a4/hfwPYWlgtwyuQJcBfv0DzS4PV8FzJ9ROBfMfIT9MUg/pCFwTgZv8SF+T15BuRn0b3p4Ox0bDpNFw4YfwhHwb83PovAyvdsPmc+pDMeGuAMmr8MuL8PgZMJmhPAp6RsFbcfD6WXj6HJwNWGqRhOj6ExR+CrXj4YEICdrPqZbdD34L/+/Dvgn+sx2e7oLn7fAjG0z9bV8r7pfnYGqr+nvcHh5t9LhhYie4PoKHpJX2LlRohumvt6vW4iu/VS24UUFr+yrktmrSXoXnbZrrK/DK71R+kuaczrA1fU2en8Kz0mJsg5RO6OxniXb1wJxWGNcKE3+jcU0E5NncBc+2w+Ot8PTFyKOusQ9ApRFyHZHv90X29l21fwATTDD9KvzXZ7Due9fJewSsngwXEuCpkbBGhh+DD2bAB4/BqXEgO71fy3BA0cttbf71Q5j+Heh6H07cCdPvDvN3/RV+GGg/2T0gR0id8tWlwJOriNs8MgyLpof+xhAYdsq+P36+KyD3dqo0QfRIiL4LJhmh0go/vhukNf+sDXK98G9TYMcDEH0V1l+E6O/C25Ph7xVIskFhYHjch8cV2PYneMoMYwdBY/J49aHdHWnr/hFw4kNYPRH+Zyo85YN/CbiC5ChlvRdqE+DUdKi+H/7rryr3B2Lg12PBeB+cfwwuPQYFmlGK3OPlnYvQej+cl8oiASYPIp+2PO+ch1dGwFvT4VICTP8r5Ev/AHBNnnfDz6bD+R/AgMFNL+RehIUT4cJ0eMsEm89qOrWAktw1GX5tBU8P/HIQF9rk78P0j+BFTcemlf+2h6/CUSWg4D8BTzQ8FXz1NiCMrMcftatuliHJNxJWfhv+o7uvIv6lC8x/19egOCsVPCrPF10g96fTbulh+jb873S1/dQ+AF0emBQLD4+AsX8H03sh/2JfPkOSUU/0jUNgGA2m+2Iv96fp9MAPP4AtY+Bfnf0atAFqrTA5ClY8BJX3qfl7PvV/e4At94DnU/DcobpfFvrAE0FZ+z6BE1dhVyB/XymGdjUpJqyIf2yAbZ+p+aKkcv4MXv8Aou+HyWNg8tBIEn0nKHfCltGaIfwX5b0KBz+CpyYEFMpIKJsCviF0Etci3XMZOu+BnwQ6o7GjYLITTnwGD8vR1Qj4e9kZSyIGmDQCuiQGGgs1RH8kLL0X1n8AGzWdW+j+7Q6MgI3BSrkb3v7OEASQxkQ7bAsmvQt+9ihM1+A8fSyMbYdXPlY7cd9l2NwL5f1cQg8/CB88qBL68fQgwfBZWvbSZy/fvJ70fVitwIlLMPGiun+TbCPVli/RRsKk9dA3DIFhp+x9H8PTdugQqoI8JhuyG14cBcfkMFhW0BXVZeDfj+9umPctyD0DHf1cDzKp7zNwSktXWrmahzFYz8pn4LoTTBHuBdN80VnOJ0Q8vgX142HzJXj8PIz9NmwZD7JDGMphujegQIeSWKa5Cl1X4AltWUbeuCLwSMV9p0aWkSpeTukaC7jS+uCn5R9BdpMBPD618/6y20fICdS5LpWo4T51JBHJ9RaB7c2LGgFbJkfw2Ws5GODfxsDc38MECxx0wASzOhrVJvuisLTs/+cRVbH7jYcrMPkyrLDCEwqkONQ5rC+io9/XERh2yl76NHc9Cr4eWCVdDyNU/26nG+Z6w7tRygnc0GFQ84SuAwHZcWSegSfGRVb0MpnhDpWmT3YUX6Ck+tMfyrW0gndJa+4K/PwC5J6DUz/QKM5rERlEnj59xVXwBjs5ObQfCU4NNr5P5XeAYGwkK/tavDX3oiVDj1oPwc7WdRV+fJ2tR7mq4q5hMeTgZDP87/cDyUf0dYkMmchtSvjwGCi/DMvlXNL98Ovr6JXkXNU7H4DzI2i9AhvHw0+/Bev/BBulq+w7N38y/TbBo7O5zQgMok5usxRadlJh9dFm6s2x90PtxMDvYZgewZr++e/g6U74ZS9IP2v2GYj+/sChs5ad7FzGfgad15jA1ab/MmG5bO/Zc4HJyJEw/VsgrbNQ8UaA8ml4AtUzRBkeuBPaAt++kHMWrUHlPgJ+ch/88v2Af/kKbLark9khua+D5wNGmNALBwPzDWf/DJ0GeCI4QR4iPrRA+ycw9jvXOeIYCQ/cHfhdZ2czNClvMNWn8HonFP4V/l7uGvyh6lsf8tJTuRxTTuB/Av/uBpcBVoxR55VmPgimHsj8ENZ9P4yjnGhu/VSdxP25nDeSCxd6wu3rBkukZ/8bR2BYPi5+pSeXJN4RRrdHTnaeD1xfhfYISxYXPgT8SfWndgp4Yiz8bHSYRsTQPeryzRf/DPPGREgh16VLt5LcjVbyPA9jLoDsfI4NmMnsmz86Gp7oUVeoyDvSQv63h8MP5wP3w9JLkPSeWtanxkFtcIfavqTCVyPgp7GQeQF+1A1j74O/vxuC75DNfAhWOyDlXdVNMjkGqjUW5WA83/kdZEoiQl3ymvKeuty1fDIslaOtByG3E16UVvldsOXhwIR2cFQRlvCaIdkJ//tnsOX+ayb7m73p+Rh+fgle/AtERatLJGdKt9VlKLwAP+yBnzwAq78H00O9foTi3gO1D8FcN9Rrl15+Cj/vhlb/ZsLw4h/UFWiSxy+7wDke1n0M6z3w1H3w4kX46ajBFx9E4KxHfU0RGH67XsolgKfgqICfTIBd31VXd8z9ECrHBKziq1B4HsqmDuKeuQKvX4BCmedRWHith0pWrLSizqgTm6u//TWt6eFQrCtQYgfXGNj1RZ3acJD3KpT8Bl7/VO1Mgy4/uW5eGiLadfNRBmiwwtHfw3/dDT8do84l9S9Gu5x/ugSuGPhFJONCk0G+4Pb4+33X2cslua/IznYczLwDXvkDvPIZ/MIKYzV59aCOQH8Ehp+y7y/hDVzLV8yjpetkCDSkxVnYBRO+DwVDWZExBJp6kjACcn345gugxMCWmKHVSTi3HtIR0BG4UQS+1sr+RsHR8+sI6AjoCHxdEBh+E7RfF2T1cugI6AjoCAwjBHRlP4wqQxdFR0BHQEfgViGgK/tbhaxOV0dAR0BHYBghoCv7YVQZuig6AjoCOgK3CgFd2d8qZHW6OgI6AjoCwwgBXdkPo8rQRdER0BHQEbhVCOjK/lYhq9PVEdAR0BEYRgjoyn4YVYYuio6AjoCOwK1CQFf2twpZna6OgI6AjsAwQkBX9sOoMnRRdAR0BHQEbhUCurK/VcjqdHUEdAR0BIYRArqyH0aVoYuiI6AjoCNwqxDQlf2tQlanqyOgI6AjMIwQ0JX9MKoMXRQdAR0BHYFbhYCu7G8VsjpdHQEdAR2BYYSAruyHUWXoougI6AjoCNwqBHRlf6uQ1enqCOgI6AgMIwT+P72V2fgx+MkgAAAAAElFTkSuQmCC"&gt;&lt;/p&gt;
&lt;p&gt;Luckily we can always find a way to get around those limitations. Here I recommand the &amp;ldquo;Stylish&amp;rdquo;, which is a powerful tool to manipulate the CSS style of the page.&lt;/p&gt;
&lt;p&gt;Just simpliy add these line to Stylish, and everything will be there as your wish.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;DIV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;notes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;DIV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;visible&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;block&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Alt text" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXkAAABnCAYAAADlqDJiAAAgAElEQVR4AeydD3AURdr/PwRwwx83elwWwWwEWUAuATGACnIKKn8KERS9cEiFAgp+B5oqoHIFFJRQ5JUUWKbEMghnKFRSCORUjHoapCCcJ6C+ScRLIkoWOLI5NBsRdkWyC5j51bM9k50kmxAgauSdqUq2Z6b76e5v9zz99NPdz9NO0zQN67IQsBCwELAQuCYRiLoma2VVykLAQsBCwEIghIDF5K2OYCFgIWAhcA0jYDH5a7hxrapZCFgIWAhYTN7qAxYCFgIWAtcwAhaTv4Yb16qahYCFgIWAxeStPmAhYCFgIXANI2Ax+Wu4ca2qWQhYCFgItEkm7/OUUlTqu+rWCXhKKfVeNZk2TSDgzid7RymBX6WUAbwe76+U969S4avL1FfK29lv4/51GouA14P3V8r76oBrrdTm/hrA938EjLbB5ANudiyZxRMT/8jtvXsy4K6HmZ+Rh9ubz2M9e9Kz0d9tzD9Qv7f6vF685j9PKbkLH+bhhTtwm5+Hwr76jMm7g4m9x5DtUZ3Jl/8Yvf+YhdvoWwEvpQU7yM7awaXGHl/Rah57bAUFv9Tg4jtA9tKl5Bplf3tiBLwUhrfNP1C/3oFSsp6YxZa6iuoVDhSxYuJjrC6tj7EBR92vN5+F945hqd4W3h0T6X3nCppLFnDvYMmKfLyBIpbc+UdWu324tyxkRb4A5mXHY3fyxI6mwQsULeT22+cTyjJQwBO9I/UP/dltery6Av8MAU82Y3pPpJkimzKtZlfmUlbv0wUYTzZ/bNS39bLfuboBjgEOLHmM+W83xMZHwfwxPNGoEU3ZhoIecqbfy8RMvbHdWfyx9xi26P2mYezQfaCU7IVZHPD5KHjiNibu8OArymLh6gNIDdxZY7hzfkEoHDl9AY/1vlPvR152TGymrXoa8SJSuoKHPvIf680fjY9aKPgOsuTee5lf4MO7YzqDxyxV/SgS9cAB5t/+x8bfQAi3ibztPsDqJ+azozn8ItH9FZ61DSYfHYvT6SRh/Ghctj489dFxPnt9Bi4bYOvDsg8Pc+zYMfV3+F1S4uSF6QocYOFdgxk82PR311iWHgwS3LeIe83PJXzvfIzvzESlfrC6gMyFs5j4x9vpeetgHl+RS7HXT2V104xPGPz0x9dz8GAOmdnqQ6hPtHXvAj4vfudkJscVk72lCK/Xh238Vg59upnJdjvjXvqIQ4cOcejQR7w0vAFmUpTqYvIOVmOz1y+Xb18WuR4HI5zR9V80uPPkredgbDJzkpqKF6B0yxJWm0a86DgnFOdRXK0T85Wxo8DGiCQHBNzsKwNXQoMCNci33q30l3cPc/hw/b9Db6TQsJvUS/dL3wR8eIMuksfb2JeVR6nXhy82hfcOfcTzw23Epmzl01BbfcqHqxIaly7gpqCgjEBMA2y8+WTm+3AlxTVOY3oSKM0m251A6gyX6Wn9oDDwJdlFYaYd7cQZzCevLKgiBn0czC0idnQCMfgoLfAQk+Qipj6ZZu5sJKz5qFFbHT60lXH2CP2zGUpX8spbkM1B+3jmDo/BMTmN8eSTdUlG0EROdhcjHEWsXJJPw2G3iRS/2uMOV5NzRUUFNTU1dOrUifj4+KsgFcOI1HRGiHS3paARHVtMDNF1fMRGxO5giyXljU9ZO6QuYiM6DR8ESlfw8OO5eIJ+/EEovvc2MuOS2ZCmYsYmTSY5ZTkJCS4c0eArmMXEhR5i30infjYB3G8vZdaTuQQnv8SHc/xkTH+cMe41bF43g8SWfwUNi9jMvYfc6feytFj/ANc/zOD1w3np8Js8EhuLTUByxOGQgmMnRu5DD0WicXOg2IO/LBe3zY6/uIACmw3n8BG4ot3krN6Hc+5uhttKWf3YSli1leWJDXD1FZCR5SZp2VYavjIK7dkxn+lL3Ux+d5l6JDOExxeGZjkFjx2gsrIa2+yFxNogb/oS7KvggL+S6ocHk2s0cux4tu5exxB/PrMmLuRgtWqr6ff6WPP6XEXXZqurmpF34wd1b648EChl9ZixrD/amMSiwT1ZZH4cl8y7H63T+0mA0syJjK1LuJSxg1cy7o3DvDIiDodNmiaWWIeDEMp21cdVn/dReqCYam8B+ZU2Ej37KCiwYXcNZ4gTijIzKUtKY3NikANLHicrYQOvz3CaSxKaIeVn5OIfv4HJDV/pMWUQmP14JsFlu/Xvy8eBhY+zosgHRRPJq/TjL57OCmHGB2YTs3YuRcV+yorHcFumTsTmImXrGyxPrGbLYxPJKJO2CnLw8Xup3PA6o0JdUNrKaFxTMSM8Mr1thaCbvPX78FfD47fmhunNHkBPubMlseqj95jrlM+jCLfXjTfoh7JiinCRkKi3jc0WaqMgDkav2szmMj8eTwDHJQSicIa/fOiKmfxLL73EF198UVfi22+/nSeffLLu/vICoh/zExRmK3iL7tBu1ztbEI/bjVvnZQQqQwy5Kfq+gicYPH0fRvRG8UwfX7RrLs9vnUywOp+Fs/MYsWEDyXEOnJULwZ7A+PGjSZDOF/TirfaQl7WPo96U+oOMr5QdK+ezKLeSpKe2smGuEx9xvP6RgyXT5zP23jyeWreOtNFO9QE3KlDDBz7cRW5sCUNovt84mfHecWaEkgcoWjGG6WXJjJABpYnJhvEdBTw7yFiSi7uymiB2spbMp7o6lmUf7WbygSVkBpPZmuIiOjrA5AQvDy/axNTdqYRlwABFmUvI849i63hHwwqECuDeMZ/HFhWT9NJ7pA/RR7noBFLXvc6MgIcdi6azvjKOyWs3kGwHu8NBcMcT+JNW8caqJGzBMjJnrySYOoeEEOdzMTk1jSFluWTkQPLcZETgzwseZf3YW1kfoRTYJ0d62uBZS/EGol2kvv4RU82dy7OFWbMPMnXrBupBYbMTVzcuRpO4/F+cXK6y9hXM596FMCNUsUs1VhmbVi6hwFNJNTb8mUvIr64m4flDvJGQzcJcG3PenYywINt4F2XzF7Jj/JtMNTWLr2AlS/fZmPzu8IhSt680i9mPZ+BJ3sp7c116P40hKW0Dr6cGcGfPZnYO9ElZx7rRNmwOBzGeLLLt43h+QyouW5DildPJcs5hhksqbSchJZW0yjKyM/JwJs9lssuGjyDFi+7i1nqjodEccab+ZTxr+NvCtvJs4bGJGRRXBwkevJfbskexKg0yyyA2eTNbU11EB0rJnL6UwLKtLA/1TxuxoQHQR/Hq+czfp/OZpbM5kJTGm+uS8BSVUXYwH0+wmKV39WRRqB/EMmrNexEG1oZl/xXvxUDZ5V4nTpzQ/t//+3+N/uT5FV1VO7UpvXpoPXqY//pr03bu1GYO66/179/wb6S2uLAmnFXNfm1m/0HqWU2FVl5erpWXlGiFhSV6eK/28sxhWo8evbSHninUzoRTqlDVdu2hXg9qL1eo25qSp7WR9cqiytV/2BTt6Q+q9NRntJKdT2sP9e+h9ej/kPb0B5K4Rit8epjW66HXtBCpmgrtg8UPab169NAGTXla215opG1YANN9TaG2YNhI7ZkSU/1MryMFz+x/WhvZ/yHt5XL9rdAY1F+bt9+gUaPtndJLG7S4UDOeaFq59uLIXtpD26s0reI17cFeD2kvf/C09mCPXtqUZ7ZrO7e/pr38zNPagmkjQ7hNq6u3pp0pfFobJvj0n6fVZaFpWtX2h7Reg+ZpLz4tdR6kzdxeYcrPKHmVtvfpkZpg+WD/kdrT2xdrI4ct0PZWlWjPDNPLI1HPfKBN6TVSe8aoU13VFmiDBun51uzVpvVXWNXU1Gg1Zz4I3b9YXqOF7o0sm/u9Arzrkat4OYSdwNiiq+oDbd4g6dtGghpt77Re2rCnS+qwqnrtQa3XyBe1cNVrtJLFw7T+M/dqZ2oEp/7atO07tQXDemiDZr6o7dy5XXvtxWe0xfOmhNpl0IL94T4eyk/677D6far8RW1kj5Ha4hcXhPr6yAUfaEaJzPWo2DlPG9b/QW2a9JUXt2vzho3Uni6p0vbP66/1mrZXz6dCe/lBU9sZBGr2alN6GflWadsfkjgVqm1qKrTX9DShtgp3TCN149+WtlVNlVZeuF978cFe2rDFO7XC/Tu1xcPUNzzsmXKFc02JtnjYIG2BmY+YchQeMKzHIG2B3sFrCp/Wpk2Zqc1bMFMb1KO/NnN7oVZe1ZJCm4j+SsErkuTPnTsXcVhq6nnEyOaHjkd48/gj4F7NnfduwvX8R7w+VZ9XPvKIOealw9FOXC7wHVjIE7PLGJGShDcvh33VCaRsfpNV45uTqH14RIoeks6/Ti4j4AuGZgQyvYwO64tCZfBkT2fsSjcJyc/z4aqpdSqZIXPn4hqTywHvDKY6nIxf+x6HkrewculKFk2vxvHpBka3ovom4N7C/NmbiE79iPGl83liSzIbltkIBs0qDFUPzHMQzwHyKl0kj3AQ8BbjtTtxBqrx2e348jeR44zD6XKRMHk5mxMymb86F/f4VFzefJbO3kQwIQ5bhEWnYHUeGTkJzNm6m/TRJnEyhJqXt+eP4cmiEbz0egoHn1iCLSGN9NFLOJC/ntxKWUMpwzfVgc1dgBsnc2ObafKQJBUk6K/G77eB30cwCD5vNX5RK/j9BEXqbIZEy18FKFrycGjRzpwmGKymOhhk6Zg7yTSmSnoE59zXeXNueP6Dr4is2fPJd63ho8R8Zj3hJ3VzSqjMNkd03UxPTRRMasmAm9yCahKWJRATLKPMb8fl8FMWtEPZDjb5nTidLhKGp5A+zsmKRZnkLxvBVIeHLfPnk2dLwB7WtJuKf5ScjGqGL3uXzalDGuHk3vIYE1d6Sd76OqOzxpAZO4JlafvI2JdHVr6fYGwBnsBoYoJuDnhsOJ0N1gtMORnBoN9Htd+GLShyPQSDXmkmQGbxjpBa1Ih7xb/RDlxDbLjsYHMNYciIWGLSX8KV9SQr149hwCahHAzhzsMDyLOBPWkNu9+citFjqw8eROZOuQuXMnn3OkYPSef1N2WSeoD5BcXYnE7s/mLyC8ooKvbgmpvOVFNTX3HZf4aEV8TkO3fuHLEoTT2PGDnCQ3d+PpUEqVz0GEucu0nzzuauJw9GVL3YRm3l0Ouj9Y6pNxhBpfYR2q40NqzKZOGiHI7GTub5d5cx2mHD7/Xix67rqlUhAv5qfMEysiYOYCXjeGmdg4zpOVQ2KmMfnvpwd0g/7UzZzEfjbdipxl/txm0sJAaGs2brcGL8btyhzgvEjGbVu8ks84OjdThOqGTegtXMnr0eUcvb8lYw2+MmYcMaYoIFeIN2RsfU6QsISBwTE/IeyMUdN5nRTqjOL8PvnEPSI1P5LNKYGkjg3Rn2uum0bcQatiYfZPpCAyAvB7JXsmRlMdhH8fzuzUyNqGtyMPqpdXzoHI6jOINd49NJS3TgWLsB+5J7yYmLI5ifRYF3OIkHD1AdNxVXBLyC1UVkPHwntuRU8Fey6fG7CH23enEOPn6XUt/Y4kh546PLWqcxatT4NxrX3FWsM2mAgu5s5i/dFYoarIYRz68l2RkG2eYML4YGPG+z8oknyRF9vj2HhbPceEdvJSHaT44fYmJNDDIYgOgwHSr3UVCdRKoMyB7Z9eViRtIM0r9Qyrr6ZR2Ny+UnTudWNsdkXlo7npwxK/RoATwFm1iyJIOjxJK8eTfr6umZwtRc45exYYSL4bYCVjpSWTbeiTNmA2tE3WTrQ2xlLusPpvG8PZ/ioItVIVVNOH0oFKwmf+nD5MWmMCMYpGzlWO5aaYqzdCyDl8q9jYRlu9md+nNwymhc40fjzrYRl7KVN9NcIXVgxsSFBNe9xyrRydrsdQwePOTnlim1U0w+Cxe+zdY0B+7iYooPFnCguprqxweTa48jKWkICQnDacH4Zqr0Lxu8IiYvi6yDBg3i3//+d11p5f6qFl8DRWRnyxcQx+TkGAqyD5K2YTOfHlJyTbB4CWMWwrrda0mS/m8zSWhBkVRt2Pz5zL5rEQdVkrqyUZ3HorF54fu4OXz4UTquyi0sXZhFbrGwczvD527gvTmjiS1bSEZcCm+8maZ2+EjKYDFLJq4IDzgiLcSWsmLMw2w62jDDcFYq1IdlH/2LJvuvr4An7prOPmNQkER1euY4kt/9iHX1V3oJFC1hzPQ8XE+tISVvJQWUUWYbzbKkGALufbhtTlLrpGB9RlInLQbwFHsJBt14ZP0jz03c+CE4AkUsvPdhchuNbmpwS5TJlWM86zZAoKg4JA1JUX0HMliY5WHIuFiOlrlIiA0PLvWQkF1Q02eH6hkUkZsc8nME+iTWvPcRny5zkzVxLBmZeUw+cJS48aOoY5MiBS9cSvauMvz0IWHOOtJGuJmdkcCaj3YTWmuULZWDVzB6979CC2j18jbfXAHekjzGNYIRBg/yFbFiyT7s48Zh31VGwqggeTllzHkjtfFCtC+f+WOepHj4Mla5sslwByk7GkvKugSifQcp8NhxidipXyFoZDFZv/d5yqgO+nF7vFQeLKDalUpSjGxrHMz0fQ37no2kNR/xXqIkdjJ1wzoIFCAwhy5vPksWbiE4Yjj2Sj9JCYbsakQwfr3sWDibpQf9Im6H+n1unqyw2hm1+SM+/RSKV97L4xlZjErIp9qVxpA6Ul4KVixkRe4+jmIjKekp1qS6yHvMxvDNh3hzvIzcsqXyLnLmHOK9RyKM5EYxrrCtjOSNfu0OtcAd8Cqhxx5bT+CT+IGiLLK9CcTZAgxflkqwwM++jPXk2xJIGjKeye5i8hLe4NN1CVRuWUSmP4EmYWxUgF/hwdWoiUQHf/jwYe2KdfGmzMtfflDrP3KeNmWQ6FirtCpdca70dTVa1d55Wv/+87S9VUrfakqqaaJf7PWg9lpDpWJNobZ4UH9tZp3iWPTQPTTRWYa0aRWvadOmzNOeeXlxKH2dTr5wgTZs2GJtb0WVVlWl/5V/oM0cNEx7+jJ05TXlr4XWGgbNi6zvDNehRquqqNAq5E/PZ/HecnVfUaWdiaj6O6OVV5zRtJpy7ZmR/bWZe8u17dP6a72mvKZ9sGCQ1mvKdpOOVelMH3xNX3QIZVylfbBgmNar/zCtVw9d912zX5s3aJi2YG/FJetdU2jSjesVCenkhz2tNQfRmapybee8QVr/adu18qoqreTlh7Rew57WDNXoGWnn0HrIg9qLYaW0KOm1wg/2avt3zqvTyYf0prKW8PI87cGRI7WRIweF1nX6D5PwSO3BaS+b9NphtGXt5PLxNqWvKdFentJf6/XQy1pJua6TLy/Unnmwl9Z/yssR63+mXNYnarTCBYO0YU/v1wql3v3naTu3z9T695+p7a1bKKrRSmRdZ8oHYb26VqOVb5+pDeo1SBvWq5f2UKgdz2gfTOmljXymUKsw+mhVeUjv/aDRkY0i19ON6w+Nb8bcJYz4+m/NmSqt5LUpWv9BC7QPKqq0Cln7kbUro10qtutrab20KQ0WJar2f6DtLZT3uk5e+lb//trM157Rpj0o7TNMtfMg1VYjH5yn1S1T1CvHlbaVwmfYgpe1l1/cqVVoci96+V5ar17yp3T0xv2guu+lQnvtof7ag8+8ps0M8aLGH19FaM3kGW2vrFf0GKYt3l/XePVK3lZurkiSN8aiq5LcDSLyK9PeDC/jNyyDFaUQ7VBqDe8OHh68CJk4Gdf0wSKR25n8xiE2jFASo899gEqbK6SDM+JF+g0UZbOlMom010co/adzBq+/OQO8OziYIZJp+ApW5jD9rjr5R38Rx5xwlHAo4KEg34Nr/IjwjhjP2yx6bCnFout7frxpKhhOFg5F43DqaxABLzE2G/bYOJwRVR5GqhhcoSS6nsgWx9QNb+AoLiZ7dpDhG0x5Bnx4fLKDJSwtgoPxazaQcuBhNtmSGV0n9YM91iTd2O11umIj58v6lW2xj2fiXLOZVNlr6c4mI89PwqoEYoMFzM/0MH7D1rotqTFJkxluy2NX3ChG1YnxkmMMQ8aPJlAk7a+k16C7jGq7i9hgEe7o8WxYNRqjhv6yTBZmewjI5pVGE4srwVvVOuDJZ+UTs8mJfoo33phLoj9bvbAPYfkbm/FPnM7YMWU8/8oapprUFzGhxjJ20thJmLuZrc4yijNnh842DDcJs/5qPzaHsbtMyEfjmrqOdfvuYnpeLJOTpLEUBtEOB06HIULb1FZZVaIr+B+gYP7DbBm1mVemOokOFpOZcRDb6GRcdj+yDZOUraQYsxnnCCYnwMHiBCaPMMqgsnWMGI8jUECWUYrqMtzBWEbZ/eR5HMxdlxbaHRV67S9m5fw8qhtOSkIvr6CtfEXsyNrEpuIglQezKZiTjtKyyXmEzbyZqqtrHltCYNWbpA8RdU2s+kYDPoKuFNbMdbHJtNPSqIb8OsenkLB0KdOftId21iwLqRbMMdpWuG0chnKNZ9maDawaZe7YohqYyu6TJzl58iTH3k0mNnYybxyT+6/qGDz4OLjjICSM07faNQ1w9JC1fHb8PTW1bzpa6I2tzxw+DOWl8j957A0mmxihOXmgMp+spY9z16138sSKHRwoyOaJMU+S71rFu1tnYPrWzclaPxzjJJibyb64VNJHmbhGsBp3tR2nbEivuwKUblrKpso4kux5zJ6/A0/Ej6wuwZUFgn48ZWV1tGOSUlm3ZjLBzLEMuGsRxcPXsspYiQ642TJ/IbtsCfSpXM/slQXNHDQJ4A6dnBpFSA1uH8LwESMYof+NSnLWqTuurOANU8m6w3zG3DWbfOcqPnx3udquao4WM5q1773LMmc+i+4dzMQlzZ2QduD0ZZPpTiItTRc6QrRk33WQ2AR9X7ZOX1RiS/KC9EmCTbOXEjogbM67VcJ+vB5ZX9I7gmMUyzcsY0TpUu4dcC8rPeNZu2yIPmYGKMqaz8riWBLiilk5ezUHmrFE4isrwG1LJDQW2BwkjAq31YhRsjDcild1GfnFMGrNG3x67DNeTw8LPDa7kzinE2dcHLI2HyMbDOQ+dJ5ExtNE5q5bzpCIBZL1jGzmT19JSCRMSCV9RhzF8+9iTFbDY+OtWJ+rJHVVkvxV5m1K7mS07KYJFJmeiXIsULfl2+9Xi6tBf/hZaMeLN5/sfZD0/Ijw7oCAhwMHPdhsavGzvoxhyiLgxe32EqguwysLk6ZXQb+Hg7IQbEiBAXeIUUXi87Lf/s2vkil9O5OMjEU8LquAotPfPLexftaUR8Rg9BDWffaviK+af+jHnT2f+fkOlr07JzSwBDwF5BcFCRZncRAXz9eNNj6KsmczPcPL5M272TC8jIUTM9hStgyCaiFTdhyoK0h1tT3yDMaIYvzaIFjtpri4lGhHNIGAl8p9Ku9kI+9gEGlLX9BOwqgEvLtmM3HWKjYsd5G/ZDbri5NY9e5WkoOZTHx4OmO8a9i6YQaJ0V6KDrgJlnnw48QWdJN7wI9LdoUEIXhwCWP+uLquDYP+o1TbIs67jNKq35bi7T1ATrabxDXvsmZG450odURjhpD6+qcM37KUpdnF+Jla9yocCOIvWs3sRcUMf15fT/DJiVY3Pn8BWcU2EpeFpzG+A6uZPj0H25w3eC/dSf6sx8jOc5NCkLKMMdyeVddY+KuDuMaHc2o2FPRy8EARSbJPPODD785jU5k57yABnw9fEGKTRuF05zJ9DKzZkEpMznxm53gY9/xuNox2s3TidB6fWM1Lr6/hESd4DhTjCR7AG7RBtJ/iHcWQtI4E2wFkjWz+vaUhJhsqX9DP0aCDSxa7pW3lmsErMkNvdAWpXH8vt26S3T1qnYGHbyUvtCNBFul3k95g7csgIW0we/56DlZDn3HL2Pq8i7zps3liloeE4iCxUyNxBiP1r/vbRph8JBA8ZD98FyvNuhpAqWtk4XUUWw+/znB/EEdSMin1tut5yVvxuNrJEDuOlwwG0zAbOXAzfTp5ovFImENoFmzEqT7IlvXV4elv0EeZH5KM941+Y0h8JJ3XH0nVd5rkMH26k3cjLcQ1StsKD7zFbMkLkrx5q1KLCElvARlPbqLSFseoZZsJrXfJc18xOblBkuu2OTpY96/RanuYLZbJqzbzVMimhGgFysiYbhxpbL6cjsTJDLevZOnj++oi2mL7MHzOWrVt1FfA/LtmU5SQTNobnzJ1iCwSv03GliD+/ExyPON5fvfzuppjOe+9EWT6koNU+meQiJf8ldNZXxYkdtxcRFPlGpLM8PGx2PLAljCXtXKISs85WJbJfF2TUleYqwk4HmFDxK1HkYjGMGTGBnZH4jMSPVhNwaZ92OXwnLFVGA+5K2eTV22jz+Q1LNNVkaGdHtn52NPeZau+zXHqK58xFR/5+bJbZAObkw0G4+fgouk0oWWoX9C44YxPymL9ooep25JgiyVhVBpPhcxUeHn7sbtY5B3OnGW72fyIi2g5+JeZi61yC6vzAqRs3s3a8dISTta9txkey+SgJ8gjThue3IU8Liv4fVKUKtA1mmRZ7BUmbx9O6to0ddAwhIfMBOpKUb+crXpnUtdEoGtvasOAKAsTRjM62Unq1GRG6/xk+JvPs2jWUvIdc3jDPHOOQPvXfNROFgd+zQJcq3mLdcicUhcp8nFcq5W8gnqJjrzBkYM6KhHV53VvrcAvjkAzjdXMq1+8mFaGzSNgMfnm8bHeWghYCFgI/KYRaBsLr79pCK3CWwhYCFgItF0ELCbfdtvGKpmFgIWAhcBVI2Ax+auG0CJgIWAhYCHQdhFoU0z+SAXcV6HAMoephSPfw8ZvmrSiGzob8g+zWYC2i7lVsmscgcIKeOXHq69k1Y/wcSvQufqSWBR+ywi0KSbfEEivD+aUwYBCmPFfEP4f8bxFUMWb4YaPzzek0vz9kWrYdqaJOLWw7nOYZBgfayLaZT3+EcZ+2cxgdVnEWhj5EnkGvoeexVBS20J6LYwWqIFXTkJFK9NtYfbNRwvCfZ/CpCooOQ7dCuHjiyqJ7xQM/gx6m/66fQrdTPfyLuVU5CwcHSDdDUeaq3cNTNV2ZBwAACAASURBVPoSqoDCozDne0Ur4IdJn8PdxZDyH9h5CqouQloh9PwMen4aFoQi5249tRCoj0Cb2Ccf+AEmfQ2lP6nD2r1PQcYNYGsPj8ZBZleIiVIf484fYV6XcCV8fphzBHyxsKsjzCmFBS6YFfHEWjidhPaUQzqQ27f+87q7KJjmggmd6p5cdUCsQXp+4U2rl8oz2g67+kLfVh7yozvBA35IKYPMATC0TfQ21YS+s1DeHnK7QeG30DcWRurli+kGh7rVb+qN4h+nH8xr2BdqYWMZrK2pH9+vwfBCMcARvsRz3ye3KSsLH1eCT/r1eUg9DdN0qxZchAobfPIHkzWGWvC1h5zB4PwvpIZJWiELgUsi0Mqf9SXzixgh+nr4cCjs6wGJPeD4HXCPnJ78CcrPwCuVkH5UfQx9O+okamHPCbj7MDickBkNVd1gVy/YdgQmHYUjumQWKdOKbyDtPOT0ge4RIpQcVZLcH76Ev56uH+EfJTCpAp4qg/uKYfCX9aW2PUdhcKH6u7ssPLuoqoYB5eA9C7eKVPYZrDNNx7eVKOlw45dKYutmSNe1MKfQFLcWnio23V+EjV+p/ITm2PKw9NxsnufhTyIhFsGocihvIHlWVMHYQuhdCAO+MKkg9PKkV8CfSuDuQph0IvIsK747ZNlhjjvy+/rI/nJ3JaegrwOG1sL7F2DxTVeYdxTMGwjHk2BCB1gg4Tvh1F1w6k441BtksPtEwjqDF7Mzz56GoTdAxbewvz0MvS6cv/cHuEPvPylVIDOicjlypH+tQe0XngmGi2aFfoMItAkm3xC3wEUQm0tZDojpADEdIdEOWQnwwHUg0vufimGOH54bBOu7Q0wtLD8BMb+DDwfC/UEYXgxp+jS4Xh4XYe03MMEJ8U0gMLCP+li3RDKdHwX7T8O8AfDPwTAhAP+jq3xkVrLcDzlJcGgoZN8I7/+gcu8eC5/Eg70rHLsTTt4JC02zErHB8vEJKLwRjgmTSIKBTZTPXJ+Pj8HGKNg1FE4mwdAfIFX0AECzeV4Hfx8Kx/4AjSYzNTDnBEwZAMeHwi4HpB8xDWY6c9w0ED5JAF8V7GlCVTbwZhh6Fl4wDWjm8v/i4VrYG9QZ+znwxcAE46isXhhpx/tKlDqlReXrALOuh1cr6zPgPV5w/r6+IHFEGDsqzxe8IHbjzKY3HNfD50NV/8npDhU+SIyDflEQ/3sYWgOpJ+rn06IyWpH+TyLQhibQhOzHlPvgjlOwuic862nQkW2QkwADo2HmrZDVVbVZ1fmQzX9WdwLfefC1U2qWKQHwRWDSgXOwvxY26emvpOUTY8MM+AEbrL2gqEQLU74A205BzI0wsCcMbGEGMe0h2B5W9zBN1S+VthZ2noUJfXVG0gEyBkGgBYNDc6SrzkB5J3hUH4Tiu8FAD+y/AP1kNhUF98sgLERskBgFFYKBSSKto98BpnWG5adghWlQq3v/SweiYIXRKNfBhze0oAAiRJTAWiNqR/j77TDUhPPQeIgvgY0/qsE7cAbSayCzgeqn3y1w6hZF6IGhBsHwr0jyopOXk9KJN8O8IOw/CQNOKPtK0keyXZfRR8KkrdD/QQTaBJMP/AiTyqBUU4xxn3TganihG+yT6a40zEWlGgjZx7sOHuoCcw5DaQMVg0QNXACPSLYi1Zo+QqN9gxfA2x4cEd4ZcS71K+sFEa8ukNsH0k/C3ccg/npY3QdkIGjJ5eisM86WRJY4tVBxEe4x16XD1TMAnzDs9qaydFB4eUQFpqvM6uFnzj9C2R028AXUoH25Zh5kYXScVxG1dVUzh0gqtgjZtt6jKFg9MIJO3pyDDZ7rCeO+hr4u2OmGvk41+zRHu1RYJPl/3qYYekhouAgDz8DMBLgnCKPcao3qUnSs9xYCgkCbYPKis9x0OwSqYK6oGKKU/ra8Gsb5w9YhZWG27rKpNHX3ekAGjOTDcE/vyAxeotnaKZoBGSAuwZwa0m/JvUi9m0R6uwhvHYc5R+HQH0wMszkiTZSn3hhRC35jcJMpfAfwmLAJnBe/OxAfSapuLm/TuxjJ0KfawRhkvbXwwBX2mGCtwt2URYuDA53w+c169Kj6qo8WE/mFIvbrCZlnYIasFd0In1zBaCRrUR+fAs9ZKLwIK/rAX7rA8m9ghajEbmj9RfJfCB4rm18BgSZYyi9cEmFU9biYyj/+RsgZoP/1g6ERpOe3voJJ5bCnBkSPmnIYYm5uPEU210gGlfgLUN7Mwqw5/uWEZfvdn47qi4wdYGgXEGmsrnpREDwfXhj1tbAM3dtDke5zQtYkCg2mHgWPdoU93+r644uQXqYWqevKfQV5drdD3xrYqa8nHPkOym1wj7HwXUe8ZYGScxB/wxXOMDpA9+v0vyscZFpWyquMdR62lUPaD3C/WO89rXTnLd5CKtsqZWH+HPytGrw2mNlTrRuNvAUcVZB8GhbffIU4XmX1rOS/TQTazCcTYnaytbBdGMgqWcQ8pt/XQkmErYdTbgW+UfrScg3uiYe/9wjTiBjqpLZhvvAdPNQzQgzZVy7qI7EKK3keg57HQQadfY1WKOunj4mBe6rUjhN5IxLxc/3CH2X3G2HaSRj+v6quE3pDjmEptj6p8F0U/CUOko/DfZUQ3xXuv07826tr5K0wzw2jPlPqkIGxkG2SIJvK8+OvIFmIaGrr6qj/VdtWMwfCNJld3QJzyuEFkcI7wup++kK1MYsIl7DZkAy+f7sAq29sNtpv9qXvR3jrJLzwPUTHqK2OI0U9dQbSjsMdVfBod5h3EwytG+0jVLcT5NwK46oh17yF8jy8VQmFIaO+8MJ/1I6ykQ23c0YgaT2yEGgbVihlK98h2KvBo31h0+/Ubo1xpyGrpy4F10LaMcgY3IQa5iJsOw5pkuZ2mNLcxyTtLlLTYbVgOe96qyP8bAhchGVl4O0Jmy41mP1shbgMwrWw7AvYdl4NooZqT/a9iwBi3vcebYO8BNj7Nbx/Hfylp1oraphbiawvnQRvLLwTSagwJZCDaXd/W3+fvGyt3SiDbG8Y2Q42/gc2XoB3EiDelNYKWghEQqBtMPlIJbvCZ3IUPEZUJC1ILxJmWgX0vRkWtmSHRQtoWlHCCMj+7vTjEIyF1bEta5NwaitkIWAh0BoIXHNMvjVAsWhYCFgIWAhcKwi0jYXXawVNqx4WAhYCFgJtDAGLybexBrGKYyFgIWAh0JoIWEy+NdG0aFkIWAhYCLQxBCwm38YaxCqOhYCFgIVAayLQppi8WAZs8cERoOoUbDQ2i+uoiOXE9EhGyfT3vmADezhNoGnQ/vgIPHVGWbwUA1xyxD4lkn152eJZDG81YaSriWx+0cdi/GxPUG0R/EcQNh5XeG+ULXoNTOWGCvYj3PeFyShZa5T2IpScgarL3GvfGllbNCwE/i8i0KaYvO97mFOpmuEfX0LIUcOnYecN4tjB7NiitAoKzcyiFl74r25bxfzcaNmLkFoGO8UAzkWYVAh7mjhxKpYvxdJkyFbOBRUvsQOUngWxw9LsdR7GSrl1c7GG2eE608HNJr66lzIoST6FQZgkDiZOhuk52sH7uiXI4I9QHg2OWmV0rM6Eczh6vZDs3+79qXLgYtRngDjRaOAAZc8RWCYDb1DZGtIdfSEnk8Xo1t0lkO6F/TVQVaXaWBxwiEMOw2lHvYytGwsBC4GrQqBtnHi9CHNK1FF9YardTsHB2yG7DPbcAuvlBEoN3PeVqqvsbxc7HoVngZPwVDUs6APR38KeaNjVRTlyqLgFMkynVypOQklnyBIm3YC5i335lB/gnX4QI554jiv76qli1dIP8e3BI2Zka2DvV/CWFCUKliTAzFp4VszHisMHjzILG30dvHN72FKlYWDtqlrrUonFhO5ZGNJDmSQoaQdZv9cx88NfT4H3O2UtcqeYZQaeFc9EMogV64fOOqpyx8gs6TRUBOFvVbDYBnJydp/p9K5YWRz1ralQNbDWD0tuhRIPeDrrJnTFiFoQZg6ob+BLTOhKWT/sCX/6t4mOFbQQsBBoNQTahiTfATbdodtfj4Eh3ZTt7KZqKScNJ3QFXweY2Q1Kf1DGnFK/hSW9oXstDO2mTsDWuWALQpoXZjobGwo78g1M+gYW36K/6wDrb4fVXZVqR+zOz4xTpo3Lu8CX4gCiD8R0hZmdILoDJHZWpyEdnRQNMRI2SRyKFOrS6iEo72CyYdNU5a7m+QX4GFgSCxWnoXu3sAVE8f70zkCYILZn2sHiOFjQDx49B44eyrZ9zg0g5nLFhr3NBgNtyu6OUzd0VnVaObMQCV5mWXe4lRkEo8glJ6FUzA7LjKoaEm80HYCqVTZ1QrOAL9QMrNwP3Q3Tw+L9KNLsyyBu/VoIWAhcEQJtg8nrRRc9+F/PQcaNUNKcbvs6SBRm1Rmm2BWjKa9UagcxziXemF44CyOF2Ygzj1p4xQ17f4J4s4GtWnjrGIz7FlYnwEOGGkZcupXAciDrd8r+TMxZ2PYtiCVGuSr8ENNZZ2I2mNIdBnaAB8RBRDsISfLiOGSwsjPzdwkPbH7w0mG44h9xaUc3uKeDmuWIvZu6k79BSPk3lHdT0nR8Zyj/TknrIZUUUF4TxkcMlE37PTg6woQb1cAlkrw4s/i8H/TVHVv8s6+ex3l49hTEx4DvO9ipqYG4rjJiwz1BDeSHxA77RXgfWCz2bDrAvFjY7oZtkdYG6ohYAQsBC4HLRaBtqGuEaVZD8jGouh42uiG+D4jbyxjDYJnOXA0+XFoNfcUIVw14O8K022BegyFLVCtiZExc4ImRLbMFRWGIXk0tPIqEKwy67hLLjrfCtI6w9gQssEO8HdK+gHhNeRXirDKHUJdG7NjL4PA17HGASPLJugpEzAAXFitGGe+Ad34mgyPim/RD3UHFLMMphlFAGzzdH7r/BMvE/nwXeAC475SylnjkJth7AR6tGxVUwmAQUktg1k1qdiBu6WTQFOwkbIuCCS6lFsu508gMTjW00VILaw/DqxKlI2S5lLVFAyMZaMQdnxhGsy4LAQuB1kPAzNpaj+plUhImPM4Dj8bAtnOwpyP8szO8cCHs+1IYaDBKqQ+EfLk4/Q5CyY/KOqRNDI593WB3ju5JStQWu26EZ4Xjy4ByUknvPiDH1YDBS4TzsNytHIuXX1B6blsnyBb9+zcw9wTYgzBP9ywV8MOkr6BIgz/fBBmdYVI05InkXqsWIJc08CKkStL0f5lJpJ9T78Xv7YdXOTBIGVOPglccqgBFp8DZDd5JhLe+hv/5LxSKESxdNXPkJEz2gLcdPHcr3C+mgn+nW+EUXfxJ2Ge2lNh0VdSbKOVg3XCELeaXn/49zNXgn7fAW2WwzWLwl0LRem8hcNkINJB9Lzt9qyQQJvzJYJjZGfoKk2wPaf+F/e10tYzkIs6LTXbZxb/q0FMwWTzd/06XLjsqP6fiW1XUJH0v6rtjxB65aTiLvwk+T4xgn97QCV8Hm24DZzvIvQO2CH2bcsIx8CZwnIbyriZ9d2fIHAB/7ggPxIAtCN4oeLUMBoh1TbGyKfr5spZvR5zZHz6/Q/39Pe7qYRad/N/j1TrCl0NhwXXg6Aox18GUm+Fjr5KkjbFEHJ/k9odEsSHfRTkfF6k9pRjuOALlurPpscdbtiVVpP/ys/D+t5DuhnQ/9IsF2yn4h19t4ZwW8iV49XW1KFgIWAiEETCxvvDDXzwUpVQZuu/pkOrF9pVy/2c4sg4Kw25v0jF3gL7iRESDPWdgwuVIgaYZgbmusv3wVYcydVzxvZotbDsB5eeUzl40GaKGkRmAeO+RhcIYGSY7wECT5cvy02CLhuA5yBqse1OSLY367iBznk2FRaffQHPSVNQWPxdvQ7LL5Vk37O8IeTJ4iQOooBoMxW2i+CWRfGVxe6BpB9J+2WF0k3Lhty9JeWeSbZWjvrt09nvc8D/nwf4tBGVwlHUDmQVFqfWXcYfV4D7hKjxZXboUVgwLgf+bCLQNJt8Ae1mATQ9AVj+11VGYauEpcHRRg4FIhW8dhWUXYNcg2HgE9sSp7Y3JJWH78/XcBTbII3Rbq/ToofBF2FujFhrlPr47rD4Hc0+BrQPs9YHsJU89AvHxMPM0jPsK8m4DKaaok0KOm36CV30w8BawnYX0r2GjEBSnJ8ZMIZThL//voVug/Ag8K4vGNtj/IyT6IdkDK/pC4X8gWVRYIvFfNGHzI7x6ARZ0gVc8MLdMYSwDr68Fg+sDt8KCEnD0a7CF8nt44TTYO0LFKXi2MyzoZvkv/eV7hpXjtYxA22PyF9UujXn9YWQH8FXDAPEOdR1k/UFviqBy6rBJVDaiWhH/sD/AszY1MDgk2kWY+3UzTRcF99tgxufhOM6ukCNb+s7DnDII3gAhqfUcrD0DL/ggxglZ3SE6FoJHYPtZWNwOxn0JpR1hVhR4u8Kj18PeKLVl8x6ZcVyA1OPhvH7pkOxpH3ccht4Eh3uAnAze6Vc7hkT1JY5TAjZIPQaF56Hvd3CfR3k6ktnKkBvh/o7wig0W91L734N+mKu7B2y2PlFgb6AYlPIk/wfuvxkOdVeL48s9sNZW/2xDs3StlxYCFgKXRMCyJ39JiKwIFgIWAhYCv10EGshXv92KWCW3ELAQsBCwEGiMgMXkG2NiPbEQsBCwELhmELCY/DXTlFZFLAQsBCwEGiNgMfnGmFhPLAQsBCwErhkELCZ/zTSlVRELAQsBC4HGCLRdJl8LVfphHJ/pUI65Cv8ogzSz0xDd8uOe7yHlqDq0ZI7/S4TlsFRov7zsM4+QoWz1vK8EjINfEqXkKIw9Ca98Ba80YaCr6kf4WLcFH4Gs9chCwELAQiAiAm2HyV+EP30edgIiB6KSj4Mwtz+VtNChhF4bW1e4Xw4fNTE4RETiCh8eOQ6TDI4tduUPK0uK/3BDsslhR7Pk9XJPcECpWM3Ur5BNnM+Vs42U/8DOU2rgSyuEnp9BT3EKYnjlMBJZvxYCFgIWAiYE2sxhqIAYHBP7NMKYO8D7Yps8AHefBr8Gk4vA3g5G9oGc6+Gpr2H/OfC5wXsTZN+krBpK+lfFAtcFZU/+HcMUrqnSrRasBb+cYtVPzsrhoG0B8MmpWw38PuhZqU6X5opVyEpIPQWl52FyCTwnh7nEoYYYDTsHz3aE8iC8cgPMkpOk4oTEBp+YDYGJ3fX2kDMYnP+F1FarjEXIQsBC4FpEoE0weVFh3P2lso44+XOY2QPeErMGg5W5XzHxO2GgbgNGb4UVLuWEwu+E58R65WH420Wo0pRN9Ee7wcCurW//xdwJ/nEYZogNd+Dm7+AvwuxvhGP9wFcFyedgV29TGW6CrA4wrkqZ2nWehXHHlImAQEflZGNaZ0g0mQrw6obAxMTyQCdkd4VywKlL/6GBUbc3Yy6bFbYQsBCwEBAE2oS6Jvp6ODREOdfYNQSGylH5dlAVhIoa8GnglbDJCXf3KGVATCR+bweYlQCfDIRp1ykDWPG1sOe/P68TiocSYJ8D7omHY7coe+wi1UuZPWL0SyRx8WVqOEC5DsS3avA8bDwH3W+AfybB353QPRoe6AxVfni2Irye4NCdc4hlzZzuIC7zEuOU85H438PQGkg9EVn/b3VxCwELAQuBNiHJ12sGcdjhgsIy2O6B/UDpBSj/D7zVHubdqkz8Vp2BIiARSDsB88Tglh/ePw9/Owz3iETcFaaI3Zif8Qo5MRErmnbYcjOM+i8sP65s3ZdrKuy4ATJ7QnQtbBNra+2h9ARsk8Vlvyp3uSwan4OhXeGeG3Qja4BI8uIAWyxDJt4M84Kw/yQMOKEbCWsP2S7TbOFnrKtF2kLAQuC3h0DbY/KieugItnbKyYR4Zwqpa/qb1DXCLL3K05MzTnk4qjgLQ2OVjntbLOR0hD+dhHktNF/bGk46xGa9ww45JnVNjkld4zutTPyKquW5myB4Aao6wbwbwFsBWQlQKLbadZPKsjtHJPl/3qYYujjaED39wDMwMwHuCcIot2W18bf32VklthD45RBoW0z+J9h4FGaK5woN0kpgLSDu8946BDHtYcUfYMKPsL09/CVKWX4UP6/i21SuKnEYfRL+dAEGusBwgnEpSMVJx6N6JHHM3dJL3NaJmdxltbCgA3h0Z9eitgm5yDM8MPWGbSfhfgfs/w76xiqb7OKCT+LuqVBmicV51S6pj36J3XqxA+85C4UXYUUf+EsXWP4NrBA10A3Qt00o3YwSW78WAhYCbQmBy2BnP1+xAz9C8hFAHEqINN4R3m8HmaJjNyR588JrR8jtCiWyAtng8sr+9ABEx8PiKNjmh2kmptkget3tlTjp2HMEltfAAzfCtG4Q7QPnjfCJSZI3L7zO7Kf08ZMaOtq4oIqxNwh5iVD4rTi3hTnl4AX+Vg1Db4CZDoiPgvhbwPGFsv2ePdhS1dQ1ohWwELAQaIRAm2Dy0V3gnTtMZZNtiRqkf6kcboi+ek+JchjStyds6q5c8ZWYkpRUwbMnYY8GM2+E908r36zb7C1j8iZSLQ4+0E+piowEom73noZRYqP+JyivhVFnlNORzAQYKgp8YxFWHI0E4dUTynGG83dw/w+wU1wLVikvTDm3wrhqyDVvoTwPb1WC+NMWR+cv/AccThhp2pFjlMf6tRCwELAQaBNMPmIziE6+H0wLrWyGY4if0UiXOPUe0hOyYtVgMNQNqT7IuiVS7J/vmSMG8iIshIbcBDbIVhZTK9pD1iB4oBP4/JByBHyxkCj1jLBovE08TXWEnNthZDvY+B/l6OOdhJarphoUw7q1ELAQuIYRsJyGXMONa1XNQsBCwEKgCbnYAsZCwELAQsBC4FpAwGLy10IrWnWwELAQsBBoAgGLyTcBjPXYQsBCwELgWkDAYvLXQitadbAQsBCwEGgCAYvJNwGM9dhCwELAQuBaQKDNMvmS48qRRnMgl5yCCtlT38JLbNRvNDsZkS2MVZD+fdMEfCajaE3HAoP2x0fgqTOw5wTsOQ9Sj5TqCClrIa0Y3jLtm48Q65p+ZDlCuaab16pcG0GgzTL5luDj+x7mVKqY//gSun2q/np/BvLXrRBKTINAaVXYKUkoVS288F+gozIt0CjPi5BaBjvFdsFFmFQIe5pwRBLTEfafBokqtuwlXmIHKD0LjgZ7/Rvlcx7Gfgq9C2Gw6a9bcf3yN0r3Mz4ImX8uboBXK+TXao5QgspMxJEG7VFxEnp/2YRVTn1gFWcr3T6HI6a+cTVV81VD75Kw5dCroVUvbS0sK2n9NuBHGNsURvUK0PSN0T/M31dTscWD21jDsU5TkdrI82b7zyXKuOdL5chH+NC2ECNonEAMK75S3UT/bBy9VZ60mcNQgTNwtxwE0qsldtIFp946E5fHcsJ00w2K4c6Rzi+ORsRszSk4eDtkl8GeW2C9mDGogfu+UsSkQ4qtl0Kx/X4SnqqGBX0g+lvYEw27usDGMqi4BTJMJhCkwUs6Q5Yw6YbM5BtI+QHe6QcxFyHtuDrhmnpeHWqKbw+eSgjUwN6v4C0pShQsSYCZ4kHqW9gvpog9ynSwmFV453YYaAy74inLfKRXx+U3/9MKjlCkPVPcMMEF/S6nB0dBZhKs9sPdR38DSF5UFlintHJR5aS1R2tlohY5HvgDnJTvtrhpMMS8ePxRGHcGcvsq+1VNx26dNwZLaR1qV0El+gY4dCcc1/92OWCIM3wvz0MMXvLoAJvuALGxnh0DQ7op++pNZR9tgwldwdcBZnaD0h+Uwa/Ub2FJb+heC0O7KU9SddJdENK8MNOpTtCaaR/5BiZ9A4tv0d91gPW3w+quaoSe4ISZcZAlDj66wJd3wqE+ENMVZnYCMYCW2BlkPHF0UjTEN+ykYiXJiyTQ+xCUdwibHDbn/4uFa+Hj46pMPQsh3eyaUBjt5zCgEAYUw5xvTNLJRVhXpt7JzGRseX21muEIRd6lVKmBMJIjlIj1vAjL3RDfG2ZdHzFGyKTEs1/CAJnRfQH/aEKqaphaVHdjC9WMasAX8IrJp67YV3qqRNEULOrV10zoPDxVDE+dMj9sOrznaHj2dncZfGyo72pg7CHYfwHG/a9y9yh9zrhkFiv9RWZ/vYvrqyFltjT4C/i4Gu6TGe2nYReVVdUwQGwinYVbxYXkZ7DOVM+PT8Dd0qaFSkiq+x6AwhMw+DMY/DmkfWdqb6NQzfwGz8GcL9QM++6v9P5wEZ4qhGXiP8K4zkNKIWxswtexEU1+Q+0l30wxDPg8jEFIGi+r70f5yAkY8BX4foT7PoenpH9+Dq+cgLHFMMnsRvMnaKr/NNdHzGVrLvxAb5h5Huaa2rO5+Ff7rs0weXHb5xMp2Pi7qJxuiMMN8zNzhUUP/tdzkHEjlBgfhzmCEb4OEkUl0xnEYqWtPZRXqg8ovQzk43rhLIwU9Y0wslp4xQ17f1Jepgwy8vytYzDuW1idAA8ZaphaEFPFy4Gs3yl3fzFnYdu34NVVAhV+iOmsGxOzwZTuMLADPPB76N4OQpJ8EhwarJyn/F3CA5sfvOrK9TMFxCXj/s7wyVD4xAmvHAurj96vgEAcHB4KhxPB8YOayUhR5CN79TqV7lASzAP2mxjt1ThCqaiG96+DxTKja+LynwO7Ew6LYNAJ/toSpyo1MOcETBkAx4eCCBnpR3SVjsy8joDfAZ/fCcf6qxnYRhNzDBVF+sHX4Pk9ZOpWUZsoYuhxaIbphxxpaxFYxOaSwfA6wYcJ0Lcj7BoGJ++Ed3ro1Gph7X/AdrNe1t/DWvGHrL8WoSYmCH/1wurb4dRd8E539bJ7LHwSD/aucOxORXdhF/XOdwpSTsHqQXBY2u0nmCGuNOX6EVKrYMntcOgOmCIuK/VXLfkR38ViHvt4Etx/DtJkEOwA86TO34YHDN8PUChC2aVsMV2EdA9MSwDpY5/0BlmjE01AvHiFkxm00edqYfv3cH9PJVCJ056ht8KKKHjhIvzdBRWnweDzTfaf5vpIS0Aw4kTBNCdUoV0QaQAAC4tJREFUiHahgYbAiNKav5cz2W3NfOvT0h1gv69bYwzUKvPCEunu78JTGltnyL1N3cvHnnwMqq6HjSLZ9VEGu2La6aR15mrw4dJq6CsdvQa8HWHabTCvwRAnqhUx9SvSzgu1yl69UVDfWWU6WBZ63xmoGLTxTtQwj96qLGauPQEL7BBvV3bw4zW9s52FvjfXpQgFpJ7CFPY4QCT55GIluYtp5cJi1SHjHfBOS+0l1yd/9XftYF6sGpjib4SBJ5T6YKBN2fsvPwV7OsMDXSCjXzg7W0cQhvH+GZhwA0zpG34noatxhFL4HThlYKxPst6dLRqm6VL+PQ7guJIc+zVob3Mi0ZWWd4JHdYYXYhTitOYC9LsI7/8Ez4mlUUl0PbyTpGZkZhoilb8q6r/4llkGDfkHEF/EpyBG8O0J4gr4klcUZAyGgF6f+Bsg5jslUIjHNPGqJj6GE8VwnfEBXJIoFFZB927KKY9Ef/RmSD+h1Jgx56DKBvfr9ARXh+76sgWk6fs7GKlzm2kxkHwaArEw8CaI/loxO3n/cRX0FWurlyIapb4VGSCG3gQDb4D1xsBvg790hhe+h2k91EzxfU25zpTvX/qn9GFfR/WditAXI76Ta9U311T/iWmuj1wGzlK1aHEOJH4xxFGQSUV8qWpfyfu2weSjYMVAWCE1kIp/BenipDsKul8Pu/oq8I0KChMe54FHxbfrOdjTEf4pjXoBhupOQoSBBqMg9CGhXAWKEbOSH0EYlq0GJn1dX42ADXISVEffdSM8Kxxfl0xFehcpIcfVgMFLhPNKhVAqlicvKOuXtk6QLfr3b2DuCbAHYV5XRS+0+PgVFGnw55sgozNMioY8kdxrlS5eJKahzTAlRall/2WHzzixWQzYusInUscWJBW1Up1hNfF+pdvrl6QPucB7ApaXQXIU/PlmyOyhmFv37pBzAZ49BqkX4J7fQ1ZvZSZZ0l6xI5RaNch0v8QHZZNyG/UTZiBO1Y37Jn59ImDIx268FwcwUeAR09U/KYZq9CWJ0tDngEh/qeeg702XoWLrArl9lP+Du49B/PWwug88cIn6Sf5HqpSkHpopao2l6uh28EBoRDIqdOlfn/Tfb6G3MSUAgjJgi8Ak+HQwDV7tL6OegN3kvEeYrKwLhK4uMLM9vOqHkV3h1QD85cZLl1UEq8z+SppPPgSBaFhyi3LAI6kf6AnLZYDqAT7p+yLdG9+TDIJGFsIjjLD+22T/aaaPhAk2INbUbRQMbA+GYNtUtNZ4blS7NWhdPQ1Rh7jhhQ6QdSMk3gR/EV310fBUVDIRaeOTwTCzs/qoMtpD2n9hfztdLSORNPVhGo05bwAMPQWTT8O036nBRCT6XUPVVFnUJH1FRSRpO4B4eTKu+Jvg80QY2tAqpLE74zrYdBs420HuHbBF6NuUOWSRVBxiPlhs5esdPbozZA6AP3eEB2LAFgRvFLwqesJDsPe8WrwZXNY6O0DEAfjnd6i/T/q3jMFL3UWFJoNl6BJJR7A3esx1MKsvfHInfOkCjwfq1BdRMDJeSbv/HQSJfkg1bSM1HKGImWWxmV8RpRyhpH8D+8WWfjOOUOztwlN7vWSNfoJ6WY1yB9up9Y9GEU0PYqSj/BRe+JeFdmGgfYWxiacuXdIzkvjEd6+BjTT3dbAvEWKqYaOhcjEiN/MrM4ZNA+HkEFjcEeYcNZWhqXQ/wlyPWnj+5A7Y51Kz2Kait/S5Q5zJ96i/DnbyDsUcRdoVTMRbWei60IJyGnEBvz5Ll0fiEU12oxnXozdBoReOyHfSGUaaBgQjTqRf8Q2d8Qc4PAzeccALx8I7kaLt8IA4G/oBtomqSGZ0Lbya6j/N9ZEWkg5Hq1VY1mkewm9aPWR8sq1O+HIJysgu+vFngVyXkqKExqwBMC0Ao0rgH8ZijEiVppKL6mXaj2AzjdbiRDuou9ELlaUD9JWOqsGeMyC7d1p8mWYE5jSyJ36Ovse+4ns1W9h2AuaegdVOJSGIGkaYozC2kEQkBDrAwC5hCaL8NMgUUTpX1mClQz0+EOJbS18ng9Z1+p9p8DLXJWJYg1el8CLBywfYEYbo203XfRlemOzeFZzCDPU2KTyudjBJuuhOuh19uZHZkyz6nVOOULw2mNlTSfgjxRFKlZrGL745jE0oc+NfFAztBOU+E7Mx3pl+ZZFvr95X9osU1yU8izBFqxfsboe+NbBTZ9BHvoNym66y6wQT2sNGfTFVdOmy82mb0R+FyQvGXSDrZvibO7x2US+TBjei0vqTwdQ7wFDpE7oaIhRVwhfV7FDufXp/kJmFzHITdQlmTxV4ZObagH6Tt1HKeY1xxsSgOzAWvKfgYz0f2WDw1EmFtbRx96COay2877307Micv/Tx0HbLWtjpJ6S+MSTo7qKqOgf/8y3cc5NpNmUm0DAs+vEvdZ12FPTtqtIZQp1I+jIjED/R73dogY7fRL+p/tNsHzGlb1HwIuyVWe6l1h5aRKz5SJfzyTdP6Sreivpi3FcQHwe79MWRut2DUTAvARKFef4biv4AKxrsqpAF2PQAZIleWBZwZSfAKXB00TuMzBCOwrILsGsQbDwCe+KUri65RJ+6iSrgp0tUQkZfQ3qTRqoBkX7kiu8Oq8/B3FPqg9/rU4tmqUcgPh5mnlZ1zLsNpJhCJyQV/aQY6cBbwHZWuQDcKARrW8YoVO4/z3/xtRv/Pdx9Qkmts2TLos7Ip8TCnK/hWcEjSn2csnNIrkQHBN3K2bjcO+3Kzr/Eu1pHKEN7Am4oFH1zE73XIV7DjsHaGqVueO42NWjIWYq5okfWt+eO+l+loskeBA91gk23qJmFrMeISmF1v/DgsLgfpLmh9wlV3wmiGtD196rW6n98D1j8vVLR7TP59zXHMcIxMXBPldrNIs9EUnyun2mAs8E8Wds5BKkoxhhSXXaFBZ0h5d+qj025Gf78A8w5Arv0NSsjj0i/wlSnnYThUv92MKE35Igfhm6Q7Ye/HlICiagcBYMQM+4Cz8WqbzC9I0z4/+2dMWhTURSGvy61xWI7SLuY0hQaGknRPULFpUOnBCw4KAoROri1uOkiDoqDQwaho4PQzbEdCkKHjsFaxRZSLBWkmyDVkFDleFPfE9Ka0Fu5af+3BB6P806++95/7zk5N+c8jOw2st7g3B5kzsFTK3uuQG8fzMdTMp0uKp/69nfrywaWolPdcKMbCiU3uVmkkR+OpWSAlKXO3kL/UBM5/sgyBz0/HPKMWLHB+LZbPNpku1SCmQ7IpWK/FcTusWWLiLOQ+w8iH8z/yVsVja029w/LI8+cgUV7qeuHrYrpjF6C9S338I+ZoA67l842pqTL7rriRcjb1P4drpdheiRKmdhq7GoZ5kbhdyRXg7sf4eHlei7cNs6UIJuBvPm1B89X4dGfeBUSPfAyDWM1KKxBpQ8eJGBgF55Ylc5X2OmH4gB01dzksnMB7nfAxHvXn3bBmnd/gswQLH2ARBKyFnFU4d4mFC9FwrrPoZ0/f9ik8QVWYt2uXq26RiiPk1EjlBdVOKgRyvIGzP6E16nmU0/tzOw0+L6+CbeAf02MLbGwtOc7uJ2ByZi2tGTjGC427ZnagFwa7pwmkT8GljJ5UglY43Nrm1iDZ8kWN0SdVCbt/L0qcHMNsmmY9ih6ljYsVOGNbVgMhI9Vcc1+hmuDh+zz8OxrMCt5z99L5kRABNqAgEXjVrl2JQFz9eqsI7ttkXXJVd1ZpN3sD7lHvm+gBiTygQ6M3BIBERABHwRiNSo+zMmGCIiACIhASAQk8iGNhnwRAREQAc8EJPKegcqcCIiACIREQCIf0mjIFxEQARHwTEAi7xmozImACIhASAQk8iGNhnwRAREQAc8EJPKegcqcCIiACIREQCIf0mjIFxEQARHwTEAi7xmozImACIhASAQk8iGNhnwRAREQAc8EJPKegcqcCIiACIRE4BeYNhcbvnSkmQAAAABJRU5ErkJggg=="&gt;&lt;/p&gt;</content><category term="Blog"/><category term="css"/><category term="stylish"/><category term="front-end development"/></entry><entry><title>用C++实现一个通用的sort函数</title><link href="https://wizmann.top/a-common-sorting-function-with-cpp.html" rel="alternate"/><published>2015-04-25T11:17:01+08:00</published><updated>2015-04-25T11:17:01+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2015-04-25:/a-common-sorting-function-with-cpp.html</id><summary type="html">&lt;h2 id="_1"&gt;问题&lt;/h2&gt;
&lt;p&gt;用C++实现一个尽可能通用的sort函数&lt;/p&gt;
&lt;h2 id="_2"&gt;分析&lt;/h2&gt;
&lt;p&gt;一个通用的sort函数应该包含以下要点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确实可以排序(LOL)&lt;/li&gt;
&lt;li&gt;可以应对C-style array和C++-style container的排序需求&lt;/li&gt;
&lt;li&gt;可以应用于任意random access container&lt;/li&gt;
&lt;li&gt;可以 …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;h2 id="_1"&gt;问题&lt;/h2&gt;
&lt;p&gt;用C++实现一个尽可能通用的sort函数&lt;/p&gt;
&lt;h2 id="_2"&gt;分析&lt;/h2&gt;
&lt;p&gt;一个通用的sort函数应该包含以下要点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确实可以排序(LOL)&lt;/li&gt;
&lt;li&gt;可以应对C-style array和C++-style container的排序需求&lt;/li&gt;
&lt;li&gt;可以应用于任意random access container&lt;/li&gt;
&lt;li&gt;可以使用用户自定义的排序函数 / 仿函数 / lambda函数&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_3"&gt;实现&lt;/h2&gt;
&lt;p&gt;为了与std中的通用函数做区别，这里的命名规则，包括类型与函数，都在前面加了&amp;rdquo;my&amp;rdquo;以示区别。可能与标准的命名法有出入，所以仅做示例用。&lt;/p&gt;
&lt;h3 id="_4"&gt;思路&lt;/h3&gt;
&lt;p&gt;** 拷贝代码是愚蠢的行为。**&lt;/p&gt;
&lt;p&gt;或者说，&lt;/p&gt;
&lt;p&gt;** 对于同一钟实现，尽量使用同一份代码。 **&lt;/p&gt;
&lt;p&gt;感谢C++ Templates，对于不同类型与需求的函数，我们可以将生成多份代码的劳动放心的交给编译器。并且，Templates的代码生成是在编译期完成的，即不会造成额外的代码膨胀（如果你姿势正确的话），也一般不会造成额外的运行时开销。&lt;/p&gt;
&lt;h3 id="_5"&gt;函数原型&lt;/h3&gt;
&lt;p&gt;我们模仿std::sort来进行开发。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;template&amp;lt; class It, class Compare &amp;gt;
void sort(It first, It last, Compare comp );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_6"&gt;从迭代器/指针获得元素类型&lt;/h3&gt;
&lt;p&gt;我们要处理C风格的数组与C++网络的容器。首先要从迭代器/指针&lt;code&gt;It&lt;/code&gt;中获得元素类型。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;It&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;myiter_traits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;It&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;value_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;myiter_traits&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这个实现非常简单，不做赘述。&lt;/p&gt;
&lt;h3 id="mysort"&gt;实现mysort函数&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;RandomAccessor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;FUNC&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RandomAccessor&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RandomAccessor&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;FUNC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RandomAccessor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mypartition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mysort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mysort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;mysort函数本体并不难理解，这里重点讨论一下模板的思路。&lt;/p&gt;
&lt;p&gt;由于迭代器不需要移动，所以声明为const reference。又由于我们需要兼容各种不同类型的排序方法（函数、仿函数、lambda、std::function等），所以不对&lt;code&gt;FUNC&lt;/code&gt;类型进行限制，即所有可以被call的类型都可以做为模板参数。&lt;/p&gt;
&lt;h3 id="mypartition"&gt;实现mypartition函数&lt;/h3&gt;
&lt;p&gt;快速排序的灵魂就是快速划分。如果处理得当，quick sort可以视作一个稳定的排序函数；否则，一组构造（不必要精心构造）的数据就可以把quick sort变成&amp;rdquo;slow sort&amp;rdquo;。&lt;/p&gt;
&lt;h4 id="quick-sort"&gt;可能会上quick sort退化的数据&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;基本一致的数据   &lt;br&gt;
e.g. &lt;code&gt;1, 1, 1, 1 ... 1, 1&lt;/code&gt; or &lt;code&gt;1, 1, ... 2, 2, ... 3, 3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;有序或基本有序的数据  &lt;br&gt;
e.g. &lt;code&gt;1, 2, ... 5, 6&lt;/code&gt; or &lt;code&gt;6, 5, ... 2, 1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="_7"&gt;解决思路&lt;/h4&gt;
&lt;p&gt;对于有大量重复的数据，我们在处理时要注意平均分配这些重复数据。即，对于与pivot相等的数据，尽量保证一半放在左面，一半放在右面。&lt;/p&gt;
&lt;p&gt;对于有序或基本有序的数据，我们在pivot的选择上可以使用随机、三值法等手段，保证数据的平均分配。&lt;/p&gt;
&lt;p&gt;总的说来，quick sort的高效性，取决于partition函数的平均分配性能上。&lt;/p&gt;
&lt;h4 id="_8"&gt;一个实现&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;RandomAccessor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;FUNC&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;RandomAccessor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mypartition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RandomAccessor&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RandomAccessor&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;FUNC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RandomAccessor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dis&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;iter_swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RandomAccessor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RandomAccessor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;iter_swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_9"&gt;主函数&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;srand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1999&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mysort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;less&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9999&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mysort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="C++"/><category term="sort"/></entry><entry><title>ZeroMQ启示录</title><link href="https://wizmann.top/inspiration-from-zeromq.html" rel="alternate"/><published>2015-04-07T10:01:34+08:00</published><updated>2015-04-07T10:01:34+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2015-04-07:/inspiration-from-zeromq.html</id><summary type="html">&lt;h2 id="mq"&gt;ØMQ是一个消息系统&lt;/h2&gt;
&lt;p&gt;ZeroMQ是一个消息系统，也被称为“消息中间件”。它被广泛的用于经济、游戏、嵌入式等领域。&lt;/p&gt;
&lt;h3 id="_1"&gt;什么是消息系统&lt;/h3&gt;
&lt;p&gt;打个比方，消息系统就像我们使用的 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="mq"&gt;ØMQ是一个消息系统&lt;/h2&gt;
&lt;p&gt;ZeroMQ是一个消息系统，也被称为“消息中间件”。它被广泛的用于经济、游戏、嵌入式等领域。&lt;/p&gt;
&lt;h3 id="_1"&gt;什么是消息系统&lt;/h3&gt;
&lt;p&gt;打个比方，消息系统就像我们使用的IM软件一样。首先，一方决定将消息发往何处（一对一或一对多）。然后将信息打包，点击发送按钮。之后，IM系统会帮你料理剩余的事务。&lt;/p&gt;
&lt;p&gt;但是，它们也有很大的不同点。IM系统对于消息系统似乎太低效了一点。另外，消息系统是没有用户界面（GUI）的。在错误发生时，消息的另一端也不会有人来智能的介入处理。&lt;/p&gt;
&lt;p&gt;所以，我们可以这样下定义。消息系统是具有高效性和容错性的消息传递解决方案。&lt;/p&gt;
&lt;h3 id="zeromq"&gt;ZeroMQ的起源和发展&lt;/h3&gt;
&lt;p&gt;ZeroMQ最先的设想是实现一个炒鸡快的用于证券交易的消息系统，所以在设计初期的关注点就是在极致的优化上。&lt;/p&gt;
&lt;p&gt;第一年的工作重点，在于发明性能测试的方法，和设计高效架构。&lt;/p&gt;
&lt;p&gt;之后，大约在第二年，工作重点转移到实现一个通用的消息系统，以应用于分布式系统，使其可以利用&lt;strong&gt;不同的编程语言&lt;/strong&gt;，使用&lt;strong&gt;不同方式&lt;/strong&gt;，来传递&lt;strong&gt;各种模式&lt;/strong&gt;的信息。&lt;/p&gt;
&lt;h2 id="1-vs"&gt;启示1：独立应用 vs. 程序库&lt;/h2&gt;
&lt;p&gt;ZeroMQ是一个程序库，不是一个消息服务器。这样设计的主要原因是：性能。&lt;/p&gt;
&lt;p&gt;使用一个中间消息服务器（Broker），每一条消息都会被在网络上传递两次（Sender-&amp;gt;Broker-&amp;gt;Receiver)。这样的设计会影响时延和吞吐量。更严重的是，如果所有消息都通过中间服务器，那么这个点就会成为整个系统的瓶颈。&lt;/p&gt;
&lt;p&gt;使用中间消息服务器的另一个弊端，是不利于大规模部署。对于证券交易来说（ZeroMQ最初的应用场景），跨组织的消息传输是不可避免的。这样一来，中央集权式的消息传输就不在有效了。&lt;/p&gt;
&lt;p&gt;所以，我们缩小消息系统的粒度，使之成为一个程序库。使其更轻量，更易于部署。同样，更轻量的消息系统可以实现更复杂的拓扑结构。&lt;/p&gt;
&lt;p&gt;获得的启示：对于一个新项目来说，如果可能，尽量把它实现为一个程序库。将一个新库联编到原有程序中，只需要少量的人力，也提供了足够的灵活性。&lt;/p&gt;
&lt;h2 id="2"&gt;启示2：全局状态&lt;/h2&gt;
&lt;p&gt;对于程序库来说，全局状态往往不能正确的工作。&lt;/p&gt;
&lt;p&gt;由于一个程序库可能被一个应用程序加载多次，这就不能保证只有独一无二的全局状态。&lt;/p&gt;
&lt;p&gt;ZeroMQ的解决方法是由库的调用者显式的维护一个“环境”，如图所示。&lt;code&gt;libA&lt;/code&gt;和&lt;code&gt;libB&lt;/code&gt;都有其独有的“环境”信息。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/71080471bf8bbf4d4e186c353d6b512c"&gt;&lt;/p&gt;
&lt;p&gt;获得的启示：不要在程序库中使用全局状态。如果你这么做了，当库恰好需要在同一个进程中实例化两次时，它很可能会崩溃。&lt;/p&gt;
&lt;h2 id="3"&gt;启示3：性能&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/4ae6721a94012d877709075558562f2b"&gt;&lt;/p&gt;
&lt;p&gt;ZeroMQ在最初设计时，性能调优就是首要的目标。做为一个消息系统，其性能指标主要有两个：吞吐量和延时。&lt;/p&gt;
&lt;p&gt;但是我们怎么度量它们呢？&lt;/p&gt;
&lt;p&gt;如上图所示，A向B发送信息。B在6秒内接收到了5条信息，因此吞吐量为0.83消息/秒，平均时延为1.2秒。&lt;/p&gt;
&lt;p&gt;如果我们换一种计量方式，A向B发送消息，对于单条信息来说，其平均时延为3秒。A花费2秒，发送了所有的消息；B花费了4秒，接收到了所有的消息。所以A的吞吐量为2.5消息/秒，B的吞吐量为1.25消息/秒。这个数据与我们上面得出的数据相差甚远。&lt;/p&gt;
&lt;p&gt;由此，我们可以看出，使用不同的计量标准，对于我们估计系统的性能，会带来很大的不同。&lt;/p&gt;
&lt;p&gt;时延只有在两个节点通信时，才可能发生。所以，并不能有“某节点的时延”这种度量标准的出现。同样，我们可以对多条消息的时延进行平均，但是并不能有“一个消息流的平均时延”。&lt;/p&gt;
&lt;p&gt;吞吐量，与时延不同，只能在单个节点上进行度量。所以，并不能有“节点间的吞吐量”这种度量方法。&lt;/p&gt;
&lt;p&gt;获得的启示：深入了解你所要解决的问题。否则，你会在解决问题时会引入（错误的）假定和玄学，写出有缺陷的复杂代码。&lt;/p&gt;
&lt;h2 id="4"&gt;启示4：关键路径&lt;/h2&gt;
&lt;p&gt;代码中经常被调用的代码，被称为&lt;strong&gt;关键路径&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;对于ZeroMQ来说，建立链接与内存申请都不是影响性能的最主要因素。因为ZeroMQ使用长链接进行通信，所以建立链接的开销均摊到每一条信息微乎其微。同样，ZeroMQ使用高效的内存维护机制，尽可能少的向系统直接申请内存空间。&lt;/p&gt;
&lt;p&gt;获得的启示：只在系统的关键路径上做优化。否则只是浪费时间。&lt;/p&gt;
&lt;h2 id="5"&gt;启示5：内存申请&lt;/h2&gt;
&lt;p&gt;对于一个高效的系统来说，高效的处理内存的方法往往是在内存申请与内存拷贝之间寻求一个平衡。&lt;/p&gt;
&lt;p&gt;对于小型数据来说，直接拷贝数据，即“深拷贝”，的开销更小。而对于大型数据来说，所谓“浅拷贝”的开销更小。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/48deb1742653d61ba04f6e9591f71902"&gt;&lt;/p&gt;
&lt;p&gt;ZeroMQ使用透明的方式来处理两种不同的场景。并且，对于规模较大的数据，使用引用计数的策略，最大限度的复用与节省内存使用。&lt;/p&gt;
&lt;p&gt;获得的启示：当我们优化性能时，不要假定只有一个全局最优解。在不同的场景下，最优解的定义可能大不相同。&lt;/p&gt;
&lt;h2 id="6"&gt;启示6：批处理&lt;/h2&gt;
&lt;p&gt;对于一个高性能消息系统来说，系统调用的绝对数量就是系统的瓶颈。这其实是一个很普遍的问题，消息在调用栈之间传递，会带来不可忽略的性能损失。所以，在构建一个高性能系统时，应该尽量避免消息在栈间的传递。&lt;/p&gt;
&lt;p&gt;如下图所示，对于四条消息，我们需要遍历整个网络栈四次。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/b99f65135b0f0e840131c58d2cc57896"&gt;&lt;/p&gt;
&lt;p&gt;然而，如果我们将这些消息打包成一条消息。我们只需要遍历网络栈一次。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/cd2ea1ae7a71443b3ff85ebbc7cb1c3b"&gt;&lt;/p&gt;
&lt;p&gt;在这里，我们的策略与TCP/IP协议中的Nagle算法类似。Nagle算法是为了充分利用带宽，而ZeroMQ的Batching策略是为了均摊网络栈的时间开销。&lt;/p&gt;
&lt;p&gt;具体的实现如下:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当消息的频率没有超过网络栈的带宽时，ZeroMQ会把所有batching关掉，以CPU利用率来换取低时延。&lt;/li&gt;
&lt;li&gt;当消息的频率超过网线栈的带宽时，ZeroMQ会启用batching，以时延为代价来优化吞吐量。&lt;/li&gt;
&lt;li&gt;当消息队列中的消息过多时，ZeroMQ会采用更激进的batching策略。因为消息的堆积造成的时延增长已经不可避免，索性将更多的信息打包，这样可以更快的清空消息的积压。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外，batching策略只应该被应用于顶层。在顶层采用batching之后，低层的batching就没有意义了。&lt;/p&gt;
&lt;p&gt;获得的启示：&lt;br&gt;
* 在一个异步系统中，想要获得最佳的响应时间，应该把底层的batching策略转移到顶层。&lt;br&gt;
* batching只应该在新数据到来的速度超过系统带宽时才采用。&lt;/p&gt;
&lt;h2 id="7"&gt;启示7：整体架构&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/22f7b30fb17c9a128bbb6dd66ad27a13"&gt;&lt;/p&gt;
&lt;p&gt;用户利用“socket”与ZeroMQ进行交互，一个socket可以同多个peer进行交互。&lt;/p&gt;
&lt;p&gt;socket存在于用户线程中。而一些工作线程会处理异步的交互过程，如：从网络读取消息，将消息放入队列，接受新的连接请求等。&lt;/p&gt;
&lt;p&gt;session负责与ZeroMQ中的socket进行交互，engine负责网络交互。session只有一种，而engine根据使用的协议不同，可以有很多种。&lt;/p&gt;
&lt;p&gt;session与socket之间使用pipe进行通信，pipe被实现为线程安全的双端队列，用来在线程间传递信息。&lt;/p&gt;
&lt;p&gt;获得的启示：学习了整体的设计思路（笑&lt;/p&gt;
&lt;h2 id="8"&gt;启示8：并发模型&lt;/h2&gt;
&lt;p&gt;高效的ZeroMQ必然要利用多核的计算资源，而传统的多线程模型会引入锁、信号量等线程同步机制，会影响系统的整体性能。而使用独立的线程又会引入上下文切换的开销。&lt;/p&gt;
&lt;p&gt;ZeroMQ使用的并发模型是Actor，其目标是完全避免锁的使用，让所有的组件全速运行。&lt;/p&gt;
&lt;p&gt;每一个CPU核心只有一个worker线程，所有内部对象都是线程专有的，这样就完全避免了锁的使用。&lt;/p&gt;
&lt;p&gt;这样一来，许多对象都要分享有限个数的worker。所以，系统应当是全异步的。因为每一个worker的阻塞，都会阻塞其它使用worker的对象。&lt;/p&gt;
&lt;p&gt;获得的启示：Actor模型是极致解决性能与扩展性问题的方法。但是，如果你不是在使用ZeroMQ或Erlang，你需要手写许多相关的Test Case来测试系统的正确性和稳定性。另外，如果你无法应对模型中的复杂模块（如ZeroMQ的shutdown），请不要轻易尝试使用Actor模型。&lt;/p&gt;
&lt;h2 id="9"&gt;启示9：无锁算法&lt;/h2&gt;
&lt;p&gt;无锁算法使用简单的方法进行线程间的通信，而不依赖内核级的同步原语。无锁算法的关键是CPU中的原子操作，例如compare-and-swap（CAS）操作。但是，要记住，无锁操作并不是真正的“无锁”，而是把锁操作放到了较为高效的硬件层。&lt;/p&gt;
&lt;p&gt;ZeroMQ使用一个无锁队列在用户线程与工作线程间进行消息传递。ZeroMQ中的无锁队列有如下特点：&lt;/p&gt;
&lt;p&gt;第一，每一个队列为“一写一读”。当有一对多的读写需求存在时，ZeroMQ会创建多条队列。这样的设计使得我们不用关心多线程读写带来的同步问题，有利于我们对其性能的优化。&lt;/p&gt;
&lt;p&gt;第二，即使无锁算法比传统的锁算法要快很多，但是其代价仍然是过高的（尤其是在CPU核心之间的通信）。所以，我们仍然依赖于“batching”算法，将昂贵的同步操作均摊到多条消息上。在从队列真正的读写操作之前，加入一次预处理（pre-write / pre-read），将消息打个包，发申通。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/9d97e2979db40e413e43cf7d642d1570"&gt;&lt;/p&gt;
&lt;p&gt;获得的启示：无锁算法是非常精巧的，如果可能的话，尽量使用成熟的设计。如果你需要极致的性能，不要仅仅依赖于无锁算法。尽管无锁算法非常快，你仍然可以通过batching策略优化它。（另外，加钱上船也可以。）&lt;/p&gt;
&lt;h2 id="10api"&gt;启示10：API设计&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;设计API，就像设计一款产品。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;用户对于一个程序库的第一感觉来自于用户接口。ZeroMQ简化了自己的用户接口，将其由原来的“炒鸡复杂一不小心坑死你的企业级消息框架”变为了“想发消息调用下就OK”的极易上手的入门级产品。&lt;/p&gt;
&lt;p&gt;另外一个重要的方面，ZeroMQ使用了广为使用的BSD Sockets API。这样做的优点是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这是一个大家都熟知的API，学习曲线相当平缓&lt;/li&gt;
&lt;li&gt;使ZeroMQ与现有的技术连接起来，有利于复用已用的框架与设计&lt;/li&gt;
&lt;li&gt;最重要的是，使用一个成熟与久经考验的框架，可以避免踩前人踩过的坑、&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;获得的启示：除了代码复用之外，我们还可以以一种更一般的方法，复用成熟的技术。当你设计一个新产品时，借鉴一下类似的产品（腾讯！）。不要犯“在这里还没有被发明”（Not Invented Here）综合症。复用一切合适的想法、API、框架抽象。允许用户使用已有的知识，同时也可以让我们规避未知的风险。&lt;/p&gt;
&lt;h2 id="11"&gt;启示11：消息模式&lt;/h2&gt;
&lt;p&gt;ZeroMQ的设计思路是&lt;strong&gt;专注于一个领域，把它做到最好&lt;/strong&gt;。因为，大而全的产品只能给领域专家来使用，而小而精的产品的受众则是任何受过训练的程序员。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REQ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tcp://192.168.0.111:5555&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Hello World!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;当我们要给用户提供更一般性的解决方案时，一个技术栈，栈的每一层可以有不同的实现，从而适应不同人群的需要。&lt;/p&gt;
&lt;p&gt;这和Internet栈的设计思路非常相似：TCP可以解决基于链接的、可靠的数据流传输，UDP可以解决不可靠的数据包传输，SCTP可以解决多用户数据流传输问题等等。&lt;/p&gt;
&lt;p&gt;这样一来，所有的解决方案都是正交的，我们可以利用其中好的设计，也可以没有额外代价的抛弃不好的设计。&lt;/p&gt;
&lt;p&gt;获得的启示：当解决一个复杂且多面化的问题时，单个通用型的解决方案可能并不是最好的方式。相反，我们可以把问题的领域想象成一个抽象层，并基于这个层次提供多个实现，每种实现只致力于解决一种定义良好的情况。&lt;/p&gt;
&lt;p&gt;当我们这么做时，确定问题的粒度非常重要。如果粒度过细，软件的一般性就会受到限制。如果粒度过粗，那么产品就会变得非常复杂，给用户带来模糊和混乱的感觉。&lt;/p&gt;
&lt;h2 id="_2"&gt;后记&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原文链接：http://www.aosabook.org/en/zeromq.html&lt;/li&gt;
&lt;li&gt;中文翻译：http://www.ituring.com.cn/article/4669&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文中借鉴了中文翻译的部分词句，对此表示感谢。&lt;/p&gt;</content><category term="Blog"/><category term="zeromq"/><category term="distributed system"/><category term="system-design"/></entry><entry><title>Codeforces Round #290 (Div. 2) Tutorial</title><link href="https://wizmann.top/cf-290-div-2.html" rel="alternate"/><published>2015-02-18T00:30:24+08:00</published><updated>2015-02-18T00:30:24+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2015-02-18:/cf-290-div-2.html</id><summary type="html">&lt;h2 id="a-fox-and-snake"&gt;A. Fox And Snake&lt;/h2&gt;
&lt;p&gt;Implementation&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="b-fox-and-two-dots"&gt;B. Fox And Two Dots&lt;/h2&gt;
&lt;p&gt;DFS …&lt;/p&gt;</summary><content type="html">&lt;h2 id="a-fox-and-snake"&gt;A. Fox And Snake&lt;/h2&gt;
&lt;p&gt;Implementation&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="b-fox-and-two-dots"&gt;B. Fox And Two Dots&lt;/h2&gt;
&lt;p&gt;DFS&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;AAAA
ABCA
AAAA
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We start at arbitrary point, and traverse the neighbour point with the same color to see if there is a circle.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;do_dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;do_dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;do_dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Yes&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Got it&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;No&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// pass&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="c-fox-and-names"&gt;C. Fox And Names&lt;/h2&gt;
&lt;p&gt;Topsort&lt;/p&gt;
&lt;p&gt;This is a classic interview problem. We can find the relationship between two letters from the given name list.&lt;/p&gt;
&lt;p&gt;But in this instance, there is no possible lexical order because the name list is invalid.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;aaa
aa
a
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So the algorithm can be describe in this way:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If the name list is invalid, there is no solution.&lt;/li&gt;
&lt;li&gt;Try to find the order of the letters.&lt;/li&gt;
&lt;li&gt;Topsort&lt;/li&gt;
&lt;li&gt;If topsort is success, print out the new lexical order of the name list. If failed, there is no solution.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;queue&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;makeG&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;top_sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;print_res&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;makeG&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;top_sort&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;print_res&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Impossible&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="d-fox-and-jumping"&gt;D. Fox And Jumping&lt;/h2&gt;
&lt;p&gt;Extended Euclidean algorithm&lt;/p&gt;
&lt;p&gt;As we might know, for every positive integer &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ax + by = gcd(x, y)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;rsquo;s extend this theorem, for an array of positive integer &lt;code&gt;Xs&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;As * Xs = gcd(Xs)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(&lt;code&gt;As&lt;/code&gt; is an array of constants, both positive and negative)&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;gcd(Xs)&lt;/code&gt; equal to one, that is, every two number of the array is co-prime.&lt;/p&gt;
&lt;p&gt;So, we can find a subarray that every two number is co-prime, and have the minimal cost.&lt;/p&gt;
&lt;p&gt;As there are not too many factors in a single number, even the number here is as large as 10^9. The &lt;code&gt;gcd()&lt;/code&gt; of the subarray won&amp;rsquo;t have too many results, and could be stored in a single &lt;code&gt;unordered_map&lt;/code&gt; here.&lt;/p&gt;
&lt;p&gt;And,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;C++ Iterator Invalidation Rules (C++03)&lt;/p&gt;
&lt;p&gt;Associative containers&lt;/p&gt;
&lt;p&gt;[multi]{set,map}: all iterators and references unaffected&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here is the rule of C++ about the behavoir of the iterators when we try to add something into the map during the iteration. So we can just use one sigle map, and avoid the complexity of moving things between to containers.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;unordered_map&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x3f3f3f3f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;gcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;unordered_map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thres&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thres&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="e-fox-and-dinner"&gt;E. Fox And Dinner&lt;/h2&gt;
&lt;p&gt;Max Flow Algorithm&lt;/p&gt;
&lt;p&gt;As we know, every odd number must be connected to two even numbers. And, of course, one even number should be connected to two odd numbers.&lt;/p&gt;
&lt;p&gt;We use the max flow algortihm. Every odd number have a path with 2 unit of flow to the &lt;strong&gt;source&lt;/strong&gt; node, every even number have a path with 2 unit of flow to the &lt;strong&gt;sink&lt;/strong&gt; node. And if the sum of one odd number and an even number is a prime, we connect them with a path with 1 unit of flow.&lt;/p&gt;
&lt;p&gt;As the result, we have a undirected graph that every node have a degree of 2. It&amp;rsquo;s easy to find out that is an &lt;strong&gt;Euler circuit&lt;/strong&gt;. We find the circuit and print it out.&lt;/p&gt;
&lt;p&gt;The problem is not easy as it seems. Harsh one, indeed. I used &lt;strong&gt;Dinic&lt;/strong&gt; algorithm for the max flow. Actually, I don&amp;rsquo;t like my code here.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;queue&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stack&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout&amp;lt;&amp;lt;x&amp;lt;&amp;lt;endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin&amp;gt;&amp;gt;x&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EDGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x3f3f3f3f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;node&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(){}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iflow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ist&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iend&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iflow&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EDGE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ind&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cnc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;addEdge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ind&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ind&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ind&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ind&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;dinic&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;curhead&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;Que&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;estack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;EDGE&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;estop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;BFS&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Que&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Que&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;Que&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;NODE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;DFS&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;minf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                                                   &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;estop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;memcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;curhead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;estop&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;                                      &lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;minf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;estop&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;estack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="n"&gt;minf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;minf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;indptr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="n"&gt;minf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                                   &lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;estop&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;estack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="n"&gt;minf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="n"&gt;minf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;estop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;indptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                                    &lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;estack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;estop&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;curhead&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;curhead&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;estack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;estop&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;                                           &lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;estop&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;-2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                                    &lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;estack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;estop&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cnc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;show_res&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EDGE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;cnc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;cnc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/*&lt;/span&gt;
&lt;span class="cm"&gt;    for (int i = 1; i &amp;lt;= n; i++) {&lt;/span&gt;
&lt;span class="cm"&gt;        printf(&amp;quot;%d -&amp;gt; &amp;quot;, i);&lt;/span&gt;
&lt;span class="cm"&gt;        for (auto&amp;amp; item: cnc[i]) {&lt;/span&gt;
&lt;span class="cm"&gt;            printf(&amp;quot;%d &amp;quot;, item);&lt;/span&gt;
&lt;span class="cm"&gt;        }&lt;/span&gt;
&lt;span class="cm"&gt;        puts(&amp;quot;&amp;quot;);&lt;/span&gt;
&lt;span class="cm"&gt;    }&lt;/span&gt;
&lt;span class="cm"&gt;    puts(&amp;quot;---&amp;quot;);&lt;/span&gt;
&lt;span class="cm"&gt;    */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; %d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;isPrime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;freopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;E.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isPrime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;addEdge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;addEdge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;addEdge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dinic&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BFS&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="n"&gt;dinic&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;DFS&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Impossible&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;show_res&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="codeforces"/><category term="algorithm"/></entry><entry><title>Codeforces Round #289 (Div. 2) Tutorial</title><link href="https://wizmann.top/cf-289-div-2.html" rel="alternate"/><published>2015-02-16T21:16:31+08:00</published><updated>2015-02-16T21:16:31+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2015-02-16:/cf-289-div-2.html</id><summary type="html">&lt;h2 id="a-maximum-in-table"&gt;A. Maximum in Table&lt;/h2&gt;
&lt;p&gt;Simulation. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="b-painting-pebbles"&gt;B …&lt;/h2&gt;</summary><content type="html">&lt;h2 id="a-maximum-in-table"&gt;A. Maximum in Table&lt;/h2&gt;
&lt;p&gt;Simulation. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="b-painting-pebbles"&gt;B. Painting Pebbles&lt;/h2&gt;
&lt;p&gt;Reading comperhension &amp;amp; Constructive.&lt;/p&gt;
&lt;p&gt;The key point of this problem is &lt;code&gt;abs(b(i, c) - b(j, c)) &amp;lt;= 1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First of all, it&amp;rsquo;s safe to paint k pebbles of every pile with the same color, when &lt;code&gt;k = min(piles)&lt;/code&gt;. At this moment, every &lt;code&gt;b(i, c) - b(j, c) == 0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And then, we paint 1 pebbles of every pile with color &lt;code&gt;C[i]&lt;/code&gt; at a time (if possible). That is, for every pile, the number of pebbles with color &lt;code&gt;C[i]&lt;/code&gt; is zero or one.&lt;/p&gt;
&lt;p&gt;If you can&amp;rsquo;t paint all the pebbles with proper color, just print a &amp;ldquo;NO&amp;rdquo; here.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;ps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mini&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;maxi&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mini&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;NO&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;YES&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mini&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mini&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="c-sums-of-digits"&gt;C. Sums of Digits&lt;/h2&gt;
&lt;p&gt;Brute force &amp;amp; Constructive&lt;/p&gt;
&lt;p&gt;After reading this problem, there is one thing that we could NEVER miss is the scope of number n: &lt;code&gt;1 &amp;lt;= n &amp;lt;= 300&lt;/code&gt;, which means that the max number here is no more than 40 digits and we can solve the problem with brute force.&lt;/p&gt;
&lt;p&gt;As we know, the number in the array must be incremental, and every number should be the minimum.&lt;/p&gt;
&lt;p&gt;Assuming we have got an array which is incremental, the last number is K. Such as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;K = d3 ++ d2 ++ d1 ++ d0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Our mission is to find a way to generate the smallest number which follow the rules:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the number here is greater than the previous one&lt;/li&gt;
&lt;li&gt;the digit sum&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Rule No.1 is not hard as it seems, if we increase any digit of the number K, the new number is of course greater. But how to satisfy the digit sum?&lt;/p&gt;
&lt;p&gt;For example, we got a new number &lt;code&gt;K1&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;K1 = d3 ++ (d2 + 1) ++ d1 ++ d0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, of course, &lt;code&gt;K1 &amp;gt; K&lt;/code&gt;. But the number &lt;code&gt;K2&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;K2= d3 ++ (d2 + 1) ++ 0 ++ 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;is smaller then &lt;code&gt;K1&lt;/code&gt;, and also greater than the number &lt;code&gt;K&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And then, we fill the lower digits with number to make the sum of the digits equal to the given one. If failed, keep on trying, such as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;K3 = d3 ++ (d2 + 2) ++ 0 ++ 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;K4 = (d3 + 1) ++ 0 ++ 0 ++ 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or even&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;K5 = 1 ++ 0 ++ 0 ++ 0 ++ 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sys&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;do_fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pre&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;do_fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
    &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[::&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="d-restoring-numbers"&gt;D. Restoring Numbers&lt;/h2&gt;
&lt;p&gt;Math&lt;/p&gt;
&lt;p&gt;Each number of the input matrix is &lt;code&gt;(A[i] + B[i]) % MOD&lt;/code&gt;. And we can get &lt;code&gt;(A[i] - A[j]) % MOD&lt;/code&gt; by subtract the number on the same line.&lt;/p&gt;
&lt;p&gt;Sometimes, the &lt;code&gt;(A[i] - A[j]) % MOD&lt;/code&gt; can be both positive and negetive. And we can get the value of &lt;code&gt;MOD&lt;/code&gt; here.&lt;/p&gt;
&lt;p&gt;As a result, we can get the value of every &lt;code&gt;A[i] - A[0]&lt;/code&gt;. We set A[0] to the number &amp;lsquo;0&amp;rsquo;, and get the values of array A.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;mat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;diffs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;diffs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;NO&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;NO&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;diffs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;As&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;Bs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;diffs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;

&lt;span class="n"&gt;Bs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bs&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Bs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Bs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Bs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;NO&amp;#39;&lt;/span&gt;
            &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;YES&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Bs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="e-pretty-song"&gt;E. Pretty Song&lt;/h2&gt;
&lt;p&gt;Math &amp;amp; Thinkin&amp;rsquo; in reverse&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s hard to get the answer by brute force because the scope of this problem is too large.&lt;/p&gt;
&lt;p&gt;Try to think in reverse. It&amp;rsquo;s hard to calculate all the value of the substrings, but why don&amp;rsquo;t we find a way to get the value that every vowel contributes to the final result?&lt;/p&gt;
&lt;p&gt;For example, string &amp;ldquo;AAA&amp;rdquo;. The first &amp;ldquo;A&amp;rdquo; will add &lt;code&gt;1 + 1/2 + 1/3&lt;/code&gt; to the final result. And the second &amp;ldquo;A&amp;rdquo;, &lt;code&gt;1 + 1/2 + 1/2 + 1/3&lt;/code&gt;. And the last &amp;ldquo;A&amp;rdquo;, &lt;code&gt;1 + 1/2 + 1/3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can make a table here for a 4-length string.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAf8AAACGCAYAAADTq4MDAAAgAElEQVR4Ae2deVxUVf/H3zPsCAiIKCiKiihuLe7WY9pq5ZbmmllZqS2Wlenza7HNHss208qsR8vKJTO13LfSyu1BixQVM1FkEVE2RWCYmXt/r2Fz2AbUmBlmvvMHnLnn3PP93Pf33Pnee+6552gKCgpUgOjoaLp27WpKysfKBNTsX3nj9RQeensEYa6XjOfGzOTex9bTYvoq5t4ZhPZSlqSsSMDW54bu8Hvc+/APtPlgA+/2qFd65MrZNTwy8D8cafM8qxcOoZGNGoiJT0DbUlnWTRiP8/3qB1ipH8z0oVNo41bevMLFjAPk+F1LI7Nzq3yp2vyeGYdNf1uraj+oOcS8fx+PrdAy4vMlTO7gVZsYqqzb1ueXSZj++HxGjfmShv/ZzLy+vmW0KpkH2H0+khuae5bZbq0vtcXHRj8X1sJWF+wYSFq/nOxbb6FJuR8n76jB3B5s4PcvV3NCXxeORTTWBgHVoMNQvmIlh9gVSzmCF71G3EiQs57JLi25u/eDNM9bzcd7d5CumINSyD23ni0ZAQSUO7fMSzl6uvL2c57YJS/x/IoLXPfE20xob5vAby/sVcWAEVAVhcK74RJh+lS2zF+H3s+9ZIvD/HfiU8IOfKic58i6ebz58T4u3rqFXe0Gc0NzLzQmaWoeCXv3cDIXSFvA/73pzeQJw+gVUuHWxg4ORCTUDoECzsTsYNPSX8lCT/QHU5gSEUKAl4GME0eI1zVh+MtvMKFfMC61I6AO1KrBs+E4Xrjbn692zuS55cvoGn49Tbw0XMzNxrXBAAa2bo7j/XTXxDV60mK2s3FZUfvZP/dFXt4Wgg8XOZuURI7/tTwxfzr9OwXivIHAQHrMT6xbuZVU00/t/Nd4fU+DIh7GXFIP7eJQyEt8X9/xrq410u1fk5NIyjgzgdrqdnMUpjbt9i8D0UhuzklScrLQuzSkSWAYfi6Fl9JlSln7i627/a19vJdrT84vy8Rqi4/zXvBZ5i25QkAI1DkCLnj7tCLCp84JF8FCwOoENDt37izziMPqCsSgEBACQkAICAEhYFUCZbr9PXp5WNW4GBMCdYFAF00XVHV+XZBqE40azQThY4G88LEABxA+NeHzz9+jO94oBsscJVcICAEhIASEgNMTkODv9E1AAAgBISAEhICzEXDi4K9SkJGNrsx7wbZ2v0JBxjnSzxvKvmt6NbIMuWRlV3hL/GpqlH2FgBAQAkKgjhNwwuCvkntkG/MHD6VP81fYn2MfHlTS/2DJsx+x8K33mdj4Zu5/ZhcZplknrvSjT2PPB6/zYOObeWROIjJH0JWClP2EgBAQAo5HwAmDvwbvqL4MvqsexTMb296r6gX2PjWdn669j/GzZjBvaX/8EhI4fzU37G7B9Bg/gJYaA1fUuaFcID46TS4abN86RIEQEAJC4B8n4ITB38RQi3cjb/uZKz/3GJs2ZeId5IkWLUGDpvLJylGEX+3LFy71CPS5MhfrDi5n9hdJFaeV/ceboFQoBISAEBAC1ibgtJP8aDTlg6KKLimW3duOke0VTpe7r6NJPdPsYCq6hD/Zm9CEXj1dOb5hJ8eIpPddkfhdBj1jZjz7Nh3ktKEBbW/tRpvG7oXT+BqzkzkZe4yTmXpcTxzn2EF/giLDCPAoOzOZejGRfT/sJ8UlhNatffBpEQbxpzhv0OIR2pKIMHcu/nWUk5lGtD6hRLQLxF2jQVs0VzCG9L/Ys+Fv1NZd6N4tmJLqK9Qb0ZbgM1t4a9A8Yjq9yokjQQQ3b4pveiz/OxFCt6iz7NySRcTAnjTzKavR2o1X7AkBISAEhMCVESgfAa+sljq/l4HUb9/l9Q9P4B0ZQt53LzAk6jW2p2RzeMFM7m/xCC/NXMuiJ9/hq6Xr+XTwaB6Z8TcFNTpuhaytc3nqvo3ktm5Hc/12Xm47ijdXni1cSMJw5i9ifjtGlmIk80AM+3+NIzW33DudF4/w+cgvOB3Vg67hp1k6cibbzrjg436Sr+4cy1PvxFOABvf6cGjao4wdvpbU0kcGKroj3/Py7S8x94UZPNujPw8+H0226VlAZfUmZ3Ni3xmMRtAlHWbf1j3s+GwWD7YYx4szVvDJo6/x6n1P89qqjCt7nFAjZlJICAgBISAEapOABH9ASd3GOx94MfaNgXTr2ZPhsx+jTeJa3v84jYgHH2Hk9ZCf4Ubf2W/y5tL3mPGQP/HLd5Jag1F0asYe3h+7hVavP0zfzq257qGpvDVZZfWYN9icouAR2ZehE2+iiZs7ze4ZysjHbycqoKxbdHEb2BDnQ4vWjQjtPojn5vShgYs7gVHXcm3TkrIa3Bu14pougeUeZ6jkGa5j6t7lLD+xnk8mN+HYe2/w9cECKq3X1ZeokQPoFaalXsdbGTZpOEOfeoT7ukBuspa7lixlY/JaZo9qUM5ObTZTqVsICAEhIAT+SQIlkeOfrLPO1XVx33r2JZxk07sLWfjmQr784gzdp9xP/7YeoHXF012LV8u2NPYydXO74t/KH21uNnnVjsZXufDrMramBtMhvGRdMXeaDetHWN5uVm3PqtErfW4h7QhLXsLDnafx+aqTuN02jv4RptX9atLtrsW/Y6uiJU1d/Oky9RE6kcLevVm4VFlvORdq3PBw01KvU2fCvLV4hzbC9zIeeZSrTb4KASEgBISAjQnITzgK+WmZ6H3/Rf+p42hZEqNLHKNmlAuxGrSmlcLUcl3zJeXL/Fc4f/wMBao3eoOpfFGwdm0UTgNULqTlFXadV7ccqzb0dmbu0vHhhA+YP+QnFnUdw6w1T9GrQRljNfqi9W1MaH2ILzCgqare4BpVJYWEgBAQAkKgjhKQO3+0eIUEoTm2gU2HdZfcaEgj+seEGj7Xv7Rb2ZQWv4jGuJPMn/FmIwQUI4qLL62vCajROuzG9ATSwwfwwp4NrFw+kmYx3zD9xYPkocHF5MHyFyLlv5uLKjhPZkEAba8JgCrrNd9B0kJACAgBIeBoBJw2+KtGpTBomsa91es2hJv8T7HgtudZsOYoKQl/s2PGXHb7BOKmKhgUFdUsoBYmTQG8sDUUkLhiEV9+l1jJhYIG395juLNRBls+3Etm8Qv3eUeiORs5hFE9vIvak6LHYDCgKyguUK6VGRK2sGBJEgaNF82GTeKliY3R5OpRXbxpEKghOy6JiwoY0w7wy94slIvmjyRUFL1S/HhB4dzmNSRc/wAPdPeiyno1Lri5Qn56DnpdOieTdYXXF0pBtc85yimXr0JACAgBIWCPBJyy278geT9rFx1D0buwZtH/aPlwT6atHMeZwQuZN3AX8/Cg/f/NYe5NbqRs+o51sSq5SWtY/3MIvX0O88P3iShJCj9+14+QYT78/OpcPlKM9Bk0jtJH+8Xe1vh34bl1kzk3+HWenvgAgzvmELPVlUdXjifKC4xnY9k6exmHVAXtnKVs9r6ZHn0j8DN/FqDmceilp5maMpZ+UTnsPd6Np+Z0wlvjSudn+1F/wIsMavEF7e8awZBOAfBnNCsW/M5jj0Zw42N92TZzMs9lDKJL/RRiUzoz44dRNHcHXVX1oiHy3k7w9DTu7z+ccWN92HxQIe/gIr5Z1ZD7BrWkntNeNtrjaSyahIAQEAKXR8A5l/RVFYzGkmf2GrSu2sKn8aouk8TDqRgatSQ81KPGo9kNGSmkEUxooIVrKcNFTsclcsEjmPAI0zv4xY5SFRSjemngn+ndfJciPaWuNBagR0N+UiKpuT40aR2Md6kpFd3pUyTnB9CshS+G06fJCwwpO0+AIZe0+DMYGjYlJMDt0hiGauo1rX1g8PM3s1WqyKkSsqSvZXfLkqzCxzIBy7nSfmrCpyReWS57ObmlIeRydqrzZTVaXCo5co1HAM2uC7jsw3MNDCW0ur1c6xHSoS0h5ctptKYXCix/XNwxje13a94S3wolNXiENKdl8XbXkFA8y5dx9SY4skX5rVBNve6B/pQf/1ixEtkiBISAEBACdY2AdN7WNY+JXiEgBISAEBACV0lAgv9VApTdhYAQEAJCQAjUNQIS/Ouax0SvEBACQkAICIGrJCDB/yoByu5CQAgIASEgBOoaAQn+dcBjasF5MrJLV+qpA4pFohAQAkJACNgzAQn+9uydQm0KGave57/R+XavVATWNgEV3blUfv1+B689+Rk337SYzZn//CtAtX0UtVa/kk/s4hUM7vEKLVrPZOgrB0kym1iz1uzWmYoVUrdsYHSv6bRoNYP+/47hlPCpwnsKyd8t4voeK4nOraJIHd8swd/eHahksG+9N326+di7UtFXywSU7NNs23SIr19cwqsf7+fn/GZE+ZVMGFHLxu2+eiPHP/2MQW/Gk6XP5eTfJ1n5+kfcMTMFs0m77f4oak+gSubOn/n07zCenTuEYb5JrHt7Pvd9k1m4tHjt2a2LNatk/fYD/Ybv4mijCCK86uIxVK9Zgn/1jGxaQjmzn131+9Lez6YyxLgdENDWD+Wu+25kVOeiaaE7Dm9DY/OZIO1Ao80k5J9ll7Yfew9OZfu+Gex6NrBQyuENCaXTattMm10Y1lC/Wx+mP9aBLp07Mn6MacYRhfSzBcXTlNuFSLsQofvrV+4bsJFYXOg5ugX+Dnp9LcHfLppbVSIU0n/ehc/gdtSrqohsdy4CeadZvcPUDxnMPXcEFk7+5FwAqjhaz8bcPzGSINPFkMaDNj2DCgsGtW+Ir/zKFbLQurkUzlqqZB7n089SoGl3XhvTUNqQWZMypsXy8isJ1C+c6605o2+sd2lGVLNyjpCU08Kevaiks2+jL327Sui3ZzdZU5vu7z9Zmww07ciAVtVNDWlNZfZkS0fc1lQTJJ55NlwunE2uUfWcjjnEV28u4oa28/ht4ETijjzEsCYSAkparppzitnPxdL1uZYkngSu6UqfRo7Lx3GPrMSjdfi/cjqa3QF9aVdxTt86fFQi/coJGDm1MYZ4IOj26wsXhrryuhx3z4K/fuP5rwzcOX8Cz7WXC6RCT6sGMlLSOfhLLHvSctk7eyMrT8obRKVngT6DZVO34fr8PfRN+p1oFdrcG0VTB24+EvxLvW9vCYVzP++h/j1RFC/8a28CRY+1CRjP89N3KYAnfUc0kTvaSvgrWcd46d5NeL72LN8+GoxHJWWccpPWi/Z39eadtVOZ20sLxpN8+HEiDjqQ/fJcrOSy443viRl0L092Uon59jg6GjDw7iCHXttEgv/lNRPrlTaeY99mf/oWD+6ynmGxZK8ElHPHWPY74BHBqM4Vlm+yV9nW05V3mo/v/5aESc+wZkoYvg46UOuqgLoFMeyx8MIq8rP1MtgPlbM/fs2oRTkkL1/F+Ie+5LlVeYCe3+dtZ+95x32VVoL/VZ1Jtbezqct/T1Af2kqXf+1BrlM1q2Tt+R97jODSvRs9AySylXGfLo1Fk1ZxasKTfPNoCN66Myx++09SjGVKyRdMi3maRkW60uXuxtKriJ5TBwy0CC3g+OHTHNgZywHTu6ENfdDlehHk5bjnmQR/u/w5UDi3bS/+97SVk9Mu/WMDUWoeu7/6C9NUTx3ujSBIztxLTshPY+HoWTy07BQ/THmfjm1eJKTh23wb0VJehUTP0a9XMumN34m7qIKSwy9Lk/G5aQhzh9YvHP1/CaQzptzpPP0Jdu6exu7dz7FojGmYvxv9/zuFX765kVamtdQd9OPAwxnqsMeMZ9m7NYC+8+Rpfx324j8kXSEj5jDrNu3l9R+KpqtJ3bKXb9t1456bg/B23BuTmvHTn2PBsJk8srbo6fWxo8W7Bd/IlDt8JbgpeRz4bjsfrdHx0Qdh9OsdiG/bMfw+/Xpay5Ojsm3MkMnm79PAtQ2ju3s77Ct+JQetKSgoKHyoER0djUcvGR5TAsam/5Uckv42EhJZH5nDxaaeKDTeRdMFVZ1veyF2qkCjmSB8LPjG5nyMOhLj0kjX1CO8dSD+dnY3a3M+Jb5T8on/M5V01/q07xBgNxfWRXz++bEHcudf4nh7+q/1oWmkPQkSLUJACNRZAi4ehLUPI6zOHoCVhGs9aXldOC2tZM7WZuTJoa09IPaFgBAQAkJACFiZgAR/KwMXc0JACAgBISAEbE1Agr+tPSD2hYAQEAJCQAhYmYAEfysDF3NCQAgIASEgBGxNQIJ/rXtAoSDjHOnnDVQ7XlMt4Hx6QfXlal3zP21ApSAjG53yT9cr9QkBISAEhMCVEJDgfyXUariPkv4HS579iIVvvc/Exjdz/zO7yKhsxjHlAn8t/oinW93EoIkxmCaXdIyPSu6RbcwfPJQ+zV9hf45jHJUchRAQAkKgrhOQ4F9bHlQvsPep6fx07X2MnzWDeUv745eQwHnzhbSUC8RHp6HX+hI5YjDdffQYqu0eqC3BtVGvBu+ovgy+qx7F00nUhhGpUwgIASEgBC6TgAT/ywRW4+K5x9i0KRPvIE+0aAkaNJVPVo4i3GweJd3B5cz+IonC6wEXH4L8HNEdWrwbectMazVuOFJQCAgBIVD7BOr4JD8KuX/HEHMhgm4Rmez7MYbM4GvofUs49cziqDEznn2bDnLa0IC2t3ajTWP30qkb1YuJ7PthPykuIbRu7YNPRBTNahiEq6rXmJ3MydhjnMzU43riOMcO+hMUGUaAR8lcrCr5xzbx1qB5xHR6lRNHgghu5oemOFstyODw+p3Ea9vQ++5I/Eqn+VPRJcWye9sxsr3C6XL3dTSpV1JncWNRC8iITyZLZ+pC0ODesAlNGrqhP5dCcpoOPPxp0jIQdw1Uql/N5+zRJLJMEz9qPQmOCEJ3MpnswokgNXg0akZYMGQeO0V6vgavsOY0DTA1o6q1aTRmzqj9Ni0WhIAQEAJCoBoCdfdX2ZDOvg9e4N7W43lr/mpm9ZvCrGlv8/Lt9zJy4i6yCgeXKWRtnctT920kt3U7muu383LbUby58iyFj94vHuHzkV9wOqoHXcNPs3TkTLadruyhfHmKlus1nPmLmN+OkaUYyTwQw/5f40jNNevPVy5wYt8ZjEbQJR1m37YYThQJRsk8yLJJ7/DNt+v5ZNAYJs46gb7QvIHUb9/l9Q9P4B0ZQt53LzAk6jW2p5YfRaeiT/iZt7oMZ/jQLaQXZ2uUdLY+9Co/HjMNKLSsX3dkJVOvGcWkD09hMF2RnNvNez1H8cBT+yh5bK8/upyXn9hGmt508VFTbeU5ynchIASEgBCwBYG6G/xdG9Dl8XHcFW66C9UyZONyVias5f0HAjn9+dssiS1AzdjD+2O30Or1h+nbuTXXPTSVtyarrB7zBptTFHRxG9gQ50OL1o0I7T6I5+b0oUENiFRXr0dkX4ZOvIkmbu40u2coIx+/nagAs4q1fkSNHECvMC31Ot7KsCcH0jXUdHuvostyo8/s//Cfpe8z85H6HFu6mzQDKKnbeOcDL8a+MZBuPXsyfPZjtElcy/tzj1Ng3nI0HjS6eQzTnm8GGWcwept6OTS4upwns8dEHrqjMe6ZFricdqfp4PE81d+L8ydz0Lh5EnzjMJ58uCGGtFy8A9zRaFzRXDDQa+YYrg92qbk2c52SFgJCQAgIAZsRMItINtNwFYZdcXfV0uCGnrT01YBLIL3+bxThJLPnf5lk/7qMranBdAh3L7bhTrNh/QjL282q7Vm4hrQjLHkJD3eexuerTuJ22zj6R1S36oXKhWrqNbvHv8xj0+DVoi0hhWtIu1I/3A9NTiYXjXBx33r2JZxk07sLWfjmQr784gzdp9xP/7ZmgwhKrbkT/vAYOmVu5ustmSgopK3fju+o6/DT1EC/xp+uk3rj+ctyfk1RQC3gYq47ypHvWXVQB4bT/LYllDu6FK06eHnaSkVKQggIASEgBGxEoI4/869IzTWkDWEekJpbQPbxMxSo3ugLh9AXPRt3bRROA1QupOVB6O3M3KXjwwkfMH/ITyzqOoZZa56iVyNL10QK56up19TTXvqYvqLEGm7RoHXVgtGAqirkp2Wi9/0X/aeOo2XJtYyFmlzCbuGBu2czddY2Uvt15ZefW3DHCC/AWCP9PjcM59aA8Xy3KpV+A/axremTPH7tiyz5KJaHph4l9tpbGVC4JGj12sr0TFjQLFlCQAgIASFgHQKWopx1FPwTVlSze23FgEHjTVjbAAIiGuNOMn/Gm4UfxYji4kvrawIgPYH08AG8sGcDK5ePpFnMN0x/8WA179lr8aum3qsP/OWhaPEKCUJzbAObDhet6V5YwpBG9I8JZbv9S3bV1Kfb83cRsHcxy79dx/GbbqGoA6SG+utFMXRsMH99+iM/LThIhwdvov/ka8n9/kuWf/Y31w4Ko6iP5Aq0lWiU/0JACAgBIWATAg4Q/BVyTucUDeAD8g7v5mSjfozs6YNv7zHc2SiDLR/uJbN44FvekWjORg5hVA9vDAlbWLAkCYPGi2bDJvHSxMZocvWoFJC4YhFffpdYSWDVVFtvoScVPQaDAV1B+QF5xX7WuODmCvnpOeh16ZxM1qGooJr+FH8Kr2lMFytAvW5DuMn/FAtue54Fa46SkvA3O2bMZbdPYHEQLtnr0n+vLiMYHpXIN/9O4Ma7GxW/bldD/bjT8qF7aHb4v3yc2Jc+zd1pePdoeii7WRTbjV7NLl3iVKdNNZoeHZiGGcpHCAgBISAE7IGAQ3T7Z235L/P/O5JeQadY/14K9yx7k2t9TS+6deG5dZM5N/h1np74AIM75hCz1ZVHV44nygt0ah6HXnqaqSlj6ReVw97j3XhqTie89amseHUuHylG+gwaV3zHfMldGn/L9RrPxrJ19jIOqQraOUvZ7H0zPfpGmL2yZ6rLm8h7O8HT07h/wAgeecCb9X8q5Pv+yI9bQujrH8cP3yeiJKms+f5umozsxbSV4zgzeCHzBu5iHh60/785zO3jW/ra4iWFxSn35vSf0o31e0bQNejSK4HV6S+px631HQy7YSvpz3TBz7R7UFdGDW+N+z09ywyM1DSoWps+eT9rFx1D0buwZtH/aPlwV0K9L2kpsSX/hYAQEAJCwHoENAXFU69FR0fj0auywWPWE3PZlnTxfNZhJOtHfsknwwtIya5H884RNCwcMGdWm+Eip+MSueARTHhE0TvuhbnGAvRoyE9KJDXXhyatg/EuvhwyZKSQRjChgRauj6qqV1VQjOqlOfo1GrQu2kqCdNGc9wY//1K7ZqorTaq6TBIPp2Jo1JLwUI9qJ89R8zNI0/nTqH4lnTxV6S+1rJB/JhO1YQO8inc3ZqWR4x1M/UrGHVSqTVUwGkt6M4rGMdS10N9F0wVVnV9KRRJlCWg0E4RPWSRlvgmfMjgqfBE+FZCU2VDEp+Q3tEzWVX2xENmuql7r7qzxIKhjO0Krsupaj5AObQkpn+/iXthl7ta8Jb7l8lwDQ6uur6RsVfVqtGhrRFaDe6A/lcTREgsV/ms8Amh2XUCF7VVt0HgG0qhwYF4lJarSX1pUi2ejBqXfTAkX/2Dql9ly6Uul2jRaXGrE4lI9khICQkAICIHaJaDZuXNn6SXFDTfcULvWpHYhIASEgBAQAkLgsggcOXLkssrXpHCZbv9esXWo21+fyk/7f2L3uRyMLr60anULwyKDL+suuiaApIwQ0EwwdfuXXiMLkHIENBqN8CnHxPyr8DGnUTEtfCoyMd9SW3zqboesW2Nu7jGam80pSVoICAEhIASEgBColkAlo8Cq3UcKCAEhIASEgBAQAnWYgAT/Ouw8kS4EhIAQEAJC4EoISPC/Emq1to+KLuckv/6+gteW/pub3/0Pm81XA6w1u1JxXSGg6pLZ8cnjDBy3mjSZNamC24RPBSRlNgifMjgqfHEmPhL8K7jfdhuUvBNsO7Sbr1e/xavbt/Kzvi1RnnXtrXjb8XN4y/kJbFv8Ge+9Mo81hzJLZ7V0+OOu6QEKH8ukhI/wMSMgwd8Mhq2TWq+W3NV9EKOaF8060LFLVxqLh2ztFvux79mcW8dN4em+PpVMGGU/Mm2mRPhYRi98hI8ZAQktZjDsIqk/yeq/LgBh3NO+UZXz9tuFVhFhAwJaXD3dJPhXSV74VImmMEP4CJ8iAhL8LbcEq+fq0nawNgsI+BcDGl7O3H9WlyoGbURAI0+CLJIXPhbxIHyEj4mABH/L7cDKuQZOHfqZeNMaOu1uJqpozVwraxBzQkAICAEh4OgEJPjbk4eVdH7abwr93vTtEkE9e9ImWoSAEBACQsBhCEjwtyNXKjl/sOwU4Hoto5pL6Lcj14gUISAEhIBDEZDgbzfuVMk6sZE9Cri06EdPWfPebjwjQoSAEBACjkZAgr+9eFS9wO7dv5MPdOh8LUEyqMtePGNnOlSMBgVVMSJz/FTmGuFTGZVL24TPJRaVpZyHjwT/yvxv1W0KGYk7+XrzLCb/mVtoOfXwBr6NS0Ym97OqI+zfmPEc+1cvYMGObNS4Jcxf+gtJOvuXbTWFwscyauEjfMwI1N0lfc0OQpJCoDYJyJK+lunW1pKjlq3WnVzhY9lXwsc2fOTO3zJ3yRUCQkAICAEh4HAEXKOjo0sPynSHIx8hIAQqEjDdncinagLCp2o2phzhI3wsE7CcGxcXZ7nAFeRKt/8VQJNdnIuAdPtb9rd02wofywQs50r7sQ0f6fa3zF1yhYAQEAJCQAg4HAEJ/g7nUjkgISAEhIAQEAKWCUjwt8xHcoWAEBACQkAIOBwBCf725FI1l9i9sxn81r20eHksQ9f8RpLBngSKFlsTUHXJ7PjkcQaOW02azPJTxh3Gszt4d2xv2oU3p22vEby29hQyDcIlRMLnEouqUs50fknwr6oVWH27geM7pjFowwGyjBc4mXaYlWsnc8fG4/IDZnVf2KnB/AS2Lf6M916Zx5pDmRjtVKZNZOkO896IZ9kVMoTJUx7k+uyVvDqgF5O2ZaHaRJCdGRU+1TvEyc4v1+qJSAmrENAnsUv7EHunX0+QJpfdK4bTa2sqh2OPkHl3KxrLm2ZWcYNdG/FsziQQ7CwAAAoASURBVK3jpqDZ+D5rE+xaqdXF5R3eRMG0jay4o2HhOuWPju6Ja+SdfP3hHt69pR9+VldkXwaFTw384WTnl9z516BNWKWIWzj3976eIJNHNN60aRVaaDYotCm+Evit4oK6YUSLq6cb0iTKessj6mGm3FYU+E05msAeDOnkikYrpEw8hE/Z9lL1N+c5vyT4V90KbJiTR9yRk0Akz9zaDlnc14ausEPTMt9QRadoPf3wNP81M6QTnxHALfdfh0/F4k63RfjU3OXOcn5Jt3/N24TVShacWc3zu/XcOeZtngt1t5pdMSQEHIWA7ugyvvN9lgX9gwsfAzjKcf1TxyF8/imSdbceCf525jsl9w9emr8Iz4Gf8u2NYXjYmT6RIwTsnoA+nq9nxDJ2wZe0kxOooruET0UmTrjFvKPMCQ/fzg5ZH8/HX7xLQt95rLmtjTzrtzP3iJw6QEA9T/SHb5My4WMmRErkr+Ax4VMBibNukOBvL543JLJo6cec+tdsvvlXC7wNCSze9Asp8i63vXhIdNg9gTyOfPEKq1pP54U+gcXd/QoGOYeKPSd87L4JW1GgdPtbEXaVpvSnWLjgER457ErE3xNZs8JAdlYOXR9cwSi5PKsSm3NmqBgNCqpiRGKaWQtQczk0fzzTjg/khZGp/Lk/FbUgnQM/rCTvwTk80dbJx84IH7PGYinpPOeXBH9L7cAaecYUFnz2II8cOF9o7diZYqO+g5nSPkAGK1nDB3XFhvEc+9csZsGObNTsJcxfGsn4e3vT1Ol7tws4Oqc/3Sf/zEUWs+5dM4d2mMXRN5w88CN8zFpE1UknO79kSd+qm4LkCIFCArKkr+WGIEuyCh/LBCznSvuxDR/pVLbMXXKFgBAQAkJACDgcAdfo6OjSgzLd4chHCAiBigRMdyfyqZqA8KmajSlH+AgfywQs58bFxVkucAW50u1/BdBkF+ciIN3+lv0t3bbCxzIBy7nSfmzDR7r9LXOXXCEgBISAEBACDkdAgr/DuVQOSAgIASEgBISAZQIS/C3zkVwhIASEgBAQAg5HQIK/XbnUSOqRhYx+eygtXhxN/5XbOWWwK4EixsYEVF0yOz55nIHjVpMms/yU8Ybx7A7eHdubduHNadtrBK+tPYWuTAnn/iJ8qve/M51fEvyrbw9WKqGQeXw5n6a15dmRkxjm+TfrNk3lvr1pGK2kQMzYOYH8BLYt/oz3XpnHmkOZ0i7M3aU7zHsjnmVXyBAmT3mQ67NX8uqAXkzaloVqXs5Z08Knes872fklM/xV3ySsVEJL/fBhTG/lihYD/t3DeScpnvSc/MJpXF2spELM2DEBz+bcOm4Kmo3vszbBjnXaQFre4U0UTNvIijsaFs6K+ejonrhG3snXH+7h3Vv64WcDTfZkUvjUwBtOdn7JnX8N2oS1imhdTIEflNwDfPprPATcxWvdm+BmLQFipw4Q0OLq6YbMOlDWVR5RDzPltqLAb8rRBPZgSCdXNFohZeIhfMq2l6q/Oc/5JXf+VbcC6+aoBZxO2s+Wg1uY99N21B6ziBvQlzYe8uNlXUfYvzWZb6iij7SefniabzakE58RwC1PXIeP+XYnTQufmjveWc4vufOveZuo5ZIFZGSncPDYb+y5cJ69275kZbq+lm1K9ULAMQnoji7jO99nebt/sCyOVYmLhU8lUJxskwR/e3G4xof2HYbyzpMLmdvKBZTDfPjzUXLtRZ/oEAJ1hYA+nq9nxDJ2wTO0c/oVDytxmvCpBIrzbZLgb28+d2nCsJvaF6rKz9PJmu325h/RY98E1PNEf/g2KRM+ZkKkRP4KzhI+FZA46wYJ/nboeRcX09h+N7p0DMfbDvWJJCFgnwTyOPLFK6xqPZ0X+gQWd/crGGQ+hGJ3CR/7bLe2USXB3zbczawWcHTPHCat20acTgU1k1+ij+MTOYm51wfJ80ozUpI0EVAxGhRUxSi9QuYNQs3l0KeP8vyRnvRvmsqf+/ezb/dmFv77ceb/VWBe0jnTwqeGfnee80tG+9ewSdRaMTWHA/tX8NGBr/hoaxv6tW6Eb+MX+L3/LbSWd/xqDXudrNh4jv1rFrNgRzZq9hLmL41k/L29aer0vdsFHJ3Tn+6Tf+Yii1n3rpl3O8zi6BvuZhucMSl8auR1Jzu/ZEnfGrWKWi6k5JKYmki6pj7hwY3xlxl9ahn45VUvS/pa5iVLsgofywQs50r7sQ0fufO3zN06uVpvwkLbEGYda2JFCAgBISAEnJyAa3R0dCkC0x2OfISAEKhIwHR3Ip+qCQifqtmYcoSP8LFMwHJuXFyc5QJXkCvd/lcATXZxLgLS7W/Z39JtK3wsE7CcK+3HNnxktL9l7pIrBISAEBACQsDhCEjwdziXygEJASEgBISAELBMQIK/ZT6SKwSEgBAQAkLA4QhI8LdblxpJ3v861781h2iZo8RuvWRtYaoumR2fPM7AcatJk5nrKuAXPhWQlNkgfMrgqPDFmfhI8K/gfnvYoJD19zz6ffYjR/2uI0Im+7EHp9heQ34C2xZ/xnuvzGPNoUyMtldkXwqEj2V/CB/hY0ZAgr8ZDHtJ6s6s5r6PvyQWV3p2a4+/vGVmL66xrQ7P5tw6bgpP9/VBmkQlrhA+lUAx2yR8zGBUknQyPhL8K2kDttxkvLCLl9ccpn7hij7tGB3hLz/0tnSI3dnW4urpJm2iSr8InyrRFGYIH+FTRECCv+WWYNVcVRfH7O920vW2TiSmA01vp4+fuMiqTqgDxmS+IctOEj7CxzIBy7nO0n4kslhuB9bLNaay7PsluN7+BH0ztxKtQpvO3WkqHrKeD8SSEBACQsBJCEhosQdHq+fZsW4OMdc8w5NNVWL2HUBHCAM7NsHZ1yOzB/eIBiEgBISAoxGQ4G9zjyqc/XMGo3Znkbx/LuMXvcpzf+QAOn7fsZy9+arNFYoAISAEhIAQcCwCsqqfzf1ZwKkkPS388zh++gSGnL84YAB8A9AV+BDkJuO6be4iESAEhIAQcDACEvxt7lBPOvf/gJ39TUL0HF47gvZrztD//s/58Ro/GdVtc//YmwAVo0FBVYzIHD+V+Ub4VEbl0jbhc4lFZSnn4SPd/pX531bblDNs/uMUaDsyuoW8y20rN9itXeM59q9ewIId2ahxS5i/9BeSdHar1vrChI9l5sJH+JgRkCV9zWDYPKnmEp90gnRtQ9qHBuMtPf42d4lJgCzpa9kNsiSr8LFMwHKutB/b8JFuf8vcrZur8aZlWHtaWteqWBMCQkAICAEnI+AaHR1desimOxz5CAEhUJGA6e5EPlUTED5VszHlCB/hY5mA5dy4uDjLBa4g17Vr166Fu5kuAlRVXiu7Aoayi4MTMJ14bdu2dfCjvPLDEz6W2Qkf4WOZgOXc2mo/MuDPMnfJFQJCQAgIASHgcAT+H8to9QEfaHEEAAAAAElFTkSuQmCC"&gt;&lt;/p&gt;
&lt;p&gt;We can easily find the pattern here. (Of course we can prove it.) And the code is right here.&lt;/p&gt;
&lt;p&gt;(But you can always find a &lt;a href="http://codeforces.com/contest/509/submission/9862199"&gt;harder way&lt;/a&gt; to sovle it. LOL. But I have to say that &lt;strong&gt;pypy&lt;/strong&gt; is awesome!)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# pypy: 171ms&lt;/span&gt;
&lt;span class="c1"&gt;# python2: 467ms&lt;/span&gt;
&lt;span class="n"&gt;VOWELS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AEIOUY&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500010&lt;/span&gt;

&lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;

&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;VOWELS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;pypy is about 3~5 times faster than the original python interpreter, and this is the very useful tool to help us with the algorithm problems.&lt;/p&gt;
&lt;h2 id="f-progress-monitoring"&gt;F. Progress Monitoring&lt;/h2&gt;
&lt;p&gt;DP&lt;/p&gt;
&lt;p&gt;This problem is about the pre-order traversal with a tree. There are multiple situations of the output string given in the problem.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;  a    | b c d |         | e f g h i j |
  ^        ^                    ^
father  children   siblings &amp;amp; siblings children
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;  a    | b c d e f |         | g h i j |
  ^          ^                    ^
father   children    siblings &amp;amp; siblings children
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But be aware, if &lt;code&gt;x &amp;lt; a&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; can&amp;rsquo;t be siblings. &lt;/p&gt;
&lt;p&gt;&lt;code&gt;dp[i][j]&lt;/code&gt; stands for the number of permutations of the subtree. whose pre-order traversal is right match the &lt;code&gt;s[i...j]&lt;/code&gt;, the substring of the given traversal path.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;#include &amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#include &amp;lt;vector&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;using&lt;/span&gt; &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="c1"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="n"&gt;typedef&lt;/span&gt; &lt;span class="n"&gt;long&lt;/span&gt; &lt;span class="n"&gt;long&lt;/span&gt; &lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;llint&lt;/span&gt; &lt;span class="n"&gt;MOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000000000&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;555&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;llint&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;outvec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outvec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;outvec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;siblings&lt;/span&gt;
                &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;%=&lt;/span&gt; &lt;span class="n"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;
            &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;%=&lt;/span&gt; &lt;span class="n"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outvec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;outvec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;llint&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                    &lt;span class="n"&gt;llint&lt;/span&gt; &lt;span class="n"&gt;sibling&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                    &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sibling&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;outvec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="codeforces"/><category term="algorithm"/><category term="算法"/><category term="题解"/></entry><entry><title>Codeforces Round #288 (Div. 2)</title><link href="https://wizmann.top/cf-288-div-2.html" rel="alternate"/><published>2015-02-16T21:16:30+08:00</published><updated>2015-02-16T21:16:30+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2015-02-16:/cf-288-div-2.html</id><summary type="html">&lt;h2 id="a-pasha-and-pixels"&gt;A. Pasha and Pixels&lt;/h2&gt;
&lt;p&gt;Brute force.&lt;/p&gt;
&lt;p&gt;There are multiple ways to form a 2*2 square at one single step.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/6fb53c51539b47559cf0d122a832cf63"&gt;&lt;/p&gt;
&lt;p&gt;So at every step, we have to check the neighbours of pixel that is colored black.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;h2 id="a-pasha-and-pixels"&gt;A. Pasha and Pixels&lt;/h2&gt;
&lt;p&gt;Brute force.&lt;/p&gt;
&lt;p&gt;There are multiple ways to form a 2*2 square at one single step.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/6fb53c51539b47559cf0d122a832cf63"&gt;&lt;/p&gt;
&lt;p&gt;So at every step, we have to check the neighbours of pixel that is colored black.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;isBlackBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOVE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOVE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOVE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;isBlackBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="b-anton-and-currency-you-all-know"&gt;B. Anton and currency you all know&lt;/h2&gt;
&lt;p&gt;At first, you have to understand the questions accurately.&lt;/p&gt;
&lt;p&gt;The exchange rate is &lt;strong&gt;an odd number&lt;/strong&gt;. And your mission is swap one digit with another, to make it the maximum even number.&lt;/p&gt;
&lt;p&gt;Because if the exchange rate is an even number, it will lead to a more sophisticated problem.&lt;/p&gt;
&lt;p&gt;The intuitive thought is that we can swap the hightest even digit with the last digit. However, for this case &amp;ldquo;92291&amp;rdquo;, you may swap the second digit &amp;ldquo;2&amp;rdquo; and the last digit &amp;ldquo;1&amp;rdquo;. But &amp;ldquo;91292&amp;rdquo; is not the largest number, &amp;ldquo;92192&amp;rdquo; is.&lt;/p&gt;
&lt;p&gt;So, ther are two scenario. First is the final answer is greater than the ordinary one. Just find out the &lt;strong&gt;first even digit that is less than the last digit&lt;/strong&gt;. Second is the final answer is less than the given one. If we want to make it the largest one, we have to find the &lt;strong&gt;lowest even digit and then swap&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We can make it by loop twice. But there is a way to find the final answer in one single iteration.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123456&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="c-anya-and-ghosts"&gt;C. Anya and Ghosts&lt;/h2&gt;
&lt;p&gt;The background of this problem is quite twisted.&lt;/p&gt;
&lt;p&gt;First of all, we have to find out in which scenario there is no way to defence against the ghost.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/833368d068c6dc956b62d9babf01c3b6"&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s easy to find out in that diagram above that if the duration of the candle is less than the number of candles which is needed.&lt;/p&gt;
&lt;p&gt;So, before the ghost comes, we have to light up the candles. If we want to have K candles in one second, we have to light it up at second (T - 1) (T - 2) &amp;hellip; (T - K).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sys&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;ghosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;# impossible&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;candles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ghost&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ghosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;candles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ghost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;candles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ghost&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt;
            &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="d-tanya-and-password"&gt;D. Tanya and Password&lt;/h2&gt;
&lt;p&gt;Tanya cut the password into three-letter continuous substrings. Our mission is to re-assemble these substrings.&lt;/p&gt;
&lt;p&gt;For example,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fuckme&lt;/span&gt;
&lt;span class="n"&gt;Substrings&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fuc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uck&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ckm&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kme&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It&amp;rsquo;s not hard to find out that the problem is not about the &amp;ldquo;string&amp;rdquo; but the &amp;ldquo;graph&amp;rdquo;. But how to convert the string and substrings into a graph.&lt;/p&gt;
&lt;p&gt;At the every beginning, we regard the substrings as vertexes, every two substrings which could be connected has an edge between them.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/bbc690924ece17dde46fd5d23188bf5d"&gt;&lt;/p&gt;
&lt;p&gt;In this scenario, all we have to do is find a path that visit all the vertexes. This path is called &lt;strong&gt;Hamilton path&lt;/strong&gt;. The algorithm to find a hamilton path in a graph is quite slow with O(2 ** N) time complexity. We have to find another way.&lt;/p&gt;
&lt;p&gt;Similar to hamilton path, the eular path is a path that visit all the edges of the graph. And this inspires us to make the strings to another graph, and the eular path will be the final answer with the complete password.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/bd69ddd562d6b4b4cde4e3a461a8706e"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;set&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;
&lt;span class="cp"&gt;#define err(x)   cerr &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;outdeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;Z&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;9&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;get_value_err:&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;get_char_err&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ia&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ia&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ib&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node_str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node_str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node_str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node_str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;outdeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;indeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_father&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_father&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;is_connected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get_father&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_father&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;indeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;outdeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_father&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1U&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_start_point&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;is_connected&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;indeg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;show_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node_str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node_str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node_str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_start_point&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NO&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;YES&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node_str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node_str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;show_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="e-arthur-and-brackets"&gt;E. Arthur and Brackets&lt;/h2&gt;
&lt;p&gt;DP + Greedy&lt;/p&gt;
&lt;p&gt;For this problem, be ware that the position of the right bracket is not the absolute position but the relative position. And according to the common sense, there will only be complete brackets between one left bracket and one right bracket.&lt;/p&gt;
&lt;p&gt;For example,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;RIGHT: &lt;span class="gs"&gt;*(*&lt;/span&gt; ()(()) &lt;span class="gs"&gt;*)*&lt;/span&gt;
WRONG: &lt;span class="gs"&gt;*(*&lt;/span&gt; ((((() &lt;span class="gs"&gt;*)*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So, it&amp;rsquo;s OK to close the bracket if possible. And this is the key to solve to problem.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;brackets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="n"&gt;INF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xcafebabe&lt;/span&gt;
&lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;brackets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;(&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre_l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pre_r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pre_l&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;pre_r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;
            &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;IMPOSSIBLE&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="codeforces"/><category term="algorithm"/><category term="算法"/><category term="题解"/></entry><entry><title>Sequence Median</title><link href="https://wizmann.top/sequence-median.html" rel="alternate"/><published>2014-12-14T16:51:50+08:00</published><updated>2014-12-14T16:51:50+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-12-14:/sequence-median.html</id><summary type="html">&lt;h2 id="description"&gt;Description&lt;/h2&gt;
&lt;p&gt;Given a sequence of integer numbers, try to find the median of the sequence.&lt;/p&gt;
&lt;h3 id="extending"&gt;Extending&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Make sure your code can get the right answer in any conditions&lt;/li&gt;
&lt;li&gt;Make sure your code work effectively on some special kinds of sequence. For example, ordered sequence or a nearly ordered one, a …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;h2 id="description"&gt;Description&lt;/h2&gt;
&lt;p&gt;Given a sequence of integer numbers, try to find the median of the sequence.&lt;/p&gt;
&lt;h3 id="extending"&gt;Extending&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Make sure your code can get the right answer in any conditions&lt;/li&gt;
&lt;li&gt;Make sure your code work effectively on some special kinds of sequence. For example, ordered sequence or a nearly ordered one, a sequence with few unique items.&lt;/li&gt;
&lt;li&gt;If the memory is not large enough for all the elements in the sequence, how can we implement this algorithm?&lt;/li&gt;
&lt;li&gt;If it&amp;rsquo;s not a sequence, but a data stream. How can we find the median?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="solution"&gt;Solution&lt;/h2&gt;
&lt;p&gt;Finding the median is quite similar to finding the kth element.&lt;/p&gt;
&lt;p&gt;The basic solution to find the kth element is to sort the sequence first, and then find the kth. It&amp;rsquo;ll get the right answer, of course, but the time complexity is O(n * logn), which is not the optimized one.&lt;/p&gt;
&lt;p&gt;There is a vintage algorithm to get the kth_element.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;partition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;kth_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kth_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;kth_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;partition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kth_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kth_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find_median&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kth_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kth_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kth_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The time complexity of the algorithm is O(N). It works well in most conditions. But there is a potential error in the code, can you find it?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If &lt;code&gt;a + b&lt;/code&gt; is greater than INT_MAX, it will overflow, and make a mess to your code. The right way is：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There is another problem in the code. If the sequence is already ordered, the algorithm will take O(N^2) time, and can&amp;rsquo;t work effectively as what we design. It is because the pivot is the very first element of the sequence (or the sub-sequence), if the sequence is ordered, we will partition the sequence into this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pivot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The solution is to use the random pivot. And we will modify the code here.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;partition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code will perform well for the ordered / nearly ordered data. But there is another &amp;ldquo;however&amp;rdquo;, what if there are few unique elements in the sequence?&lt;/p&gt;
&lt;p&gt;For example, the sequence &lt;code&gt;[1, 1, 1, 1, 1, 1, 1]&lt;/code&gt;. If we deal this sequence by the previous algorithms, it also takes O(N) time, because we can just separate the sequence into this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pivot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This scenario is similar as the previous one. So we have to come up a new way to cope with it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;partition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pivot_idx&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// &amp;lt;- rewrite zone&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// &amp;lt;- end of rewrite zone&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code could put the same number into left part and right part by half.&lt;/p&gt;
&lt;p&gt;With all these optimization, you can get an &lt;strong&gt;Accepted&lt;/strong&gt; in the problem &lt;a href="http://poj.org/problem?id=2623"&gt;POJ-2623&lt;/a&gt;. But be ware, the function to initizalize of random number, &lt;code&gt;srand(time(NULL))&lt;/code&gt;, is disallowed when using the G++ compiler, please choose C++ instead.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s always something next, if we don&amp;rsquo;t have enough memory to storage all the data in the sequence. We will use a heap to find the kth_element, and that will save half of the memory space. But the time complexity is O(n * logn) here.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// This is a bad code :)&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;priority_queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%lld&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%.1f&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%.1f&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Okay, there is the last problem: what if the sequence is a stream that you have to find the median whenver a new number comes in? The solution is using two heaps. The max heap storages the numbers which less than the median, and the min heap storages the numbers which greater than the median.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MaxHeap&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;priority_queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MinHeap&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;priority_queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;greater&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MedianStream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_max_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_max_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_max_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_min_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;do_adjust&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_median&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_max_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_max_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_min_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;do_adjust&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_max_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_min_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_min_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_max_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_max_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_min_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_max_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_max_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_min_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_min_heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MaxHeap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_max_heap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MinHeap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_min_heap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="quick sort"/><category term="median"/><category term="partition"/><category term="priority queue"/></entry><entry><title>类型-长度-值（TLV）协议</title><link href="https://wizmann.top/tlv-protocol.html" rel="alternate"/><published>2014-11-17T00:25:42+08:00</published><updated>2014-11-17T00:25:42+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-11-17:/tlv-protocol.html</id><summary type="html">&lt;p&gt;在数据通信协议中，可选的信息或字段通常使用type-length-value（a.k.a TLV）元素来进行编码。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Type - 类型&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用来标示字段类型的值，通常是一个 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;在数据通信协议中，可选的信息或字段通常使用type-length-value（a.k.a TLV）元素来进行编码。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Type - 类型&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用来标示字段类型的值，通常是一个二进制值或简单的字母&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Length - 长度&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;字段长度，单位通常为Byte&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Value - 值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个变长的比特数组用来存储这个字段的值&lt;/p&gt;
&lt;h2 id="_1"&gt;优势&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;TLV序列方便遍历查找&lt;/li&gt;
&lt;li&gt;新的字段可以无痛的加入现有的协议中。解析的时候，对于未知的字段，可以轻松的跳过。这点与XML类似&lt;/li&gt;
&lt;li&gt;TLV元素的顺序可以是随意的&lt;/li&gt;
&lt;li&gt;TLV元素通常使用二进制存储，可以使解析速度加快并且使数据更小&lt;/li&gt;
&lt;li&gt;TLV可以与XML数据相互转换，易于人类阅读&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_2"&gt;例子&lt;/h2&gt;
&lt;p&gt;在这里，我们以protobuf的可选和变长字段为例。&lt;/p&gt;
&lt;h3 id="field_number-wire_type"&gt;field_number ++ wire_type&lt;/h3&gt;
&lt;p&gt;每一个protobuf的字段在传输时，都会加上&lt;code&gt;field_number&lt;/code&gt;和&lt;code&gt;wire_type&lt;/code&gt;这两个值，这两个值组成这个字段的key。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;field_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wire_type&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;field_number&lt;/code&gt;标明了字段的编号，方便协议向前向后的兼容。而&lt;code&gt;wire_type&lt;/code&gt;标明字段的类型，方便解析程序使用相应的方法来进行反序列化。&lt;/p&gt;
&lt;h3 id="varint"&gt;Varint 变长整型&lt;/h3&gt;
&lt;p&gt;对于一个变长整型字段，protobuf中使用Type(0)来标示，而长度并没有显式的标出。&lt;/p&gt;
&lt;p&gt;Varint的值使用如下编码方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Varint使用分段存储方法，每个Byte为一段&lt;/li&gt;
&lt;li&gt;Varint每段的第一个字节是标示位，如果这一位是1，则下一个Byte也是这个数的一部分，如果这一位是0，则在这个Byte是这个Varint的最后一个Byte&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="string"&gt;String 变长字符串&lt;/h3&gt;
&lt;p&gt;字符串被标示为Type(2)，长度使用Varint类型显式标出。&lt;/p&gt;
&lt;p&gt;一个string在protobuf中被编码为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;encoded_string = key ++ length ++ string
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_3"&gt;其它方法&lt;/h2&gt;
&lt;p&gt;TLV同样也可以表示tag-length value，例如HTTP、FTP、POP3等协议都是使用这种基于可读文本的&amp;rdquo;Field: Value&amp;rdquo;协议。这样设计的原因大概是由于在“上古时代”，互联网速度远小于CPU处理的速率（现在更应该是&lt;strong&gt;远远小于&lt;/strong&gt;，CPU已经爆了IO一条街了），设计一些更可读的协议对人类来说确实比较方便。&lt;/p&gt;
&lt;p&gt;而TCP/IP核心协议都使用的定长不可变的协议，这样可以使编码、解析速率达到最快。&lt;/p&gt;
&lt;p&gt;对于XML和json这种奇行种，我们就不说了吧 :)&lt;/p&gt;
&lt;h2 id="_4"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Type-length-value"&gt;Type-length-value&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.cnblogs.com/shitouer/archive/2013/04/12/google-protocol-buffers-encoding.html"&gt;Google Protocol Buffers 编码(Encoding)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="TLV"/><category term="protocol"/><category term="network"/><category term="protobuf"/><category term="flatbuffer"/></entry><entry><title>Reasons They Recruit</title><link href="https://wizmann.top/reasons-they-recruit.html" rel="alternate"/><published>2014-11-16T01:03:14+08:00</published><updated>2014-11-16T01:03:14+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-11-16:/reasons-they-recruit.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;From &lt;em&gt;Ace of Programming Interview&lt;/em&gt;, Cpt1 - Hiring Programmers: The Inside Story&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="establish-a-rapport"&gt;Establish a Rapport&lt;/h2&gt;
&lt;p&gt;For an interviewee, one the the most efficient way to build a rapport is to &lt;strong&gt;try to see things in from the interviewer&amp;rsquo;s perspective&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;understand the motivation of the interviewer&lt;/li&gt;
&lt;li&gt;establishing a common ground&lt;/li&gt;
&lt;li&gt;adapting …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;From &lt;em&gt;Ace of Programming Interview&lt;/em&gt;, Cpt1 - Hiring Programmers: The Inside Story&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="establish-a-rapport"&gt;Establish a Rapport&lt;/h2&gt;
&lt;p&gt;For an interviewee, one the the most efficient way to build a rapport is to &lt;strong&gt;try to see things in from the interviewer&amp;rsquo;s perspective&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;understand the motivation of the interviewer&lt;/li&gt;
&lt;li&gt;establishing a common ground&lt;/li&gt;
&lt;li&gt;adapting your responses appropritely&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="reasons-they-recruit"&gt;Reasons They Recruit&lt;/h2&gt;
&lt;p&gt;If you know what the reason is and understand the motivation for it, then you can optimize your approach accordingly.&lt;/p&gt;
&lt;h3 id="planned-expansion"&gt;Planned Expansion&lt;/h3&gt;
&lt;p&gt;This is a common scenario that the company&amp;rsquo;s expansion require them to take on more programmers accordance with the comming business growth. &lt;/p&gt;
&lt;h4 id="the-interviewer-vs-you"&gt;The Interviewer vs. You&lt;/h4&gt;
&lt;p&gt;As the hiring is due to a long plan, so the interviewer is unlikely to feel a great sence of urgency. The interviewer will have a well prepared job description (a.k.a JD), or even a person profile. The interviewer are unlikely to compromise their pre-determined requirements. If you are deviate from their expectation, they will probable be less open to giving you the offer.&lt;/p&gt;
&lt;p&gt;Your approach is to &lt;strong&gt;highlight&lt;/strong&gt; these areas which matches to the job profile. That&amp;rsquo;s the easy part.&lt;/p&gt;
&lt;p&gt;If your skills are not a good fit, you can use these three tricks below to change the situation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Play it down&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your first choice is to downplay the perceived gap in skills &amp;ndash; including the option of substituting other experience as being of equivalent value.&lt;/p&gt;
&lt;p&gt;For example,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“It’s been my experience that it never takes long to learn the basics of a new component library, since, as programmers, we face an endless supply of new components and frameworks both open source and from the major vendors.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;or,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“One thing I really like about programming is the experience of learning new&lt;br&gt;
technologies and platforms. It’s part of the ongoing attraction of the job.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, the biggest risk in taking this approach is that you might appear evasive, so be wary of overdoing it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Take it on the chin&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you decide to take it on the chin, simply agree with the interviewer&amp;rsquo;s observation and at the same time show your enthusiasm for learning something new.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I don’t have experience of that particular technology but I would really enjoy learning it.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the interviewer persists, you might feel it appropriate to ask how other developers in the team might learn new things.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Could you describe how the developers in your team generally learn new skills?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each example the interviewer gives you is an opportunity to show how, as a part of the team, you would &lt;strong&gt;benefit the same approach&lt;/strong&gt; and so acquire the necessary skill.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understand the requirement&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your third option is to gently probe the motives underpinning the requirement. The basic idea is that you explore the requirement looking to show that you understand and can meaningfully address the underlying requirement despite lacking a specific skill or experience.&lt;/p&gt;
&lt;p&gt;Whatever approach you take, keep in mind that you should not &lt;strong&gt;dwell on any particular mismatch&lt;/strong&gt;. In particular, keep you comment brief and to the point. The more you talk about it, the more prominence it will have in the interviewer&amp;rsquo;s memory of the interview when they reflect afterward.&lt;/p&gt;
&lt;h3 id="specific-projet"&gt;Specific Projet&lt;/h3&gt;
&lt;p&gt;When a company spots an opportunity in the market, it might scramble to put &lt;br&gt;
together a development team focused on delivering a solution to capitalize on &lt;br&gt;
the opportunity. &lt;/p&gt;
&lt;h4 id="the-interviewer-vs-you_1"&gt;The Interviewer vs. You&lt;/h4&gt;
&lt;p&gt;The interviewer wants to know that you can work under pressure, and that you are someone who finishes what you start. Sometimes that the pressure to hire can relax the strictness with which the interviewer will match your experience against the details of job specification, although of course you can&amp;rsquo;t assume that case.&lt;/p&gt;
&lt;p&gt;Be ware that although you have to demonstrate how your skills and experience are good match for the position, the interviewer also probable has the need of specific project in mind. You enthusiasm and ability to adapt might count for more than usual. Showing an ability of &lt;strong&gt;grasp key aspect of project&lt;/strong&gt; give you an advantage over others.&lt;/p&gt;
&lt;p&gt;If you are not sure of the motivation of hiring, there&amp;rsquo;s absolutely no harm to ask directly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Could I ask why you are recruiting? Is it for a specific project?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="replacing-someone"&gt;Replacing Someone&lt;/h3&gt;
&lt;p&gt;This is another common reason for hiring simply to replace someone who is leaving or has left the company.&lt;/p&gt;
&lt;h4 id="the-interviewer-vs-you_2"&gt;The Interviewer vs. You&lt;/h4&gt;
&lt;p&gt;An interesting aspect of this situation is that they will probably have experience of a previous person i  lling this role, for better or for worse, and will therefore have a list of things they want to ensure the next person will and won’t bring to the role.&lt;/p&gt;
&lt;p&gt;Unless you are very lucky, you can&amp;rsquo;t gather insight into what interviewer like or dislike prior to the interview. What you can do at the interview is ask about &lt;strong&gt;unique challenge for the role&lt;/strong&gt;, things for which you might to need to be on guard, and so on:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Could you tell me a bit about the challenges of this role that might make it different from the usual programming job?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you ask right questions, you may get vatal clues about the things you need to highlight with regard to your experience and ability:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Can I ask whether there have been issues about how the team has been working together that make this ability particularly important?”&lt;/p&gt;
&lt;/blockquote&gt;</content><category term="Blog"/><category term="interview"/><category term="programming interview"/><category term="读书"/></entry><entry><title>Quora - What are effective ways to assess if someone is good at "getting things done"?</title><link href="https://wizmann.top/good-at-get-things-done.html" rel="alternate"/><published>2014-11-15T16:08:10+08:00</published><updated>2014-11-15T16:08:10+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-11-15:/good-at-get-things-done.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;Ian McAllister, GM at Amazon. I lead the AmazonSmile program.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;First, let’s break “getting things done” into two components: “excellent functional skills” and “drive”. Someone with great functional skills but poor drive will not get (enough) things done. Someone with great drive but poor functional skills will not get …&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;Ian McAllister, GM at Amazon. I lead the AmazonSmile program.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;First, let’s break “getting things done” into two components: “excellent functional skills” and “drive”. Someone with great functional skills but poor drive will not get (enough) things done. Someone with great drive but poor functional skills will not get things done, or they’ll do the wrong things, or they’ll do the right things shittily.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Excellent functional skills&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can probe for domain knowledge and functional skills effectively in an interview or on a phone call. You come up with a list of role-specific responsibilities, probe deeply (several levels below the surface) into past examples where they’ve done similar work, and give them example challenges and see how they perform. You can make allowances for language or tool by letting them pick the language or tool of their choice, but don’t give them a pass on accomplishing the task set forth. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Drive&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Drive is tougher to gauge effectively. You’ll have to form a picture of drive based on a number of different signals, and use your judgment on how heavily to weight each one.&lt;/p&gt;
&lt;p&gt;Projects they’ve initiated - Are they spawning new projects, based on their own ideas or prototypes? If so, that’s evidence they’re pushing the boundaries of their role in good ways. If they haven’t, then they might make a good soldier, but you’ll know going in that they’ll always need someone to tell them what to do next.&lt;/p&gt;
&lt;p&gt;Variation in projects or roles - Have they worked on the same types of projects for 5+ years? If so, they might have deep knowledge and be able to get things done in that domain, but it is evidence that they have a comfort zone. They clearly don’t have a drive to leave or expand their comfort zone, and may not be effective if your role places them outside of it. Look for evidence that a candidate has initiated some type of change in the type of work they do.&lt;/p&gt;
&lt;p&gt;Progression in complexity of projects or roles - Someone good at getting things done gets more done over time. Often the results of this are not more projects, but projects of larger scope and complexity. A good résumé will show this, but you can also probe for it explicitly.&lt;/p&gt;
&lt;p&gt;Side projects - I have a hard time hiring engineers, web developers, or designers (maker roles) who don’t have a history of side projects. These days, if you’re hiring a young engineer you’re looking for one who has been coding since she was twelve (or younger).&lt;/p&gt;
&lt;p&gt;I intend to add more signals as I think of them, but hopefully these are a start.&lt;/p&gt;</content><category term="Blog"/><category term="get things done"/><category term="quora"/><category term="career"/></entry><entry><title>The Checklist of Steve Yegge</title><link href="https://wizmann.top/steve-yegge-interview-checklist.html" rel="alternate"/><published>2014-10-26T00:24:44+08:00</published><updated>2014-10-26T00:24:44+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-10-26:/steve-yegge-interview-checklist.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;Hey man, I don&amp;rsquo;t know that stuff&lt;/p&gt;
&lt;p&gt;Stevey&amp;rsquo;s talking aboooooout&lt;/p&gt;
&lt;p&gt;If my boss thinks it&amp;rsquo;s important&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m gonna get fiiiiiiiiiired&lt;/p&gt;
&lt;p&gt;Oooh yeah baaaby baaaay-beeeeee....&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;非技术部分&lt;/h2&gt;
&lt;h3 id="_2"&gt;热身&lt;/h3&gt;
&lt;h4 id="_3"&gt;好好读一本讲数据结构和算法的书 …&lt;/h4&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;Hey man, I don&amp;rsquo;t know that stuff&lt;/p&gt;
&lt;p&gt;Stevey&amp;rsquo;s talking aboooooout&lt;/p&gt;
&lt;p&gt;If my boss thinks it&amp;rsquo;s important&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m gonna get fiiiiiiiiiired&lt;/p&gt;
&lt;p&gt;Oooh yeah baaaby baaaay-beeeeee....&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_1"&gt;非技术部分&lt;/h2&gt;
&lt;h3 id="_2"&gt;热身&lt;/h3&gt;
&lt;h4 id="_3"&gt;好好读一本讲数据结构和算法的书&lt;/h4&gt;
&lt;p&gt;熟悉一些“术语”，可以强化分辨问题的能力。&lt;/p&gt;
&lt;p&gt;Yegge推荐了 Steven S. Skiena 的&lt;a href="http://book.douban.com/subject/4048566/"&gt;《算法设计手册》&lt;/a&gt;，而我推荐的是&lt;br&gt;
Udi Manber 的&lt;a href="http://book.douban.com/subject/1436134/"&gt;《算法引论》&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;每一本书都有它的长处短处。找一本评价不错的书，认真读完，肯定会有收获。&lt;/p&gt;
&lt;h4 id="_4"&gt;找个朋友来面试你，尝试白板编程&lt;/h4&gt;
&lt;p&gt;在白纸/白板上编程的体验和在计算机上大有不同。没有条件的情况下，试试Leetcode的“Pick one”，然后在白纸上练习吧！&lt;/p&gt;
&lt;h4 id="_5"&gt;在面试前保持警醒，充分热身&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;读读书记&lt;/li&gt;
&lt;li&gt;喝点咖啡，这可以让你的思路快一些&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_6"&gt;心理准备&lt;/h3&gt;
&lt;h4 id="_7"&gt;保持谦逊、开明、专注的态度&lt;/h4&gt;
&lt;p&gt;不要质疑面试官的水平，但是也不要害怕问问题。问一个蠢问题总比沉默僵持半小时要好的多。况且，一个好问题也许还是一个加分项。&lt;/p&gt;
&lt;p&gt;并且，不要尝试去转移话题，把注意力放在问题本身。&lt;/p&gt;
&lt;h4 id="_8"&gt;了解面试官对代码的要求&lt;/h4&gt;
&lt;p&gt;有的面试官不会要求你写代码，但是他们希望你在回答问题时写一点代码。如果你不能确定，不妨直接问一下。&lt;/p&gt;
&lt;p&gt;不同的面试官对于面试代码风格的要求是不一致的，对于苛刻的面试官，最好提高对代码的要求。并且仔细检查。&lt;/p&gt;
&lt;h4 id="_9"&gt;问问题的艺术&lt;/h4&gt;
&lt;p&gt;在面试中的有不清楚的地方是可以问的（并且问问题是被鼓励的），有时候还可以去和面试官确认自己是不是在正确的方向上。&lt;/p&gt;
&lt;p&gt;什么都不问，直接冲到白板前开始写代码有可能会留下“设计无用”的坏印象。所以，即使你确定自己怎么做，也要先说说自己是怎么样的。但是，也不要说的太多。&lt;/p&gt;
&lt;h4 id="_10"&gt;自带高级装备&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;细头可擦马克笔&lt;/li&gt;
&lt;li&gt;铅笔和橡皮&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在面试中要使用一切可以使用的资源，例如白板上的空间管理。&lt;/p&gt;
&lt;h2 id="_11"&gt;技术部分&lt;/h2&gt;
&lt;h3 id="_12"&gt;算法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;大O&lt;/li&gt;
&lt;li&gt;排序算法 —— 快速排序和归并排序&lt;/li&gt;
&lt;li&gt;哈希表&lt;/li&gt;
&lt;li&gt;树 —— 构造和遍历&lt;/li&gt;
&lt;li&gt;至少熟悉一种平衡二叉树 —— 必须掌握实现细节&lt;/li&gt;
&lt;li&gt;图 —— 存储与遍历，Dijkstra和A*&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;每次遇到问题，首先应当考虑的就是图算法。它们是任何关系最基本、最灵活的表示方法，任何有点意思的设计问题可以说有一半的机会涉及图算法。只有在你百分之百确定没办法用图算法来解的时候，才能去考虑其它方案。这条建议一定要牢记在心！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;NP问题 —— 应该知道NP完全问题是什么意思&lt;/li&gt;
&lt;li&gt;好好读数据结构书，&lt;strong&gt;能记多少记多少&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;离散数学 —— 计数问题、概率问题&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_13"&gt;计算机基础知识&lt;/h3&gt;
&lt;h4 id="_14"&gt;操作系统&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;进程、线程、并发&lt;/li&gt;
&lt;li&gt;锁、互斥锁、信号量，管程机制&lt;/li&gt;
&lt;li&gt;死锁和活锁&lt;/li&gt;
&lt;li&gt;进程和线程各需要什么资源、上下文切换、调度&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;作者推荐了 Doug Lea 的&lt;a href="http://book.douban.com/subject/1244021/"&gt;《Java并发编程》&lt;/a&gt;，做为一个Java hater，我决定还是勉为其难的看一下吧。:)&lt;/p&gt;
&lt;h4 id="_15"&gt;语言&lt;/h4&gt;
&lt;p&gt;至少要熟练掌握一种编程语言，最好是C++或者Java。并且&lt;strong&gt;一定要对那门语言的细节有相当程度的了解&lt;/strong&gt;。&lt;/p&gt;
&lt;h4 id="_16"&gt;其它的基础知识&lt;/h4&gt;
&lt;p&gt;在作者的文章中没有提到的，但是也许比较重要的知识。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CS专业第二重要的知识 —— 编译原理&lt;/li&gt;
&lt;li&gt;计算机网络 —— TCP/IP协议也许是个重点&lt;/li&gt;
&lt;li&gt;数据库的一些知识&lt;/li&gt;
&lt;li&gt;MapReduce？&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_17"&gt;其它&lt;/h2&gt;
&lt;p&gt;剩下的基本就是看脸了。。。&lt;/p&gt;
&lt;p&gt;&lt;img alt="puzzles" src="https://github.com/Wizmann/assets/raw/master/wizmann-pic/fa4b0cfd335bae28abf23d34fc6e84ee"&gt;&lt;/p&gt;
&lt;h2 id="_18"&gt;总结&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;好好热身。实际工作只会让你反应迟钝！&lt;/p&gt;
&lt;/blockquote&gt;</content><category term="Blog"/><category term="interview"/><category term="Google"/></entry><entry><title>Snake Problem</title><link href="https://wizmann.top/snake-problem.html" rel="alternate"/><published>2014-10-20T09:11:27+08:00</published><updated>2014-10-20T09:11:27+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-10-20:/snake-problem.html</id><summary type="html">&lt;h2 id="_1"&gt;题目&lt;/h2&gt;
&lt;p&gt;在一个平面上，有n+m条蛇，其中n条蛇沿水平方向（y轴方向）移动，m条蛇沿竖直方向（x轴方向）移动。&lt;/p&gt;
&lt;p&gt;现给出这些蛇头和尾所在的坐标点，求出这n+m条蛇在此时共有多少个交点。在同一个方向移动的 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;题目&lt;/h2&gt;
&lt;p&gt;在一个平面上，有n+m条蛇，其中n条蛇沿水平方向（y轴方向）移动，m条蛇沿竖直方向（x轴方向）移动。&lt;/p&gt;
&lt;p&gt;现给出这些蛇头和尾所在的坐标点，求出这n+m条蛇在此时共有多少个交点。在同一个方向移动的蛇不会有交点。&lt;/p&gt;
&lt;p&gt;如图所示，n = 5, m = 4，这些蛇一共有5个交点。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAvcAAAGjCAYAAACoiDrHAAAABHNCSVQICAgIfAhkiAAAEipJREFUeJzt3TFuHFe2x+FDogISVcwm8Qa4gXZIQpxtOLdmDYoMR1rDkxfzJJDO3F6AFyAHciZyupOpnoCGgPGbN3U8ul2XOvy+xIJw8WcBmgF+apT6nnz4cDj85S+xaLef4/zsdPHcb79F2LNnz549e/bs2bNnb/295Z8GAAB8EU4+fDgcMgfHaY6H+3Z/F7Bnz549e/bs2bNnz17bvROv5dizZ8+ePXv27NmzV2PPazkAAFCEuAcAgCLEPQAAFCHuAQCgCHEPAABFiHsAAChC3AMAQBHiHgAAijj5++4fqRtqAQCAp214uD99sjds2bNnz549e/bs2bNnL7/ntRwAAChC3AMAQBHiHgAAihD3AABQhLgHAIAixD0AABQh7gEAoIih9wP8J19//XXvRwAA4Bn56aefej/CZxkiHr84f8k45c4dYw8AANbQq3db7Q0R2RuxcufyN2zlzkVE/PS//5M7CAAA/4Wv//q3iOjTuy33vHMPAABFiHsAAChC3AMAQBHiHgAAihD3AABQhLgHAIAixD0AABQh7gEAoIhhnObY7XOHd/t58cw4RdM9AABYS4/ebbk3PNyfJm/EmuP8bPmD/vwNW7k9AABYS4/ebbmnrgEAoAhxDwAARYh7AAAoQtwDAEAR4h4AAIoQ9wAAUIS4BwCAIsQ9AAAUMUQ8fnH+knHKnTvGHgAArKFX77baGyKyN2LlzuVv2MqdAwCAtfTo3ZZ7w/IMABzfx9tt3N9tY7raxMX1pvfjAHyRvHMPwJPw8W4b71+/iY93296PAvDFEvcAAFCEuAcAgCK8c//MeKcVAKAun9w/M95pBQCoS9wDAEAR4h4AAIoYxmmO3T53eLefF8+MUzTdAwCAtfTo3ZZ7w8P9afJGrDnOz5Y/6M/fsJXbA/49/zgaANrr0bst99Q1fKH842gA4I/EPQAAFCHuAQCgCHEPAABFiHsAAChC3AMAQBHiHgAAihD3AABQxBDx+MX5S8Ypd+4YewAAsIZevdtqb4jI3oiVO5e/YSt3DgAA1tKjd1vueS0HAACKEPcAAFCEuAcAgCLEPQAAFCHuAQCgCHEPAABFiHsAAChC3AMAQBHDOM2x2+cO7/bz4plxiqZ7AACwlh6923JveLg/Td6INcf52fIH/fkbtnJ7AACwlh6923JPXQMAQBHiHgAAihD3AABQhLgHAIAixD0AABQh7gEAoAhxDwAARYh7AAAoYoh4/OL8JeOUO3eMPQAAWEOv3m21N0Rkb8TKncvfsJU7BwAAa+nRuy33vJYDAABFiHsAAChC3AMAQBHiHgAAihh6PwAA8Hy8vd3Gu7tt78fgM7242sTN9ab3Y/BviHsAYDVv77bx/es3vR+Dz/Tdq5fi/okS9wDAam6uNhGvXvZ+DD7TzZWwf6rEPQCwmptrr3PAMQ3jNMdunzu828+LZ8Ypmu4BAMBaevRuy73h4f40eSPWHOdny1+uk79hK7cHAABr6dG7LffUNQAAFCHuAQCgCHEPAABFiHsAAChC3AMAQBHiHgAAihD3AABQhLgHAIAihojHL85fMk65c8fYAwCANfTq3VZ7Q0T2RqzcufwNW7lzAACwlh6923LPazkAAFDE0PsB+M/e3m7j3d222d7l7TYuI+Ld7TZ+iTfNdllf5s/yxdUmbq436z4YANCNuH/i3t5t4/vXnxfhJycnn3797eEQl7/v/vDjz59+/3A4fNbPYB1/9s/yu1cvxT0APCPi/om7udpEvHrZbO/ydhtxt40XV5v4SvR90TJ/ljdX/owB4DkR90/czXXb1yrex5v49W4bN9eb+KbhXxpYnz9LAOCP/INaAAAoQtwDAEAR4h4AAIoYxmmO3T53eLefF8+MUzTdAwCAtfTo3ZZ7w8P9afJGrDnOz5Y/6M/fsJXbAwCAtfTo3ZZ76hoAAIoQ9wAAUIS4BwCAIsQ9AAAUIe4BAKAIcQ8AAEWIewAAKELcAwBAEUPE4xfnLxmn3Llj7AEAwBp69W6rvSEieyNW7lz+hq3cOQAAWEuP3m2557UcAAAoQtwDAEAR4h4AAIoQ9wAAUIS4BwCAIsQ9AAAUIe4BAKAIcQ8AAEUM4zTHbp87vNvPi2fGKZruAQDAWnr0bsu94eH+NHkj1hznZ8sf9Odv2MrtAQDAWnr0bss9dQ0AAEWIewAAKELcAwBAEeIeAACKEPcAAFCEuAcAgCLEPQAAFCHuAQCgiCHi8Yvzl4xT7twx9gAAYA29erfV3hCRvRErdy5/w1buHAAArKVH77bc81oOAAAUIe4BAKAIcQ8AAEWIewAAKELcAwBAEeIeAACKEPcAAFCEuAcAgCKGcZpjt88d3u3nxTPjFE33AABgLT16t+Xe8HB/mrwRa47zs+UP+vM3bOX2AABgLT16t+WeugYAgCLEPQAAFCHuAQCgCHEPAABFiHsAAChi6P0AAMDT8vF2G/d325iuNnFxven9OMCf4JN7AOBffLzbxvvXb+Lj3bb3owB/krgHAIAihojHL85fMk65c8fYAwCANfTq3VZ7Q0T2RqzcufwNW7lzAACwlh6923LPazkAAFCEuAcAgCLEPQAAFCHuAQCgCHEPAABFiHsAAChC3AMAQBHiHgAAihjGaY7dPnd4t58Xz4xTNN0DAIC19OjdlnvDw/1p8kasOc7Plj/oz9+wldsDAIC19OjdlnvqGgAAihD3AABQhLgHAIAixD0AABQh7gEAoAhxDwAARYh7AAAoQtwDAEARQ8TjF+cvGafcuWPsAQDAGnr1bqu9ISJ7I1buXP6Grdw5AABYS4/ebbnntRwAAChi6P0A8Fy8vd3Gu7tts73L221cRsS72238Em+a7ULGi6tN3Fxvej8GAH8g7mElb++28f3rz4vwk5OTT7/+9nCIy993f/jx50+/fzgcPutnQMZ3r16Ke4AnSNzDSm6uNhGvXjbbu7zdRtxt48XVJr4SWazs5qr9/+Yufv//yMURtgGeC3EPK7m5bvsaw/t4E7/ebePmehPfNPxLA/Rycb2JC39RBfgs/kEtAAAUIe4BAKAIr+U8M95pBQCoaxinOXb73OHdfl48M07RdI+2vNMKAPD/69G7LfeGh/vT5I1Yc5yfLb/Fk79hK7cHAABr6dG7LffUNQAAFCHuAQCgCHEPAABFiHsAAChC3AMAQBHiHgAAihD3AABQhLgHAIAihojHL85fMk65c8fYAwCANfTq3VZ7Q0T2RqzcufwNW7lzAACwlh6923LPazkAAFCEuAcAgCLEPQAAFCHuAQCgCHEPAABFiHsAAChC3AMAQBHiHgAAihjGaY7dPnd4t58Xz4xTNN0DAIC19OjdlnvDw/1p8kasOc7Plj/oz9+wldsDAIC19OjdlnvqGgAAihD3AABQhLgHAIAixD0AABQh7gEAoAhxDwAARYh7AAAoQtwDAEARQ8TjF+cvGafcuWPsAQDAGnr1bqu9ISJ7I1buXP6Grdw5AABYS4/ebbnntRwAAChC3AMAQBHiHgAAihD3AABQhLgHAIAixD0AABQh7gEAoAhxDwAARQzjNMdunzu828+LZ8Ypmu4BAMBaevRuy73h4f40eSPWHOdnyx/052/Yyu0BAMBaevRuyz11DQAARYh7AAAoQtwDAEAR4h4AAIoQ9wAAUIS4BwCAIsQ9AAAUIe4BAKCIIeLxi/OXjFPu3DH2AABgDb16t9XeEJG9ESt3Ln/DVu4cAACspUfvttzzWg4AABQh7gEAoAhxDwAARYh7AAAoQtwDAEAR4h4AAIoQ9wAAUIS4BwCAIoZxmmO3zx3e7efFM+MUTfcAAGAtPXq35d7wcH+avBFrjvOz5Q/68zds5fYAAGAtPXq35Z66BgCAIsQ9AAAUIe4BAKAIcQ8AAEWIewAAKELcAwBAEeIeAACKEPcAAFDEEPH4xflLxil37hh7AACwhl6922pviMjeiJU7l79hK3cOgKfn7e023t1tez8GR3J5u43LiHh3u41f4s0qP/PF1SZurjer/Cz4T3r0bsu9YXkGAP7V27ttfP96nehjHScnJ59+/e3hEJfx+Of8w48/f/r9w+FwtJ//3auX4h4aEPcA/Gk3V5uIVy97PwZHcnm7jbjbxourTXy1UnDfXAl7aEHcA/Cn3Vx7haKy9/Emfr3bxs31Jr7xlzj4ovi2HAAAKELcAwBAEeIeAACKEPcAAFCEuAcAgCKGcZpjt88d3u3nxTPjFE33AABgLT16t+Xe8HB/mrwRa47zs+UP+vM3bOX2AABgLT16t+WeugYAgCLEPQAAFCHuAQCgCHEPAABFiHsAAChC3AMAQBHiHgAAihD3AABQxBDx+MX5S8Ypd+4YewAAsIZevdtqb4jI3oiVO5e/YSt3DgAA1tKjd1vueS0HAACKEPcAAFCEuAcAgCKG3g9AH29vt/Hubtv7MfgMl7fbuIyId7fb+CXeHPVnfffq5VH3AYA2xP0z9fZuG9+/Pm4Q0t7JycmnX397OMRlPP5Z/vDjz59+/3A4NP+54h4Avgzi/pm6udpECLYv2uXtNuJuGy+uNvHV9ab34wAAT4C4f6ZurjdxIwi/aO/jTfx6t42b60184y9qAED4B7UAAFDGME5z7Pa5w7v9vHhmnKLpHgAArKVH77bcGx7uT5M3Ys1xfrb8QX/+hq3cHgAArKVH77bcU9cAAFCEuAcAgCLEPQAAFCHuAQCgCHEPAABFiHsAAChC3AMAQBHiHgAAihgiHr84f8k45c4dYw8AWM/F1Sbi1cvH/8Iz06t3W+0NEdkbsXLn8jds5c4BAOu6uN7ExbWw53nq0bst97yWAwAARYh7AAAoQtwDAEAR4h4AAIoQ9wAAUIS4BwCAIsQ9AAAUIe4BAKCIYZzm2O1zh3f7efHMOEXTPQAAWEuP3m25NzzcnyZvxJrj/Gz5g/78DVu5PQAAWEuP3m25p64BAKAIcQ8AAEWIewAAKELcAwBAEeIeAACKEPcAAFCEuAcAgCLEPQAAFDFEPH5x/pJxyp07xh4AAKyhV++22hsisjdi5c7lb9jKnQMAgLX06N2We17LAQCAIsQ9AAAUIe4BAKAIcQ8AAEWIewAAKELcAwBAEeIeAACKEPcAAFDEME5z7Pa5w7v9vHhmnKLpHgAArKVH77bcGx7uT5M3Ys1xfrb8QX/+hq3cHgAArKVH77bcU9cAAFCEuAcAgCLEPQAAFCHuAQCgCHEPAABFiHsAAChC3AMAQBFD7wcA/jsXV5uIVy8f/wsAEL/H/W+/LR8cp9y5Y+wB/9fF9SYuroU9ALTUq3db7Q0R2RuxcufyN2zlzgEAwFp69G7LPe/cAwBAEeIeAACKEPcAAFCEuAcAgCLEPQAAFCHuAQCgCHEPAABFiHsAAChiGKc5dvvc4d1+XjwzTtF0DwAA1tKjd1vuDQ/3p8kbseY4P1v+oD9/w1ZuDwAA1tKjd1vuqWsAAChC3AMAQBHiHgAAihD3AABQhLgHAIAixD0AABQh7gEAoAhxDwAARQwRj1+cv2SccueOsQcAAGvo1but9oaI7I1YuXP5G7Zy5wAAYC09erflntdyAACgCHEPAABFiHsAAChC3AMAQBHiHgAAihD3AABQhLgHAIAixD0AABQxjNMcu33u8G4/L54Zp2i6BwAAa+nRuy33hof70+SNWHOcny1/0J+/YSu3BwAAa+nRuy331DUAABQh7gEAoAhxDwAARYh7AAAoQtwDAEAR4h4AAIoQ9wAAUIS4BwCAIoaIxy/OXzJOuXPH2AMAgDX06t1We0NE9kas3Ln8DVu5cwAAsJYevdtyz2s5AABQhLgHAIAixD0AABQh7gEAoAhxDwAARYh7AAAoQtwDAEARQ+8HyPj6r3/r/QgAAPDkDeM0x26fO7zbz4tnxima7gEAwFp69G7LvZMPHw6H3I1Yc5yfLb/Fk79hy549e/bs2bNnz549ey33vHMPAABFiHsAAChC3AMAQBHiHgAAihD3AABQhLgHAIAixD0AABQh7gEAoIiTDx8Oh8zBcZrj4b7d3wXs2bNnz549e/bs2bPXds8Ntfbs2bNnz549e/bsFdnzWg4AABQh7gEAoAhxDwAARYh7AAAoQtwDAEAR4h4AAIoQ9wAAUIS4BwCAIk7+vvtH6oZaAADgaRse7k+f7A1b9uzZs2fPnj179uzZy+95LQcAAIoQ9wAAUIS4BwCAIsQ9AAAUIe4BAKCIfwKP1g+twRLEdAAAAABJRU5ErkJggg=="&gt;&lt;/p&gt;
&lt;h2 id="_2"&gt;分析&lt;/h2&gt;
&lt;p&gt;对于此题，最简单直接的方法就是枚举蛇两两之间的关系，这种算法的时间复杂度为O(n^2)。&lt;/p&gt;
&lt;p&gt;当然，我们不能满足于这种暴力的解法。那么，有没有更优美的方法呢？&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alt text" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH8AAAFECAYAAAAOd+HJAAAABHNCSVQICAgIfAhkiAAABy9JREFUeJzt3D9s1AUYxvHnbFNCwmETEkybmE4ciRFDcozXwC5xpzs1uDqYuiBTdTBxsqHM2t3EGc3Vif4coDGhG5iUwFR6Rf4kxzm0d/1R7q2iba+8z/cztbTWI19ffk9JbKWzvtQRLL0z6BeAwSG+MeIbI74x4hsjvjHiGyO+MeIbI74x4hsjvjHiGyO+MYv4rWahVrMY9Ms4dIYH/QIOwursvCoVqTp5fdAv5VBJf/mtZqGNxYLr7yN9/NXZ+d7bD76e3+Uz/aSO37368vtc/7bU8ctX38X1b0sbf+fVl3+d69+UNn6/q+/i+jeljB9dffnjXH/S+OWrPzF1UfX1JdXXl3Ri6mLv17n+hPF3Xv34zHTft7n+hPF3Xv3IxHjv/ZGJca6/JFX8fle/Ojuv4vg5FcfPaXV2nusvSRV/t6vv4vq3pYn/4t6qnt6523u/fOE7lT/21+27enFvdV9f22FVyfR/6bbXWno4t6D2Wkvvf/P5rp/75xffami0qveuXNLQaPWAXuHhkio+3kyaP/bx5tLH37n2sS19fMSIb4zBZ4zLN0Z8Y+njs/Zj6eMjRnxjrH1jXL4x4htLH5+1H0sfHzHiG2PtG+PyjRHfWPr4rP1Y+viIEd8Ya98Yl2+M+MbSx2ftx9LHR4z4xlj7xrh8Y8Q3lj4+az+WPj5ixDfG2jc2fI3noCTpfKOuC5P1Qb+MA1WRlO7yK5XKv/q8Tmf7t351Zlpf7fLj2zIavpr8N1xrFjq99VM57zbqWgmu+0LD6+olg2f+6uy8Hmw92sZmpnf94YxuWPvG0l8+Yly+MeIbSx+fv9uPpY+PGPGNsfaNcfnGiG8sfXzWfix9fMSIb4y1b4zLN0Z8Y+njs/Zj6eMjRnxjrH1jXL4x4htLH5+1H0sfHzHiG2PtG+PyjRHfWPr4rP1Y+viIEd8Ya98Yl2+M+MbSx2ftx9LHR4z4xlj7xrh8Y8Q3lj4+az+WPj5ixDfG2jfG5RsjvrH08Vn7sfTxESO+Mda+MS7fGPGNpY/P2o+lj48Y8Y2x9o1x+caIbyx9fNZ+LH18xIhvjLVvjMs3Rnxj6eOz9mPp4yNGfGOsfWNcvjHiG0sfn7UfSx8fMeIbY+0b4/KNEd/Y8KBfQD+/NAv9uljsydeqNQvVtr7WSqOulcn6nnzdDA5n/MVC1/7Ht2WVSqX39uVOR7XS173x2++9j3U63nPnUMa/0KhLM9N78rVqzULauvzzjbrGuPwe1r4xBp8x4htLH5+/24+lj48Y8Y2x9o1x+caIbyx9fNZ+LH18xIhvjLVvjMs3Rnxj6eOz9mPp4yNGfGOsfWNcvjHiG0sfn7UfSx8fMeIbY+0b4/KNEd9Y+vis/Vj6+IgR3xhr3xiXb4z4xtLHZ+3H0sdHjPjGWPvGuHxjxDeWPj5rP5Y+PmLEN8baN8blGyO+sfTxWfux9PERI74x1r4xLt8Y8Y2lj8/aj6WPjxjxjbH2jXH5xohvLH181n4sfXzEiG+MtW+MyzdGfGPp47P2Y+njI0Z8Y6x9Y1y+MeIbSx+ftR9LHx8x4htj7Rvj8o0R31j6+Kz9WPr4iBHfGGvfGJdvjPjG0sdn7cfSx0eM+MZY+8a4fGPEN5Y+Pms/lj4+YsQ3xto3xuUbI76x9PFZ+7H08REjvjHWvjEu3xjxjQ1fS76Aa81CtcVCkrTSqGtlsr6v/76rM9P7+vX3UkVSumd+pVLpvX2501E3x7ykG6WPdTp7/1vvrC/t+dfcL8Nv03+p/0WtWUhbl3++UdfYPl/+24S1b4zBZ4z4xtLH5+/2Y+njI0Z8Y6x9Y1y+MeIbSx+ftR9LHx8x4htj7Rvj8o0R31j6+Kz9WPr4iBHfGGvfGJdvjPjG0sdn7cfSx0eM+MZY+8a4fGPEN5Y+Pms/lj4+YsQ3xto3xuUbI76x9PFZ+7H08REbHvQL2EvttZYezS1o6N1jOvnZ1K6f++j7H9V+vKGTVy5paLR6QK/wcEmz9l/cW9UfjSm1H29oaLSqM7d/CqO211q689Enaq+1NDRa1QfNHzQyMX7Ar3jw0vyxPzIxrqNnTkvajPtwbiH83IdzC2qvtSRJRz+sWYaXEsWXpPHSj5V7VApc1n009Ptn3KR65lcn6zrWqGtjsXjl+h9srfyxrdDd/yiONeqqGv9cvlSXL71+/S+fPe+9//LZc66+JF387vVLmxf+5NZy72NPbi1z9SXp4kuvXvTT5RWdvX9TZ+/f1NPllb6f4yrVM78revZz9a9K833+Tq1moZWPP5Wk3vf73fi1n68TX0n/2Jdef/Zz9a9LG1/q/1znWb8tdfzqZF1HTk303j9yaoKrL0kdX5Imvvuy79tIuvbLys9+rv5V6eNLPOcjab/Vwz9L/8xHjPjGiG+M+MaIb4z4xohvjPjGiG+M+MaIb4z4xohvjPjGiG+M+MaIb4z4xohvjPjG/gYdfhbrYRov+AAAAABJRU5ErkJggg=="&gt;&lt;/p&gt;
&lt;p&gt;对于这一条在y轴方向上的（红）蛇来说，它与x轴方向上的（黑）蛇共有三个交点。那么，也就意味着，问题的关键在于，我们如何快速确定某一条红蛇（或黑蛇）与其它蛇一共有多少个交点。&lt;/p&gt;
&lt;p&gt;我们可以做出如下假设，我们知道当x = k时，所有在平面上的蛇的位置。根据这个假设，我们可以使用区间求和的算法来确定竖直位置上的蛇会有多少个焦点。&lt;/p&gt;
&lt;p&gt;假设我们从x = 0到x = MAX_X方向进行扫描，每条蛇在扫描时，都有且只有两种状态：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;扫描线第一次经过蛇的某端点&lt;/li&gt;
&lt;li&gt;扫描线第二次经过蛇的另一个端点（废话！）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这两个状态分别意味着某一条黑蛇在x = k时是否存在。我们维护一个数组，数组中第u个元素代表y = u的黑蛇是否在x = k时存在。&lt;/p&gt;
&lt;p&gt;这个时候，当我们查询一条x = [v, w]位置的红蛇共有多少个交点时，只需要计算数组中[v &amp;hellip; w]元素的和。而使用树状数组(Binary Indexed Tree, BIT)，每次这样的查询只需要O(logN)时间。&lt;/p&gt;
&lt;p&gt;所以，总的时间复杂度为O(N * logN)，比O(N^2)的算法优化了很多。&lt;/p&gt;
&lt;h2 id="_3"&gt;代码&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;lowbit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;BITree&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_tree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_tree&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_tree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lowbit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_tree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lowbit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Snake&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// manual tested&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count_intersection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Snake&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xsnakes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Snake&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ysnakes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;_tree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xsnakes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Mark&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Mark&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ysnakes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Mark&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;_tree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;_tree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ysnakes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ysnakes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_tree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Mark&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;friend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mark&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;BITree&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_tree&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Snake&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xsnakes&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Snake&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Snake&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ysnakes&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Snake&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Snake&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Solution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count_intersection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xsnakes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ysnakes&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_4"&gt;题目来源&lt;/h2&gt;
&lt;p&gt;《算法引论》&lt;/p&gt;
&lt;h2 id="_5"&gt;扩展题目&lt;/h2&gt;
&lt;p&gt;POJ-2482 &lt;a href="http://poj.org/problem?id=2482"&gt;Stars in Your Window&lt;/a&gt;&lt;/p&gt;</content><category term="Blog"/><category term="binary indexed tree"/><category term="algorithm"/><category term="geometric"/></entry><entry><title>思维训练 - Thinkin' in induction 2</title><link href="https://wizmann.top/thinking-in-induction-2.html" rel="alternate"/><published>2014-10-01T00:05:29+08:00</published><updated>2014-10-01T00:05:29+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-10-01:/thinking-in-induction-2.html</id><summary type="html">&lt;h2 id="maximal-induced-graph"&gt;最大导出子图（maximal induced graph）&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;你现在在组织一个学术会议。现在你有一份人员名单。假定名单中的每一个人都同意到达，并且有充 …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;h2 id="maximal-induced-graph"&gt;最大导出子图（maximal induced graph）&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;你现在在组织一个学术会议。现在你有一份人员名单。假定名单中的每一个人都同意到达，并且有充足的时间交流意见。同时，每一个科学家都写下了他愿意与其进行交流的科学家的名字。&lt;/p&gt;
&lt;p&gt;现在，问题来了：&lt;del&gt;挖掘机技术哪家强？&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;如果要保证每一位科学家至少能与k位到场的科学家进行深入的交♂流♂。那么我们最多可以邀请多少人到会？&lt;/p&gt;
&lt;p&gt;注：如果A愿意和B交流，AB一定会进行交流。反之亦然。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们可以把问题转化成数学语言：对于一个无向图&lt;code&gt;G=(V, E)&lt;/code&gt;，试求得G的最大导出子图H，使得H中所有顶点的度大于或等于k，或者证明这样的子图是不存在的。&lt;/p&gt;
&lt;p&gt;我们继续使用归纳的思想来解决这个问题。&lt;/p&gt;
&lt;p&gt;易得，对于顶点数为k的图，如果存在k-导出子图，则该图必为一个完全图。&lt;/p&gt;
&lt;p&gt;假设，对于任意顶点数小于n的图，我们总可以找到图的k-最大导出子图。&lt;/p&gt;
&lt;p&gt;对于有n个顶点的图G来说，如果有任意顶点的度小于k，那么对于图G的任意子图，此顶点的度总小于k。&lt;/p&gt;
&lt;p&gt;所以，对于图中任意度小于k的点，必然不属于所求的子图。于是，我们每次删除一个不属于k-导出子图的点，就可以把有n个顶点的图问题化归为n-1顶点的图问题。&lt;/p&gt;
&lt;h2 id="_1"&gt;一对一映射&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个集合A和一个映射关系f。求A的一个子集S，使得f对于S是一个一对一映射。即：f把S中的一个元素映射到一个元素；S中没有两个元素映射到同一个元素。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们仍然可以做假设：对于含有k个元素的集合，我们有方法找到所求。&lt;/p&gt;
&lt;p&gt;基础情况的证明非常简单，对于一个点的情况，&lt;code&gt;f(A) = A&lt;/code&gt;满足条件。对于两个点，找到两个点&lt;code&gt;(A, B)&lt;/code&gt;，在图中有&lt;code&gt;(A -&amp;gt; B)&lt;/code&gt;和&lt;code&gt;(B -&amp;gt; A)&lt;/code&gt;即可。&lt;/p&gt;
&lt;p&gt;对于任意集合，我们可以确定，当没有&lt;code&gt;f(x) = i&lt;/code&gt;时，元素i必然不属于这个集合。所以，每次操作我们都删除掉必然不属于所求子集的那个点，把问题&lt;code&gt;Q(n)&lt;/code&gt;化归为子问题&lt;code&gt;Q(n-1)&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="_2"&gt;社会名流问题&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;社会名流都是逼格比较高的人，这体现在所有的人都认识他，但是他不认识任何人。&lt;/p&gt;
&lt;p&gt;试在n个人的聚会中，找出唯一的名流。而找出的名流的方法，就是询问任意一个人：Do you know that person? 每一个人都会如实回答。而你的目标是使询问次数最少。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们仍然使用归纳的方法，如果这个聚会只有两个人，我们很容易就知道谁&lt;strong&gt;不是&lt;/strong&gt;名流。(Why?)&lt;/p&gt;
&lt;p&gt;对于一般的情况，如果询问A：Do you know person B?&lt;/p&gt;
&lt;p&gt;如果A回答YES，那么A必然不是名流。如果A回答NO，那么B不是名流。&lt;/p&gt;
&lt;p&gt;如是，我们又可以一步一步缩小题目的数据范围。最后在排除了所有&lt;strong&gt;不是&lt;/strong&gt;名流的人之后，对最后一个候选人再进行一轮验证。&lt;/p&gt;
&lt;h2 id="_3"&gt;总结&lt;/h2&gt;
&lt;p&gt;以上三题都是&lt;strong&gt;Thinkin&amp;rsquo; in induction&lt;/strong&gt;的良好范例。对于有些题目，做出大胆的假设并不是纯粹的碰运气，而是一种科学的尝试。同时，在思考时，如果不能直观的找出“谁是对的“，我们不妨反向思考一下，找出“谁是不对的”。&lt;/p&gt;
&lt;p&gt;本文参考Udi Manber的《Introduction to algorithms - A creative approach》.&lt;/p&gt;</content><category term="Blog"/><category term="induction"/><category term="algorithm"/></entry><entry><title>思维训练 - Thinkin' in induction</title><link href="https://wizmann.top/thinking-in-induction.html" rel="alternate"/><published>2014-09-26T00:10:45+08:00</published><updated>2014-09-26T00:10:45+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-09-26:/thinking-in-induction.html</id><summary type="html">&lt;h2 id="-24game"&gt;热身题 - 24Game&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://codeforces.com/contest/469/problem/C"&gt;原题请戳我&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="_1"&gt;题意&lt;/h3&gt;
&lt;p&gt;给你一个包含整数1&amp;hellip;n的集合S。接下来进行n-1次操作，每次操作从集合S中选取两个数，在加、减、乘三种运算中选取一种，将结 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="-24game"&gt;热身题 - 24Game&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://codeforces.com/contest/469/problem/C"&gt;原题请戳我&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="_1"&gt;题意&lt;/h3&gt;
&lt;p&gt;给你一个包含整数1&amp;hellip;n的集合S。接下来进行n-1次操作，每次操作从集合S中选取两个数，在加、减、乘三种运算中选取一种，将结果放回再集合S。在n-1次操作完成后，集合S中只剩下一个数。求问一种取数和运算策略，使最后的结果为24。&lt;/p&gt;
&lt;p&gt;举例：&lt;/p&gt;
&lt;p&gt;S = [1, 2, 3, 4, 5]&lt;/p&gt;
&lt;p&gt;我们选取(2, 5)，并进行加法运算，获得结果7。再将7放回集合S中。&lt;/p&gt;
&lt;p&gt;此时，S = [1, 3, 4, 7]。&lt;/p&gt;
&lt;h3 id="_2"&gt;数据范围&lt;/h3&gt;
&lt;p&gt;1 &amp;lt;= n &amp;lt;= 100000&lt;/p&gt;
&lt;h3 id="_3"&gt;解答&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;建议：请思考10分钟后再来看答案&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们日常写代码，往往是为了实现一个功能或者实现一套逻辑。这时候，我们做的事一般是从零开始，然后逐步迭代，最终实现目标。&lt;/p&gt;
&lt;p&gt;这是正常的一种思维方式，也是不错的思维。但是，在我们做题时，按部就班的思路往往会束缚我们的想法。我经常自黑说：&lt;strong&gt;“做什么题都像做模拟题”&lt;/strong&gt;，实际上就是这样一个道理。&lt;/p&gt;
&lt;p&gt;对于此题，如果我们从零开始思考，必然会遇到“第一次选哪两个数”、“第二次选哪两个数”这样的问题，而解决这种问题的方式大多只能有暴力搜索一种方式。而根据这题的数据规模，暴力搜索在时间和空间上都是不可能的。&lt;/p&gt;
&lt;p&gt;当然，也有的同学善于逆向思维，但是，同样也会进入暴力搜索的死路中。&lt;/p&gt;
&lt;p&gt;那么这题如何思考呢？ 我们不妨试试归纳法。&lt;/p&gt;
&lt;p&gt;假设&lt;code&gt;n = k&lt;/code&gt;，并且有&lt;code&gt;f(k)&lt;/code&gt;，使得&lt;code&gt;f(k)=&amp;gt;24&lt;/code&gt;。那么，易得，对于&lt;code&gt;f(k + 2)=&amp;gt;f(k) * ((k + 2) - (k + 1))=&amp;gt;24&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;此时，我们只需要找到&lt;code&gt;f(k)=&amp;gt;24&lt;/code&gt;，就可以证明所有&lt;code&gt;f(k + 2x) =&amp;gt; 24&lt;/code&gt;。聪明的同学们必然可以手动算出&lt;code&gt;f(4) = 24&lt;/code&gt;的过程，这可以证明对于所有&lt;code&gt;k &amp;gt;= 4&lt;/code&gt;的偶数，总有&lt;code&gt;f(k) =&amp;gt; 24&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;f(5) =&amp;gt; 24&lt;/code&gt;略微复杂一点，但是也不在话下。这样我们的结论已经扩展到了&lt;code&gt;k &amp;gt;= 4&lt;/code&gt;的所有整数。&lt;/p&gt;
&lt;p&gt;又由于在&lt;code&gt;k = [1, 2, 3]&lt;/code&gt;时，&lt;code&gt;f(k)&lt;/code&gt;必须不能推出24。我们的结论已经推广到了所有正整数。此题得证。&lt;/p&gt;
&lt;h2 id="_4"&gt;归纳法&lt;/h2&gt;
&lt;p&gt;在Udi Manber的_Introdcution to Algorithms - A creative approach_一书中，在第二章就对数学归纳法进行了大篇幅的的讲解。而在一般的算法书中，这个位置往往是给了算法分析。&lt;/p&gt;
&lt;p&gt;归纳法是一种“非常有力的证明方法”，可以提供一种想问题的方法，同时可以证明算法的正确性。&lt;/p&gt;
&lt;p&gt;归纳法的基本过程如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let T be a theorem we want to prove.&lt;/p&gt;
&lt;p&gt;Suppose that T includes a parameter n whose value can be any natural number. &lt;/p&gt;
&lt;p&gt;Instead of proving directly that T holds for all values of n, we prove the following two conditions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;T holds for n = 1&lt;/li&gt;
&lt;li&gt;For every n &amp;gt; 1, if T holds for n - 1, then T holds for n&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id="_5"&gt;归纳法应用 —— 笛卡尔树&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;已知一个最大堆的中序遍历序里，要求恢复该最大堆。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;或者用另外一种方法来表示，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个数组，求一个二叉树，这个二叉树的父节点总比子节点要大，并且这棵树的中序遍历与原数组相同&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果我们从build from scratch的角度来思考这个问题，那么得出来的结论一定是O(n^2)的 —— 每次找到（子）数组的最大值，然后partition这个数组，直到构造出整棵树。&lt;/p&gt;
&lt;h3 id="_6"&gt;换一种思考方式&lt;/h3&gt;
&lt;p&gt;我们尝试用归纳法的思维去考虑这道题。假设我们已经有一棵树，这棵树满足上面所说的条件，且这棵树展开后为数组的前k项。&lt;/p&gt;
&lt;p&gt;此时，我们想要插入第k+1项，有以下几种情况。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;A[k+1] &amp;lt;= A[k]&lt;/code&gt;，此时第k+1项会成为到第k项的右儿子，这样树展开时，第k项和第k+1项必然相联，并且也满足父节点必须比子节点大的条件。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;A[k+1] &amp;gt; A[k]&lt;/code&gt;，第k+1项必然会成为第k项的左儿子。但是我们还需要考虑，第k项的父节点比第k+1项小的情况。经过思考，我们不难发现，第k+1项的左儿子t，一定是第k项祖先节点中小于第k+1项的最大值。而第k+1项则替换掉节点t的位置。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;情况一示意图：&lt;/p&gt;
&lt;p&gt;&lt;img alt="cond1" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAYwAAAFLCAYAAADF1LtGAAAABHNCSVQICAgIfAhkiAAAEJJJREFUeJzt3XusZdVdwPHfuQ+GERyGwUBLYYZ2aKGlaYrYBoKVEoViLBYaiS1TKpFGHmof1EZCiNEUqsak1T5ACq0ttvgIIkIhlqGARROU6AA2SpEyQB9AQy0ggWFm7hz/gAN37nPdc/bZe+21P59k/oBhLvuec2d99/rtve/t9fv9fgDAMiaaPgAA2kEwAEgiGAAkEQwAkggGAEkEA4AkggFAEsEAIIlgAJBEMABIIhgAJBEMAJIIBgBJBAOAJIIBQBLBACCJYACQRDAASCIYACQRDACSCAYASaaaPgBy049dMzOxqx/Rm5yKyV7TxwPkwg6D3Tx/70Vx6NR0TE9Px0+846/j8V1NHxGQC8Fglufini98Oba++E/bv/HZuPEHM40eEZAPweBlz9wVl1/9/YiJn47f/NUDI3b9S1x63SOxs+njArIgGLyoH0/+8+fimiciJt/24Tj/Y++LDRHx75f9TXxnR9PHBuRAMHhB/0dx22dviKdjOt5+9olxyBtPj9NfHRH/dUX85X3PN310QAZ6/X6/3/RB0Lxdj34lfmH9GXHbAvOngz70b3H/n74lVtd/WEBGBKNwvd78+2Lnv+Uz8cjlx8aGc/41Jg77lTjnpFfFdET0n/lWfOUL34j/3f8Dccd3roif3buWQwYyJRiFWigUc7301u94ID75M6+Nj967V7zr+kfi709eF72IiO3/HZe86Q1x0bfXxntvfiiuPmGfsR4zkDfBKExKKObyJQCkcNEbgCSCUZBhdhej/DmgWwQDgCSCUYhRdwl2GcByBAOAJIIBQBLBACCJYACQRDAKMerDdx7eA5YjGAAkEYyCDLtLsLsAUggGAEkEo+PsLoBUglGQ2U9r9/v9RWMw+/c84Q2kmmr6AKje7FCk7CB6vZ6dBrAsO4xCDHYKK1n4Z/+3dhrAcgSjAKMs9nYWQCrBKMioi79dBrAUwWi5KhZ5oykghWAUwrcGAcZNMFpsmAvdS3GrLbAUwWBBogHMJRgtVfXuYsBoCliMYLTQuM/+jaaAhQhGi9WxGxANYEAwWqauBdyttsBcgtFSdewuXM8AZhOMFhnXhe6luJ4BDAgGyUQDuk0wWqKJ3cWA0RQQIRitkMOZvdEUIBgtksuZvmhANwlG5nJanHMJFtAMwWiJXBZroynoLsHIWJMXulOIBnSLYLBingKHbhKMTOW+u8j1uIDxEYwMteWs3fUM6BbByFibzuJFA8onGJlp28LbpqgBoxGMTLVpITaagm4QjIzkfqE7hWhAuQSDSrQ5ckAawchECbsLoykom2BkoMQFtsTPCbpOMDLS5t3FgKfAoVyC0bASF9USwgfMJxiZKG2RdT0DyiMYDSrhQncK0YAyCAZjU3oIoWsEoyFd2V0YTUE5BKMBXV08u/p5QykEo0Gl7y4G3GoLZRCMmnV1wexKHKFkgtGQLi+gXY0mtJ1g1KgrF7oXYzQF7SYYNbFAvqCrsYQSCEbNLJhutYW2EowaWBgX57WB9hCMGtldvMxrAe0jGGPW9QvdSzGagnYRDLIgGpA/wRgju4vludUW2kMwxsTil05QoR0EY8wshmlcz4D8CcYYWPRG4/WDPAnGGNldrIzXC/ImGBVzoXs0RlOQL8EgW6IBeRGMCtldVMPrB3kSjIo4G66W0RTkRzAq5uy4eqIBeRCMCljQxsNT4JAXwaiQ3UX1vKaQD8EYkQvd4+d6BuRBMGgV0YDmCMYI7C7q4zWG5gnGkJzp1s9oCpolGCNy5tsM0YD6CcYQLFbNEWhojmCMwOLVDKMpaIZgrJAL3XkRDaiPYNBKngKH+gnGCthd5MX7APUSjETOYvPkegbURzBWyFltvkQDxkswEliI8ibiUA/BWAELU77GOZrqb/9xfPeBb8eDjz4V230J0GGCsQwXutunqmjsenpLXP7rb4n9Vq2L9a89PDYeuDZW7Xd0fOyOp8NXA1001fQBQFX6/f5Lsej1eqNFfseDccWpx8Y5tz4XcfAvxe+cf0ocNvlY3PP1a+O+7z0X/VgTBpV0Ta/v1HlRg8Vnx44dEdGLialJW7IWqGJX+Oyd58XGYy6Lx6aPiysfuCXOWj84t+rHrn4vJtSCDrL+LWL2WGN6ejqmp6disteLiXWvj3f+3ub44UyDB0eS4UdTM/HEljvjsYiIN50e73jV7I24WNBdgrGMEyYjIl4Rp3380/Fnv/+eeM2P74sbP35W/PHd25o+NBbhKXAYD8FYwPxF5pVx/PvPi98+/7w44ZURETviuR27GjgyUo02aZ2Mnzry6HhFRMS9V8c/fn/nnI89ypFBe7mGsYCXZuBP3hAn7ndybJ6JiMmpmJjZGbsiYu0v/0VsuebMOGS60cMkwdzrGQvtOBb8K7Djwfjzk46Ic2/dFnHQL8b5H35XHDb1w/jW5uti66ab4h/ee4CzLTpHMObYbYF56msvBmPf+PlzPhBHTj0ct1z5t3H3tgPjrK//Z3z+xHUWjcwN7pZKGU3N/auw6+ktceVHzo4Lv3hX/GjwL9e+NT56/eb4k7e5S4ruEYxZZi8quwfjyLj04bvi3PU7454LXx9v/sOtse8Zt8d3rzou9mrweFneMNcw5v6V6O94Mh793hOxffX+ceABa2IPpaCjOvkcxnJjifkN/UHc8sVPx7Y9HoqbPr81IiIOOGz/MJHqht702jjw1WubPgxoXKeCsdTZ5tJnoo/HtX9wflwbEbH6oDj6zAvjsg8eHntUfYBUatg7pEZ+6A8K1YmRVBVjCdpnlFtqvf8wn2u2FGnU5y88vwHzFR+MUcYSALys+GAAUI2ig2EsAVCdooMBQHUEgyKNepeTu6RgPsEAIIlgUKxhdwl2F7CwooNhLAFQnaKDASuNvpMEWFzxwTCWYGCx97Tf7y/58zKAF3Tqmw9CyomAbz4ICyt+hxGx+xlklf8t+Zv7E/eW4n2HpXUiGANLxUAoiFj6R7lC13VyJCUM3bCS3cVif97XCrysUzsMSCESsDDBoEij7i6MpmA+wYBliAa8QDAoTlULvNEU7E4wKFYVC77RFLxMMCjKOBd20aDrBIMiVTlOMpqCFwgGJDCaAsGgIKPeSrvS/w90jWBAIqMpuk4wKEJduwujKbpMMGBIokHXCAatV/fCbTRFVwkGxahzITeaoosEg1bLYcHO4RigDoJBEZoYExlN0TWCASMwmqJLBIPWqutW2lSiQekEA0aUS7Bg3ASDVsptd2E0RRcIBlRMNCiVYNA6uS7Iuex2YFwEg9bKcYE2mqJkgkGrtGkhbtOxQgrBoJVy3F0M5HxsMArBgDEwmqJEgkFr5HYrbSrRoBSCAWPStrDBcgSDVmjr7sJoipIIBtRENGg7wSB7bd1dDLT1uGEuwYAaGE1RAsEgayUusCV+TnSDYNAKJYx1Svgc6DbBgBoZTdFmgkG22n6xezmiQdsIBtSs1ABSPsEgS6XvLoymaCPBgIaJBm0hGGSn9N3FQOmfH+URDGiQ0RRtIhhkpcsLZ5c/d9pBMMhSl8Y1XfpcaTfBIBtdPsM2mqINBIPsdP2MWzTIlWBAJroeSvInGGShK7fSLsdoipwJBmRKNMiNYNA4u4vdeR3IlWBAhoymyJFg0CgL4vK8RuRCMMiCMcx8XhNyIxg0xpnz8oymyIlg0Dhn0mlEg6YJBmROUMmFYNAIt9KujNEUORAMaBnRoCmCQe3sLobj9aJpggEtYjRFkwSDWlnoquO1pG6CQSOMV4bntaMpgkFtnBFXx2iKJggGtXOGXC3RoC5TTR8AXdSPXTMzsWtON3oTkzE5YfFL1e/3xYJa2WFQi91upX3qxjhp1XRMT+/+a92m2+OZho+zbYymqJMdBg1aE8eesSnevGYiIiZi7TEHxx5NH1KL9Xo94z7GSjAYu8Uf1NsYmy7+TJy7frL+gypI9aOpwciwF73JyZi0eeFFRlI0aEuct2Eqer1e9Hqr4rivPh7Oj4dT6WjqpZHhVExN9KLXm4x9Nrw1Trvomrj/We9Ql9lhMFZLfxuQveKod58aR+w9ERF7xhGHrq712EpV3WhqTRz7vvfEYdv/J/7putvimktOixu++cm4e/NH4vBVFXx4WkcwaNDr4qxPfclIqiLVj6Y2xqZLLo1z10/Gjoe/HKe88cy46Y6L4ndv/rW47uR1YVLVPYJBZVa+WD0QV11wbtz9ky/8udVv+I24+ENHxd7VH1pnDKJR9QXw6Q2nxG8dv2fcdMOz8R+3bY1tJ68L+8HuEQxGNvxZ7f/FnX91Rdw5+Mdjfi4u/OBRsbdT10pUHY3Bh+r1wu6iowSDoa0kFLtdy9jnnXHzThdPx2UcD/Rt3/p38elbt0XEXnHU8a8JlzC6STCgQAuNphaKyNI7kAfiqgvOjjufvz++ef0d8dDOiNVv/0T80Qn72mF0VK/vSR+GMMoZrC+5egxikfJe7faePPW1OHG/k2PzzOBfTMfaQ46ME99/QXziglNi42q56CrBYCiCkb9h3iPvDUvx4B4rNup83Pc9gnYSDCjQsFEWc5YiGAAkEQwojJEh4yIYACQRDFZs1Dtp3IkD7SQYACQRDIYy7C7B7gLaSzCgMEaGjIvvJcXQVvJT3ixC0H6+NQiVWfk3t2OcfGsQqmaHQWUsNlA21zCgUP1+f0URF3yWIxhQuKXCMfv3POHNcoykoCNSdhBV/1hXymKHAYgESQQDiIiV3SZNNwkGMI9osBDBAF5iNMVSBANYkF0GcwkGsBu7DBYjGMA8LoCzEMEAliQaDAgGsCCjKeYSDGBRRlPMJhhAEtFAMIAlGU0xIBjAsoymiBAMYIVEo7sEA0hiNIVgAMmMprpNMIChiEb3CAawIkZT3SUYwIoZTXWTYAAjEY3uEAxgKEZT3SMYwMjsMrpBMICh2WV0i2AAI3EBvDsEA6iMaJRNMICRGU11g2AAlTCaKp9gAJUTjTIJBlAZo6myCQZQKaOpcgkGMDaiURbBACpnNFUmwQDGwmiqPIIBjJ1olEEwgLExmiqLYAC1sMtoP8EAxsouoxyCAYydC+BlEAygVqLRXoIB1MJoqv0EA6iN0VS7CQbQCNFoH8EAamU01V6CAdTOaKqdBANolGi0h2AAjTCaah/BABpjNNUuggFkQTTyJxhAo4ym2kMwgMYZTbXDVNMHADBbr9erYNfRj5iZiZj7YSYmIyZEaVh2GEAWKh1NPXVjxKrpiOk5vzbdXt3/o4PsMIDsVLPLiIhYE3HGpog1ExExEXHMwRV8zO4SDCAb/X6/4usYGyMu/kzE+skKP2Z3GUkBWan2AviWiA1TEb1eRG9VxFcfr+BjdpcdBpCt0UdTe0W8+9SIvSciYs+IQ1dXdWidJBhAdqobTb0u4lNfMpKqiJEUkKUFR1O93vxf1MYOA8hav99fOgyD3/PE+Nj1+p7LB3I1zA7CkjY2RlIAJBEMIE/DXp9wXWNsBAOAJIIB5GfUXYJdxlgIBgBJBAOAJIIBQBLBACCJYAD5GfXhOw/vjYVgAJBEMIA8DbtLsLsYG8EAIInvVgvka7BbSHkQz85i7AQDyN9S4RCK2ggG0B7i0CjXMABIIhgAJBEMAJIIBgBJBAOAJIIBQBLBACCJYACQRDAASCIYACQRDACSCAYASQQDgCSCAUASwQAgiWAAkEQwAEgiGAAk+X9XZl99SNeETwAAAABJRU5ErkJggg=="&gt;&lt;/p&gt;
&lt;p&gt;情况二示意图：&lt;/p&gt;
&lt;p&gt;&lt;img alt="cond2" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQEAAAEPCAYAAABC5nGNAAAABHNCSVQICAgIfAhkiAAADW9JREFUeJzt3XuMnFUdh/Hvu7vTdimU0pqWa4tcLAIh1CqBIALRFowWCkoUCoQEBFovQBFTkRgNN40JCiJ3iGAlarDWXohaoAiSqI22INEKhdIK1BKQLmmgtLv7+gedZXZ2ZnfmvZ5zfs8n2YR26e7Zd+d93nPOvLMbxXEcC4BZHWUPAEC5iABgHBEAjCMCgHFEADCOCADGEQHAOCIAGEcEAOOIAGAcEQCMIwKAcUQAMI4IAMYRAcA4IgAYRwQA44gAYFxX2QNA1mL19/WpP5aizi51RmWPB65jJhCYd5+5Rod0VVSpVLTbKb/Qlv6yRwTXEYGgvKOn771fG3b9acejt2rFq32ljgjuIwIh2bZadz74itTxEX35C/tK/U/ptiWb1Fv2uOA0IhCMWFv/9BM99LrUecLlWnDVuZoq6W+3/1Iv7Cx7bHAZEQhF/IZW3bpMb6miky6ZpQOPPEfnfFDSP+/Wz9a9W/bo4LCIXz4Shv7Ni/SpKedpVYO5//6X/VXP/ehj6i5+WPAAEXBcFA19jm/ot6xPm+48XlMv/Ys6pn1el566nyqS4m3PatG9j+p/ky7Sky/crY/vXsiQ4Rki4KhGJ3+9gW/dzvW66aOH6spnxur0pZv0m9kTFEnSjn/p+qMO1zX/Hq+z//CSHpy5Z65jhp+IgGNaOfnr8S1EGmwMAsYRAYckmQWk+XeARAQA84iAI9JezZkNICkiABhHBADjiABgHBEAjCMCjkh7ww83DCEpIgAYRwQckvRqziwAaRABwDgi4DlmAUiLCDiketdfHMcDb43Uvo87BZEWv3fAEc1O5lau9FEUMSNAYswEHNPOycyJjywQAQfULgPaxbIAaRGBkmV58hICJEEEHJFmal/7bwkB2kUESpTlCcv+AJIiAg7I+gRmNoB2EIGSpNkMbIZlAZIgAiXI8wRlWYB2EYES5XXC8rQh2kEECpbHMqCVzwc0QwQKVOQJybIArSICJSjqBGVZgFYQgYIUvQxo9vmBekSgAGWegCwLMBIiUKCyTkiWBRgOEciZayeea+NB+YhAjmpPuLKn5WV/friLCBTAlROQZQEaIQI5cf1Ec318KA4RyJkrs4AqXmSEekQgB2XfEzASV8eFchCBjPl2dfVtvMgeEciJ61dblgWoIgIZcn0ZUM+XcSJfRCAjvl5NedoQRCBjPl9dCYFNRCADvi0D6vk6bmSDCKQUytWTZYFdRCAjIV1NCYEtRCCF0E6WkEKG1hGBDIR08rAssIcIJOT7ZmArCIENRCCB0E+OkMOGoYhACiGfLCwL7CACbbKwDKhHCMJGBNpg7WSwFDrLiEAClk4OlgXhIwItsrgMqEcIwkQEWmD9wc/PHggbEWiD5VmA5a89dERgBFz5huKYhIUIDMOlXx7iApYFYSICLSAA7+NYhIcINMGVrjmeNgwLERgBV77hEQL/EYEGuCdgZBybcBCBOlzZWseyIAxEoAmudO0hBP4iAjVYBrSPY+U/IrALV7LkWBb4jQjU4cqWDiHwDxEQy4AscOz8ZT4CtVeu3t4+9Zc4Ft+xLPCT+QjUqlS61BlF6pjwYX322yv1Wl/ZI/IXIfCH6QgMfqDurbOuvUU3f+eLOujNdVpx7YX6/trtpY3NV7zIyD+mI1A1s1OS9tHJ58/XVxfM18x9JGmn3tnJ4iCJ7PcHYqmvV+qte+tnHyILZiMwsBm4ddmuv1mj+QeNUde4T+iOzdL4027UN2bsVt4AA5HJbKBnhTS6IlXq3uY+nv5jQ11lD6AMjR+Ye+mTX7pI07s26pF7fqW1S7+l61adprtmTbBbyhTiOB44zlEUZTQ7GCedN1ca1yGpQzrugAw+JkxGoCqOY6ln+a4/HajPffNGzZvSq6f3WK2jb9ygxYv+oZtnnaixpY7SX7UhyMbB0nU/lqZ0ZvgxEWwEGj34ah+UQ69Mr+qR+27R9lEv6eG7NkiSJk+bpEreAw1c9ZhnMxtYI02tPmRHSYs2SXMnpx2iecFFYLgrz/BXpS1a/N0FWixJ3fvr2Auu1u1fO0yjsh6gYelDMFY68wxp9w5JY6RDurMammlRHMitXkmmnYF86V5IdVdmz3Jp4mypb7q0cTXLgYyx54VCNLybMIqGvqFwQUQg6eYTN7MUL47j4U94YlC4IJYDaU7mAL58fyT5PvH9yZ33M4G0V3NmA7DO+wjAE0ljS6RzRwQA44gA8pf2as5sIFdEADDO+wik3d3n2QFY530EAKQTRASSXs2ZBQCBRACOSxtbYp2rYF5F2M5PumUGALwviNuGG2n28wRQIm4bdlIwM4F6nPBAa4KNANxSOzNrKc9EvDBEAIUaNENrtDzg5C8cEUDumv5UIU54J/AUIXLFS7XdRwSQm0H7AFz1nUUEkDsC4DYigFyk+unCKBQRQObYB/ALEUCm2AfwDxFALgiAP4gAMsM+gJ+IADLBPoC/iABSYx/Ab0QAqRAA/xEBZIIA+IsIIDE2AsNABJAIG4HhIAJoG/sAYSECSIwAhIEIoC3sA4SHCKBl7AOEiQigJewDhIsIoC0EIDxEACNiHyBsRADDYh8gfEQATbEPYAMRwIgIQNiIABpiH8AOIoAh2AewhQhgEPYB7CECGEAAbCICGIIA2EIEIImNQMuIANgINI4IGFcbgE3Pr9OLm3u0g8mAKUQAkqS9JE059DAdvO94jZ54rK568i3RAhu6yh4AylM7C3jzgM/o6wvmaFrnf/X07xdr3cvvKNY4sVAIXxSzE2TSoH2Ayom6Z/0junBK9ZoQqz+O1EEBTGA5YNCQjcCjztEp+9VOCgmAJUTAsI23TS97CHAAETCm9n6AD0w/VntL0jMP6nev9A76/1gk2sGeQIAaPe8fx/HQ24J3vqg7Tj1C8x7bLu3/aS24/HRN63pNz65cog1zH9Zvz57MVcIAIhCQVm/6qf2W97+1RvdccYmuvm+13qj+5fhjdOXSlfrBCTw7YAERCECSO/7qv+3xzq3a/PLr2tE9SftOHqdRnP1mEIEAZBEB2MWSz3NJ7/vn9QKoIgKAcUTAY2mv5swGIBEBwDwiABhHBADjiABgHBHwWNrn+rlXABIRAMwjAp5LejVnFoAqIgAYRwQ8xw0/SIsfNBqI2ul9s58n0Ox9sI1XEXos6W8N4rcNoRbLAU9lcUVnVgCJCHgp7W8PHmnpAFuIgGey+vXhhABVRMBTWazn2ROARAS8kseGHs8agAh4Is8dfUJgGxHwQJEnJyGwhwg4LquNwJGwUWgXEXBYUQFo9DkIgR1EwANF7uLzjIE9RMBRZd7ay0ahLUTAQS6dfC6NBfkgAo4peh+gGfYH7CACDnElAI3GQAjCRQQc5EIAqlwaC/JBBBzh8mv82SgMGxFwgE8nl09jRWuIQMlc2wdohv2BcBGBEvkSgCpCECYi4AAfAlDl01jRGiJQEpc3AkfCRmFYiEAJfA5AFSEIBxEoWIgnTYhfkyVEoEC+bQSOhI3CMBCBgoQWgCpC4D8iULCQAlAV4tdkCREoQAgbgSNho9BfRCBnFk8Ki1+zz4hAjkLdB2iG/QE/EYGcWAtAFSHwDxHImaUAVFn8mn1GBHJgYSNwJGwU+oMIZIwH/VAcE7cRgQxZ3Qdohv0BPxCBjBCAxgiB+4hAxgjAUBwTt0Ux36EUYvX39amzq/LenziUw8p+w/S9499f9+Gijk51djDraBUzgTR6VgwEQJKiqFN7Tj1GZ13zkJ57myDUy/wZg54VOnV0RZXK4LcJcx/Xtmw+gwldZQ/AZ9H42QP/ffy5F2vajuf1xyWr9ND1Z2nZEzdp7cordNjoEgfosCiKMpwRjNPx583V0eM6JHVo/HEHaFRGH9kClgMJDb6aTddtG1dr3pRO7dx4v+YceYEe3rabTlv6Hy2ZPUFMTAfLbBO1Z7lmTZytlX3vH3+0j+VAArUP4pl1j7vK1Dn6ysljJL2tv6/aoO3FDs0L2T9jsEbzp3YpiiJF0Wid+PMt4srWOpYDKcRbl2nWxNlD/37XIzCKxCygiTiOM3zKcKxmnHmGjti9Q9IYHXFId0Yf1wYi0KZBO9w9y4e8f8eGX+uWx7ZLGqsZJx8ktgSaq4Yg/f7Ah3ThD3/KciAhItBAoyvU8Feu9Xpg4SX687vP6YmlT+qlXqn7pBv0vZl7MRNoUW0Imh3/5tbrgYXztHaP9/5d9+EX67rLZmj3PAYaIDYGa7Q6PR04ZAMbU9X3VDT+wOmadf5C3bBwjg7uJgGtqAagleM/6OE65PjvctwibXlqriZx+FtCBJRsc4rDlh2Of7l4dgAwznwEku5Q82KYbHD8y2c+AoB1piOQ9mrC1Sgdjr8bTEcAABEAzCMCgHFEADDOdATS3nDCDSvpcPzdYDoCAIhA4qsJV6FscPzLZz4CgHW8gKhG269iQ6Y4/uUgAg20/3p2ZInjXywiABjHngBgHBEAjCMCgHFEADCOCADGEQHAOCIAGEcEAOOIAGAcEQCMIwKAcUQAMI4IAMYRAcA4IgAYRwQA44gAYBwRAIwjAoBxRAAwjggAxhEBwDgiABhHBADjiABgHBEAjCMCgHFEADCOCADGEQHAuP8Dl+qMi0F2KEgAAAAASUVORK5CYII="&gt;&lt;/p&gt;
&lt;p&gt;由此一来，原本看起来复杂的思路一下子变的简单。我们可以把一个复杂的问题化归到重复的子问题上来。这样我们只需要每次解决一个问题了。&lt;/p&gt;
&lt;p&gt;关键代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;TreeNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;do_insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// one node at a time&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TreeNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;TreeNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="-"&gt;课后习题 - 最大子段乘积&lt;/h2&gt;
&lt;p&gt;这是Leetcode新加的一题，在昨天吃撑了喝醉了的情况下，勉强AC，今天看来，自己还是too young too simple啊。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个int数组，求这个int数组的最大子段乘积。（不需要考虑溢出）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="_7"&gt;从零开始的想法&lt;/h3&gt;
&lt;p&gt;最大子段乘积必然是一段不含有0的子段。所以我们可以把子段分割为k段，每一段都不包含0。&lt;/p&gt;
&lt;p&gt;对于每一个子段，要满足两个条件，一是尽量为正，二是尽量包含更多的数。&lt;/p&gt;
&lt;p&gt;所以对于子段A[l&amp;hellip;r]，最大乘积只能为A[m&amp;hellip;r]或A[l&amp;hellip;m]两种情况。所以我们维护两个指针，就可以求得最后的结果了。&lt;/p&gt;
&lt;p&gt;不过。。。等下。。。这真特么twisted啊。。。_(:з」∠)_&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// a drunk moron who wrote this&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maxProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;pro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pro&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;pro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pro&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x3f3f3f3f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_8"&gt;用归纳法解决这个问题&lt;/h3&gt;
&lt;p&gt;让我们做一个假设，对于A[k]来说，我们已知&lt;code&gt;mini = min(A[i...k])&lt;/code&gt;和&lt;code&gt;maxi = max(A[i...k])&lt;/code&gt;。mini和maxi是以k结尾的子段中，乘积绝对值最大的负数/正数。所以无论乘一个负数还是一个正数，maxi和mini的值只会是&lt;code&gt;maxi * a&lt;/code&gt;和&lt;code&gt;mini * a&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;那么，对于第k+1项来说，以第k+1项结尾的最大子序列必为&lt;code&gt;max(mini * A[k+1], maxi * A[k+1], A[k+1])&lt;/code&gt;(mini和maxi可能为0)。&lt;/p&gt;
&lt;p&gt;同时，我们继续维护mini和maxi两个值。此时，我们就有了一个循环的子问题。代码也就在我们的笔下了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;maxProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;mini&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;0xdeadbeef&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;mini&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
            &lt;span class="n"&gt;maxi&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
            &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mini&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;mini&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mini&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mini&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="induction"/><category term="binary tree"/><category term="codeforces"/></entry><entry><title>最小表示法及其证明</title><link href="https://wizmann.top/minimal-round-string.html" rel="alternate"/><published>2014-09-17T00:46:16+08:00</published><updated>2014-09-17T00:46:16+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-09-17:/minimal-round-string.html</id><summary type="html">&lt;h2 id="_1"&gt;问题&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;对于一个字符串S，求S的循环的同构字符串S’中字典序最小的一个。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们举例说明，字符串&amp;rdquo;abcd&amp;rdquo;的循环同构字符串有：&lt;code&gt;["abcd", "bcda", "cdab", "dabc"]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;题目的目标是 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;问题&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;对于一个字符串S，求S的循环的同构字符串S’中字典序最小的一个。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们举例说明，字符串&amp;rdquo;abcd&amp;rdquo;的循环同构字符串有：&lt;code&gt;["abcd", "bcda", "cdab", "dabc"]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;题目的目标是求这些字符串中字典序最小的那个。&lt;/p&gt;
&lt;h2 id="_2"&gt;暴力解法&lt;/h2&gt;
&lt;p&gt;暴力解法非常直观，直接枚举字符串的起点，然后找到构成最小字符串的那一个。&lt;/p&gt;
&lt;p&gt;代码就不在这里写了。&lt;/p&gt;
&lt;h2 id="_3"&gt;最小表示法&lt;/h2&gt;
&lt;p&gt;最小表示法是解决同构字符串最小表示的巧妙算法。&lt;/p&gt;
&lt;p&gt;其算法描述如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;令i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;如果S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;如果S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="n"&gt;如果S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;设指针k&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;分别从i和j位置向下比较&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;直到S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;如果S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i+k&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j+k&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;否则j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;返回i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;初看这个算法，一般都会一头雾水：这TMD是嘛玩意儿？&lt;/p&gt;
&lt;p&gt;但是我们可以经过证明，来证实它的正确性。&lt;/p&gt;
&lt;h3 id="_4"&gt;最小表示法的正确性证明&lt;/h3&gt;
&lt;p&gt;首先，&lt;code&gt;S = S ++ S&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;设&lt;code&gt;i &amp;lt; j&lt;/code&gt;，且&lt;code&gt;S[i] &amp;lt; S[i + 1 ... j - 1]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;并且以i为起点的字符串为&lt;code&gt;RS[i]&lt;/code&gt;，以j为起点的字符串为&lt;code&gt;RS[j]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;且&lt;code&gt;RS[i]&lt;/code&gt;为&lt;code&gt;RS[0...i-1]&lt;/code&gt;字典序最小的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;RS&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i...i+k&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i+k+1 ... i+n-1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;RS&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j...j+k&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j+k+1 ... j+n-1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;以上为我们的子问题。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;i = 0, j = 1&lt;/code&gt;时，子问题即成立。&lt;/p&gt;
&lt;h4 id="0"&gt;情况0&lt;/h4&gt;
&lt;p&gt;易得。&lt;/p&gt;
&lt;p&gt;当&lt;code&gt;S[i] &amp;lt; S[j]&lt;/code&gt;时，&lt;code&gt;j++&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;当&lt;code&gt;S[i] &amp;gt; S[j]&lt;/code&gt;时，&lt;code&gt;i = j; j++&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id="1"&gt;情况1&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;S[i+k+1 ... i+n-1] == S[j+k+1 ... j+n-1]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;此时易得，字符串S是由一个长度为k的子串循环复制生成。所有的同构子串只有&lt;code&gt;RS[i ... j-1]&lt;/code&gt;这k个，又由于&lt;code&gt;RS[i + 1 ... j - 1]&lt;/code&gt;的所有字符串都字典序大于&lt;code&gt;RS[i]&lt;/code&gt;。所以i即为最后的答案。&lt;/p&gt;
&lt;h4 id="2"&gt;情况2&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;S[i+k+1 ... i+n-1] &amp;gt; S[j+k+1 ... j+n-1]&lt;/code&gt;，那么此时&lt;code&gt;RS[i] &amp;gt; RS[j]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;由于&lt;code&gt;S[i...i+k] == S[j...j+k]&lt;/code&gt;，且这两个前辍中，只有&lt;code&gt;S[i] == S[j]&lt;/code&gt;字典序最小。&lt;/p&gt;
&lt;p&gt;所以i指向j点，保持最小性质。而j则指向&lt;code&gt;j + k + 1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;保持i &amp;lt; j，且S[i] &amp;lt;= S[j]的性质。使问题回到我们归纳的子问题上来。&lt;/p&gt;
&lt;h4 id="3"&gt;情况3&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;S[i+k+1 ... i+n-1] &amp;lt; S[j+k+1 ... j+n-1]&lt;/code&gt;，那么此时&lt;code&gt;RS[i] &amp;lt; RS[j]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;由于&lt;code&gt;S[i...i+k] == S[j...j+k]&lt;/code&gt;，且这两个前辍中，只有&lt;code&gt;S[i] == S[j]&lt;/code&gt;字典序最小。&lt;/p&gt;
&lt;p&gt;所以i不变，保持最小性质。而j指向&lt;code&gt;j + k + 1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;保持i &amp;lt; j，且S[i] &amp;lt;= S[j]的性质。使问题回到我们归纳的子问题上来。&lt;/p&gt;
&lt;h2 id="_5"&gt;代码&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Result: wizmann  1509    Accepted    272K    16MS    C++ 1247B   2014-09-17 00:44:22&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_6"&gt;后记&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;证明的逻辑性不好，但是应该是对的。只是语言表达上问题很大。&lt;/li&gt;
&lt;li&gt;有一个好的子问题假设会大大提升做题效率啊！&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_7"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.csdn.net/cclsoft/article/details/5467743"&gt;理解字符串循环同构的最小表示法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="string"/><category term="字符串"/><category term="最小表示法"/><category term="algorithm"/></entry><entry><title>System Design - 最热门的IP地址</title><link href="https://wizmann.top/hottest-ip-address.html" rel="alternate"/><published>2014-08-08T01:25:54+08:00</published><updated>2014-08-08T01:25:54+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-08-08:/hottest-ip-address.html</id><summary type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;问题是非常流行的，也确实流行了一阵的system-design问题。在&lt;a href="http://www.zhihu.com/question/19805967"&gt;知乎&lt;/a&gt;上再次被人提起。然后我非常欣赏&lt;a href="http://zhi.hu/3gJb"&gt;陈硕的回答&lt;/a&gt;。所以要写一篇 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;问题是非常流行的，也确实流行了一阵的system-design问题。在&lt;a href="http://www.zhihu.com/question/19805967"&gt;知乎&lt;/a&gt;上再次被人提起。然后我非常欣赏&lt;a href="http://zhi.hu/3gJb"&gt;陈硕的回答&lt;/a&gt;。所以要写一篇文章，记下自己的感想。&lt;/p&gt;
&lt;h2 id="_2"&gt;问题&lt;/h2&gt;
&lt;p&gt;海量数据算法:如何从超过10G的记录IP地址的日志中，较快的找出登录次数最多的一个IP？&lt;/p&gt;
&lt;h2 id="_3"&gt;银弹？&lt;/h2&gt;
&lt;p&gt;面对这种system-design问题，尤其是这种，&lt;strong&gt;非高并发、非实时&lt;/strong&gt;的问题，很多人会采用_map-reduce_ —— 解决system-design问题的银弹。&lt;/p&gt;
&lt;p&gt;我对map-reduce的理解非常肤浅，但是可以解释一下大概的流程。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将日志进行分片。把hash(ip)相同的ip地址分到同一个片中。（注：这里的hash并不是签名函数，只是一个分片标示）&lt;/li&gt;
&lt;li&gt;分片后的日志的大小会小很多，可以方便的进行排序，记数。&lt;/li&gt;
&lt;li&gt;然后再从各个片中，统计出最热门的IP地址。（或TopK的IP地址）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果不满意我的答案的话，推荐&lt;a href="http://book.douban.com/subject/19934150/"&gt;Mining of Massive Datasets&lt;/a&gt;一书，其中对map-reduce算法做一番不错的介绍。&lt;/p&gt;
&lt;h2 id="_4"&gt;正确的分析姿势&lt;/h2&gt;
&lt;h3 id="_5"&gt;业务实体&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;业务实体拥有四种主要的组件： 信息模型、生命周期模型、访问策略以及通知。 &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;换句话说，业务实体就是题目中提到的“名词”。&lt;/p&gt;
&lt;p&gt;在本题中，业务实体有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IP地址（默认为ipv4）&lt;/li&gt;
&lt;li&gt;最热门IP地址&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_6"&gt;业务应用&lt;/h3&gt;
&lt;p&gt;业务应用指的是当前场景的&lt;strong&gt;特殊&lt;/strong&gt;应用，以及业务实体的关联关系。&lt;/p&gt;
&lt;p&gt;在本问题中，业务应用指的是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;找到&lt;strong&gt;最热门&lt;/strong&gt;的IP地址&lt;/li&gt;
&lt;li&gt;大数据量，10G的日志文件 —— 不方便在内存中进行操作&lt;br&gt;
（在动辙上百G的服务器面前，10G的数据量真是弱爆了^_^)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_7"&gt;物理&lt;/h3&gt;
&lt;p&gt;物理指的是数据的物理模型，包括数据结构、数据库表等。&lt;/p&gt;
&lt;p&gt;在本题中，指的是对IP地址存储和记数的数据结构。&lt;/p&gt;
&lt;h3 id="_8"&gt;让我们做一下分析&lt;/h3&gt;
&lt;p&gt;本题中，业务实体的特点是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IPv4可以由一个uint32_t来表示&lt;/li&gt;
&lt;li&gt;ip地址是稀疏的&lt;ul&gt;
&lt;li&gt;大部分ip地址的访问次数非常少（长尾）&lt;/li&gt;
&lt;li&gt;很多ip地址是保留地址，所以不可能出现在日志中&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;业务应用的特点是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“最热门”表示要求得精确解，而不是满意解&lt;/li&gt;
&lt;li&gt;内存限制&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;应用的物理结构的特点是： 支持存储与记数&lt;/p&gt;
&lt;h2 id="_9"&gt;无代码无真相&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;assert.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdint.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;static_assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;64-bit only.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;counts_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;IPcount&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IPcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rhs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rhs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPcount&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;overflows_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IPcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;addOverflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IPcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lower_bound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;overflows_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;overflows_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newItem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;overflows_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;you need larger count variable&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;newItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;overflows_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newItem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newItem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counts_&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;addOverflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;counts_&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counts_&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;counts_&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getMostFrequenntIP&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counts_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xFFFFFFFFUL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;counts_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1L&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%zd&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;counts_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1L&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%08x %u&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_10"&gt;从代码说开来&lt;/h3&gt;
&lt;p&gt;这段代码不算最漂亮，有几个小槽点，但也算是非常优雅的。&lt;/p&gt;
&lt;p&gt;从思路上说，这段代码注意到了我们刚才分析到的，这个问题的业务特点。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ipv4地址可以存在uint32_t中，无需存储字符串&lt;/li&gt;
&lt;li&gt;ip地址是稀疏的，所以使用一层uint_8进行哈希记数，对于少数的热门ip再进行uint32_t计数&lt;br&gt;
（同时考虑了ip地址的稀疏性以及内存的限制，并且对内存的优雅使用，可以提高缓存的命中率，提高效率）&lt;/li&gt;
&lt;li&gt;使用精确计数，获得正确解&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="_11"&gt;代码留给我们的思考题&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;练习：找出 worse case，让运行时间长达几分钟甚至十几分钟，然后提出并实施改进措施&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;由于我们拿不出real world中的data，所以很多分析都是纸上谈兵，不过一切的实践也都是从纸上谈兵开始。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;题目中的&lt;code&gt;std::vector&amp;lt;IPcount&amp;gt; overflows_;&lt;/code&gt;使用&lt;code&gt;unordered_map&lt;/code&gt;更好，减少查找的时间（O(logN) =&amp;gt; O(1)），并且减少插入的时间（O(N) =&amp;gt; O(1)）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;std::vector&amp;lt;uint8_t&amp;gt; counts_;&lt;/code&gt;可以在适当的情况调整为&lt;code&gt;uint16_t&lt;/code&gt;，可以减少哈希节点生成对于内存的频繁申请。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_12"&gt;后记&lt;/h2&gt;
&lt;p&gt;题目中的分析有很多是“执果索因”的成果，毕竟反推比正推要更容易一点。&lt;/p&gt;
&lt;p&gt;想要从反推提升为正推，真的需要良好的发散思维以及敏锐的洞察力。因为面试时，没人会把题目帮你写在纸上。&lt;/p&gt;
&lt;p&gt;话说，我才知道ipv6是128位的。那么当题目中的ip地址为ipv6时，又会有什么好方法呢？&lt;/p&gt;
&lt;h2 id="_13"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.infoq.com/cn/news/2010/05/BEDL"&gt;介绍：业务实体和业务实体定义语言&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="interview"/><category term="system-design"/></entry><entry><title>Single Number Problem</title><link href="https://wizmann.top/single-number-in-the-array.html" rel="alternate"/><published>2014-08-05T23:07:02+08:00</published><updated>2014-08-05T23:07:02+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-08-05:/single-number-in-the-array.html</id><summary type="html">&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;There are a lot of interview problem based on the 1D-array, which is the one of the easiest &amp;ldquo;data structure&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;But the problem about that simple data structure might not be that simple. Here is the summary of the problem about 1D-array.&lt;/p&gt;
&lt;p&gt;Of course, most of them come from …&lt;/p&gt;</summary><content type="html">&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;There are a lot of interview problem based on the 1D-array, which is the one of the easiest &amp;ldquo;data structure&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;But the problem about that simple data structure might not be that simple. Here is the summary of the problem about 1D-array.&lt;/p&gt;
&lt;p&gt;Of course, most of them come from Leetcode.&lt;/p&gt;
&lt;h2 id="all-twice-excpet-one"&gt;All Twice Excpet One&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Given an array of integers, every element appears twice except for one. Find that single one.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This &lt;a href="https://oj.leetcode.com/problems/single-number/"&gt;problem&lt;/a&gt; is the very basic one. So I just paste my code here. If you are confused with the &lt;code&gt;xor&lt;/code&gt; operator， you might have to review the knowledge of &lt;strong&gt;bit manipulation&lt;/strong&gt; carefully.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# @param A, a list of integer&lt;/span&gt;
    &lt;span class="c1"&gt;# @return an integer&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;singleNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Time complexity: O(n)&lt;/p&gt;
&lt;h2 id="all-once-except-one"&gt;All Once Except One&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Given an array of N integers, which are in the scope of [1&amp;hellip;N - 1]. Every element in the array appears once except one. Find that number.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This one is simple enough. But it looks a &amp;ldquo;hard&amp;rdquo; problem because we can solve this by using the previously &amp;ldquo;xor&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s easy for us to calcuate the summary of the array [1&amp;hellip;N - 1], and easy enough to calculate the summay of the given array as well. And the answer is the diffrence of the two summary.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# @param A, a list of integer&lt;/span&gt;
    &lt;span class="c1"&gt;# @return an integer&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;singleInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Time complexity: O(n)&lt;/p&gt;
&lt;p&gt;p.s. &lt;code&gt;xor(A) ^ xor(range(n))&lt;/code&gt; is better if we have a large N that might overflow when we add all the elements.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given an array of integers, every element appears once except for one which appears twice. Find that special number.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This problem is harder because all numbers in the array is arbitrary. And it seems hard to find any rules and patterns in the array.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know there is an algorithm which is O(1) space and O(n) time complexity. Tackle it with a hash set may be the best solution, which takes O(n) space and O(n) time complexity.&lt;/p&gt;
&lt;h2 id="all-three-times-except-one"&gt;All three times except one&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Given an array of integers, every element appears three times except for one. Find that single one.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To slove &lt;a href="https://oj.leetcode.com/problems/single-number-ii/"&gt;this problem&lt;/a&gt;, just using an array of size 32 to keep track on the total count of the ith bit.&lt;/p&gt;
&lt;p&gt;And a tricky solution to reduce the memory usage is use three integers to indicate the remainder of 3 of the total count of the bits.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;singleNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;twos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;threes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;twos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;threes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;twos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;threes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;twos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;threes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="all-twice-except-two"&gt;All twice except two&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Given an array of integers, every element appears twice except for two. Find that two numbers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;xor(array) = 0 ^ a ^ b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="http://www.v2ex.com/t/94742"&gt;This problem&lt;/a&gt; is an update of &amp;ldquo;All twice except one&amp;rdquo;. It&amp;rsquo;s easy to prove that if there is an &amp;ldquo;1&amp;rdquo; in the bits of xor(array), it indicates that a and b are diffrent on that bit. We can separate the whole array by that bit, and then we can get two arrays which each contains a single &amp;ldquo;single number&amp;rdquo;.&lt;/p&gt;
&lt;h3 id="once-twice-three-times-a-lady"&gt;Once, twice, three times a lady&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Given an array of integers, some of the numbers appear once, and some appear twice, and the others appear three times. Please find the number which appear three times.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Of course, hash map is a panacea, with O(n) space and O(n) time.&lt;/p&gt;
&lt;p&gt;And there is another way to solve &lt;a href="http://www.ituring.com.cn/article/56179"&gt;this problem&lt;/a&gt; with O(1) space and O(n) time. But it has its limitation &amp;ndash; integer overflow. If the max number of this array is too large, it can&amp;rsquo;t be done.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;random&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;randint&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;

&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

&lt;span class="n"&gt;ns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;
    &lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;

&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;cnt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cnt&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Considering the number &lt;code&gt;ns[i]&lt;/code&gt; with the index &lt;code&gt;i&lt;/code&gt; and with the value &lt;code&gt;val&lt;/code&gt;. We make &lt;code&gt;ns[i] = count(i) * MAX + val&lt;/code&gt;. By that, we can get the count of number &lt;code&gt;i&lt;/code&gt; by &lt;code&gt;ns[i] / MAX&lt;/code&gt;, and get the value of &lt;code&gt;ns[i]&lt;/code&gt; by &lt;code&gt;ns[i] % MAX&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And it&amp;rsquo;s the same to find the &amp;ldquo;missing number of an array of [1 &amp;hellip; n]`` or something like that.&lt;/p&gt;
&lt;h2 id="summarize"&gt;Summarize&lt;/h2&gt;
&lt;h3 id="hash-map-is-panacea"&gt;Hash Map is PANACEA&lt;/h3&gt;
&lt;p&gt;Almost every problem on the array which want you to detect a single / two / or more &amp;ldquo;special&amp;rdquo; number can be tackled by the Hash Map. Easy and fast.&lt;/p&gt;
&lt;p&gt;But for almost every problem, a hash map may no the very &lt;strong&gt;BEST&lt;/strong&gt; solution.&lt;/p&gt;
&lt;h3 id="bit-map-takes-less-memory"&gt;Bit Map takes less memory&lt;/h3&gt;
&lt;p&gt;An update for the hash map is the bit map. It takes less memory, but can storage less infomation, 0 or 1. Further, you can treat several bits as one to put more information in it.&lt;/p&gt;
&lt;p&gt;By its very nature, bit map is the same with hash map.&lt;/p&gt;
&lt;h3 id="more-powerful-tool-bloomfilter"&gt;More powerful tool: Bloomfilter&lt;/h3&gt;
&lt;p&gt;Bloomfilter is a powerful algorithm / data structure which is used to slove the &amp;ldquo;in / not in&amp;rdquo; problem, and takes less memory than hash map, and can do better than bit map if the data is sparse and random.&lt;/p&gt;
&lt;p&gt;But it can&amp;rsquo;t keep way the &lt;strong&gt;randomizing error&lt;/strong&gt; called &lt;strong&gt;false positive&lt;/strong&gt;, and if you can put up with that error and want to reduce your memory usage, try that.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t mention this in my passage, but you can find some information on this &lt;a href="http://en.wikipedia.org/wiki/Bloom_filter"&gt;wikipedia page&lt;/a&gt;. It&amp;rsquo;s easy.&lt;/p&gt;
&lt;h3 id="xor-and-bits-manipulation"&gt;xor and bits manipulation&lt;/h3&gt;
&lt;p&gt;xor is a good way to solve the &amp;ldquo;only one appear once&amp;rdquo; problem. And xor manipulate will never cause overflow which will ruin your whole program.&lt;/p&gt;
&lt;h3 id="just-calculate-the-sum-of-the-array"&gt;just calculate the sum of the array&lt;/h3&gt;
&lt;p&gt;Somethimes we just forget the simplest way to deal with a &amp;ldquo;hard problem&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;For example, once I was asked &amp;ldquo;give you three integers (a, b, c), and calculate how many (x, y, z) is possible to make ax + by + cz == R&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m glad because it is so much like a &amp;ldquo;3-Sum&amp;rdquo; problem, and I solve it fast. But the interver told me it&amp;rsquo;s not the best solution. (You know how to deal with 3-sum, right?)&lt;/p&gt;
&lt;p&gt;I thought for a while, and give up at last. And the interver told me that the solution is to enumerate (x, y) and get z by this formula.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;z = (R - ax - by) / c
p.s. must be exact division
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It&amp;rsquo;s a better and much easier solution, right? It was a shame for me not came up with that idea.&lt;/p&gt;
&lt;p&gt;So, don&amp;rsquo;t forget the simple way, it may be the very best solution.&lt;/p&gt;
&lt;h3 id="attach-some-information-to-some-numbers"&gt;attach some information to some numbers&lt;/h3&gt;
&lt;p&gt;It useful if the length of the array (L) and the max value of the array (M). If M * L &amp;lt;= MAX_INT, you can storge the counter of number i in the array[i] by &lt;code&gt;array[i] = array[i] + counter * M&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a useful way to implement a counter in the array. And it will be a big plus for you in the interview.&lt;/p&gt;</content><category term="Blog"/><category term="算法"/><category term="leetcode"/><category term="algorithm"/></entry><entry><title>Codeforces 447D DZY Loves Modification</title><link href="https://wizmann.top/cf-447d.html" rel="alternate"/><published>2014-07-24T23:44:44+08:00</published><updated>2014-07-24T23:44:44+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-07-24:/cf-447d.html</id><summary type="html">&lt;h2 id="_1"&gt;题意&lt;/h2&gt;
&lt;p&gt;给你一个n * m的矩阵，让你做K次操作，使得最后得到的值最大。&lt;/p&gt;
&lt;p&gt;操作有两种：&lt;/p&gt;
&lt;p&gt;一是&lt;strong&gt;在任意一行上&lt;/strong&gt;操作，最终的结果值加上这一行数的 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;题意&lt;/h2&gt;
&lt;p&gt;给你一个n * m的矩阵，让你做K次操作，使得最后得到的值最大。&lt;/p&gt;
&lt;p&gt;操作有两种：&lt;/p&gt;
&lt;p&gt;一是&lt;strong&gt;在任意一行上&lt;/strong&gt;操作，最终的结果值加上这一行数的和，然后这一行每一个数都要减去p。&lt;/p&gt;
&lt;p&gt;二是&lt;strong&gt;在任意一列上&lt;/strong&gt;操作，最终的结果值加上这一列数的和，然后这一列每一个数都要减去p。&lt;/p&gt;
&lt;p&gt;数据范围：1 ≤ n, m ≤ 10^3; 1 ≤ k ≤ 10^6; 1 ≤ p ≤ 100&lt;/p&gt;
&lt;h2 id="_2"&gt;退化版的题目思路&lt;/h2&gt;
&lt;p&gt;如果我们只限定一种操作，此题就是简单题了。我们维护一个大根堆，堆中保存每一行（或列）之和。&lt;/p&gt;
&lt;p&gt;每次操作只需要取出最大值，加到最终结果上。之后将这个值减去对应的p * n（或p * m），再加入堆中。&lt;/p&gt;
&lt;p&gt;经过K次循环，就可以得到最后的答案了。&lt;/p&gt;
&lt;h2 id="_3"&gt;真正的题目思路&lt;/h2&gt;
&lt;p&gt;对于行和列同时操作，我们也可以套用这种方法。但是要解决对行操作后，对列上数字的值的影响。&lt;/p&gt;
&lt;p&gt;易得，如果行列混合操作，且只使用上述方法的话。每次行操作所得到的值，实际上为&lt;code&gt;简单行操作得到的值 - 此次行操作之前的所有列操作次数 * p&lt;/code&gt;(为什么？)。对于列操作亦然。&lt;/p&gt;
&lt;p&gt;假设我们有一个操作序列，&lt;code&gt;&amp;lt;a0, b0&amp;gt;&lt;/code&gt;代表序列的一段执行了a0个行操作和b0个列操作。如下图所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;a0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;|&lt;/span&gt;
&lt;span class="o"&gt;|&amp;lt;---&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;---&amp;gt;|&amp;lt;---&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="o"&gt;---&amp;gt;|&amp;lt;---&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;---&amp;gt;|&amp;lt;---&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="o"&gt;---&amp;gt;|&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;操作被分为了四个阶段。&lt;/p&gt;
&lt;p&gt;对于B阶段来说，其结果为&lt;code&gt;1次简单行操作的值 - b0 * p&lt;/code&gt;(为什么？)，对于C阶段来说，其结果为&lt;code&gt;1次简单列操作的值 - (a0 + 1) * p&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;那么，如果当我们把B阶段和C阶段互换的话， 结果是不变的。(为什么？我真TMD是十万个为什么。。。)&lt;/p&gt;
&lt;p&gt;所以我们可以得出，在任一个操作序列中，我们可以交换任意一个的行操作和列操作，而总结果不变。&lt;/p&gt;
&lt;p&gt;最终，我们可以将操作序列等价变化成下面的序列。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;lt;a, 0&amp;gt; | &amp;lt;0, b&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;此时，最终的结果为&lt;code&gt;a次简单行操作的值 + b次简单列操作的值 - a * b * p&lt;/code&gt;。(为什么？)&lt;/p&gt;
&lt;p&gt;而a与b的值可以简单的通过枚举得到。思路有了，代码如果不出大问题，这题就可以AC了。&lt;/p&gt;
&lt;h2 id="_4"&gt;代码&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;queue&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sumX&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sumY&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;do_calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;priority_queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;calcX&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;do_calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sumX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;calcY&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;do_calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sumY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;freopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;input.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;calcX&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;calcY&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;numeric_limits&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sumX&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sumY&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_5"&gt;后记&lt;/h2&gt;
&lt;p&gt;某厂的g++版本是3.4.x，没有C++11，&lt;strong&gt;根本秀不起来啊&lt;/strong&gt;！&lt;/p&gt;
&lt;p&gt;说的就和你会写C++11一样_(:з」∠)_&lt;/p&gt;</content><category term="Blog"/><category term="codeforces"/><category term="algorithm"/><category term="算法"/><category term="题解"/></entry><entry><title>CPU cache引发的性能血案</title><link href="https://wizmann.top/cpu-cache-miss.html" rel="alternate"/><published>2014-07-20T00:18:00+08:00</published><updated>2014-07-20T00:18:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-07-20:/cpu-cache-miss.html</id><summary type="html">&lt;p&gt;在__&lt;a href="http://evol128.is-programmer.com/posts/35453.html"&gt;为什么转置一个512x512的矩阵，会比513x513的矩阵慢很多？&lt;/a&gt;__一文中，作者引用了一个矩阵转置的例子，来讲解由于CPU cache的失效而带来的性能损失。&lt;/p&gt;
&lt;p&gt;上面的文章对问题的解释与讨论都 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;在__&lt;a href="http://evol128.is-programmer.com/posts/35453.html"&gt;为什么转置一个512x512的矩阵，会比513x513的矩阵慢很多？&lt;/a&gt;__一文中，作者引用了一个矩阵转置的例子，来讲解由于CPU cache的失效而带来的性能损失。&lt;/p&gt;
&lt;p&gt;上面的文章对问题的解释与讨论都非常的透彻。我的这篇文章只是对上面文章的一篇读后感和实验报告。就酱。&lt;/p&gt;
&lt;h2 id="cpu-cache"&gt;CPU cache 之 组相联&lt;/h2&gt;
&lt;p&gt;&lt;img alt="组相联" src="https://github.com/Wizmann/assets/raw/master/wizmann-tk-pic/blog-cpu-cache-2-way-set-assosiate.jpg"&gt;&lt;/p&gt;
&lt;p&gt;组相联的实现和原理不必再赘述了。我想讨论的是，如何在编程中优化CPU的cache性能。&lt;/p&gt;
&lt;h2 id="cpu"&gt;查看CPU信息&lt;/h2&gt;
&lt;p&gt;我的系统是Ubuntu 12.04，CPU是i5-3230M。（屌丝机 :D)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;wizmann&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;Wichmann&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;devices&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;cpu0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;index0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="nx"&gt;coherency_line_size&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;physical_line_partition&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;
&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;shared_cpu_list&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;
&lt;span class="nx"&gt;number_of_sets&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nx"&gt;shared_cpu_map&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;ways_of_associativity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;使用cat命令查看文件内容，可以获得CPU L1 cache的一些信息。&lt;/p&gt;
&lt;table class="table table-striped-white table-bordered"&gt;
&lt;thead&gt;
&lt;tr&gt;
 &lt;th&gt;Key&lt;/th&gt;
 &lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
 &lt;td&gt;level&lt;/td&gt;
 &lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
 &lt;td&gt;size&lt;/td&gt;
 &lt;td&gt;32K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
 &lt;td&gt;ways_of_associativity&lt;/td&gt;
 &lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
 &lt;td&gt;type&lt;/td&gt;
 &lt;td&gt;Data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
 &lt;td&gt;number_of_sets&lt;/td&gt;
 &lt;td&gt;64&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;以上可知，CPU L1 cache有64组，每组有8个cache line。是&lt;strong&gt;8位组相联&lt;/strong&gt;的Cache类型。&lt;/p&gt;
&lt;h2 id="_1"&gt;分析缓存失效率&lt;/h2&gt;
&lt;p&gt;对于以上问题，我们可以手工计算，也可以使用程序模拟Cache的失效率。&lt;/p&gt;
&lt;p&gt;同时，Valgrind为我们提供了cachegrind工具来分析cache的失效。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;wizmann&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Wichmann&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;valgrind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="k"&gt;tool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cachegrind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;D1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Cachegrind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;prediction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;profiler&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Copyright&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2002&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2011&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GNU&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GPL&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;d, by Nicholas Nethercote et al.&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Valgrind&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;3.7&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LibVEX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rerun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copyright&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;L3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;its&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;simulation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;Average&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;257&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1875&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;refs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;708&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;198&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I1&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;misses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LLi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;misses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;355&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I1&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;miss&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LLi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;miss&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;refs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;936&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;548&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;543&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;346&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;393&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;202&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;D1&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;misses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;107&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;687&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;086&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;263&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;424&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LLd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;misses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;502&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;179&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;323&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;D1&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;miss&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mf"&gt;12.3&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mf"&gt;23.9&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LLd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;miss&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;refs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;109&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;091&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;087&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;667&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;424&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;misses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;857&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;534&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;323&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;14282&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;miss&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;其中I1代表指令1级缓存，D1代表数据1级缓存，而LL代表二级或三级缓存。&lt;/p&gt;
&lt;p&gt;上面的输出也许过于复杂，我们在下面列表分析。&lt;/p&gt;
&lt;h3 id="_2"&gt;测试环境&lt;/h3&gt;
&lt;p&gt;只讨论L1的情况，L1大小32768 Bytes，2路组相联，每个cache line有16 Bytes。&lt;/p&gt;
&lt;p&gt;valgrind测试命令为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;wizmann&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Wichmann&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;valgrind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="k"&gt;tool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cachegrind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;D1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_3"&gt;测试程序&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#define SAMPLES 64&lt;/span&gt;
&lt;span class="cp"&gt;#define MATSIZE 256&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;time.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MATSIZE&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;MATSIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;transpose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MATSIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aux&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aux&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;//initialize matrix&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MATSIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MATSIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SAMPLES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="n"&gt;transpose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;elapsed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Average for a matrix of &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MATSIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;elapsed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SAMPLES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_4"&gt;测试结果&lt;/h3&gt;
&lt;table class="table table-striped-white table-bordered"&gt;
&lt;thead&gt;
&lt;tr&gt;
 &lt;th&gt;-&lt;/th&gt;
 &lt;th&gt;MATSIZE = 256&lt;/th&gt;
 &lt;th&gt;MATSIZE = 256 + 1&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
 &lt;td&gt;运行时间 (g++ O2) 1024次&lt;/td&gt;
 &lt;td&gt;78ms&lt;/td&gt;
 &lt;td&gt;39ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
 &lt;td&gt;D1 Miss&lt;/td&gt;
 &lt;td&gt;2,621,967&lt;/td&gt;
 &lt;td&gt;1,107,687&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
 &lt;td&gt;D1 Miss Rate&lt;/td&gt;
 &lt;td&gt;29.5%&lt;/td&gt;
 &lt;td&gt;12.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;由此可见，Cache的Miss Rate基本决定了程序的运行速度，运行时间比例和D1 MISS RATE的比例基本一致。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;注：本机环境与cachegrind参数是不一致的，在本机上由于cache较大，且采用8位组相联，所以D1 cache miss较少，差异主要体现在LLd Miss Rate上。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="_5"&gt;实际意义&lt;/h2&gt;
&lt;p&gt;如果程序对一段内存进行顺序读取的时候，以上的缓存失效问题有可能会显现出来。但是缓存失效只是程序性能问题的一个可能的原因，应该在对程序进行profile之后再做结论。&lt;/p&gt;
&lt;h2 id="profile"&gt;其它profile工具&lt;/h2&gt;
&lt;p&gt;我的提问：__&lt;a href="http://www.zhihu.com/question/24540567/noti-answers?group_id=564624072"&gt;有没有什么方法可以对CPU cache失效进行计数？&lt;/a&gt;__中，各位答主还提供了以下几种工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;perf (linux)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://tiptop.gforge.inria.fr/"&gt;Tiptop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;qemu&lt;/li&gt;
&lt;li&gt;visual studio的cpu counter&lt;/li&gt;
&lt;li&gt;intel performance counter monitor&lt;/li&gt;
&lt;li&gt;vtunes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;profile的方法很多，选一个易用性与正确性达到平衡就可以。反正我是哪个也不会_(:з」∠)_&lt;/p&gt;
&lt;h2 id="_6"&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://yoursunny.com/study/EI209/?topic=cache"&gt;cache映射功能、命中率计算&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.focus-linux.net/?p=391"&gt;使用valgrind检查cache命中率，提高程序性能&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://valgrind.org/docs/manual/cg-manual.html"&gt;Cachegrind: a cache and branch-prediction profiler&lt;/a&gt; （官方文档）&lt;/li&gt;
&lt;li&gt;&lt;a href="https://access.redhat.com/documentation/zh-CN/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/ch05s03s02.html"&gt;使用 Cachegrind 简要概述缓存使用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://wwwcdf.pd.infn.it/valgrind/cg_main.html"&gt;Cachegrind: a cache-miss profiler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.ibm.com/developerworks/cn/linux/l-cn-perf"&gt;Perf &amp;ndash; Linux下的系统性能调优工具，第 1 部分&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://coolshell.cn/articles/10249.html"&gt;7个示例科普CPU Cache（扩展阅读）&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="cpu"/><category term="cache"/><category term="profile"/><category term="valgrind"/><category term="cachegrind"/></entry><entry><title>Codeforces Round #253 Tutorial</title><link href="https://wizmann.top/cf-253.html" rel="alternate"/><published>2014-06-21T19:24:37+08:00</published><updated>2014-06-21T19:24:37+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-06-21:/cf-253.html</id><summary type="html">&lt;hr&gt;
&lt;h2 id="443a-anton-and-letters"&gt;443A - Anton and Letters&lt;/h2&gt;
&lt;p&gt;Simple and easy, solved by two lines of python code.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="443b-kolya-and-tandem-repeat"&gt;443B - Kolya and Tandem Repeat&lt;/h2&gt;
&lt;p&gt;Brute force. Just enumerate the beginning and the end of the substring, and …&lt;/p&gt;</summary><content type="html">&lt;hr&gt;
&lt;h2 id="443a-anton-and-letters"&gt;443A - Anton and Letters&lt;/h2&gt;
&lt;p&gt;Simple and easy, solved by two lines of python code.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="443b-kolya-and-tandem-repeat"&gt;443B - Kolya and Tandem Repeat&lt;/h2&gt;
&lt;p&gt;Brute force. Just enumerate the beginning and the end of the substring, and check if that substring is &lt;strong&gt;tandem repeat&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;freopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;input.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="cm"&gt;/* pass */&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;goto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nl"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="cm"&gt;/*pass*/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="442a-borya-and-hanabig"&gt;442A - Borya and Hanabig&lt;/h2&gt;
&lt;p&gt;Because Borya knows about the color and value of all his cards, he just need to distinguish each card from the others. &lt;/p&gt;
&lt;p&gt;Distinguish one card from all others seems difficult, but distinguish one card from &lt;em&gt;ONE&lt;/em&gt; other card is simple enough. So if we can tell the difference between one card and any other, it can be determined from all pairs which contain this card. At last, if all pairs of cards can be distinguished, we can claim that we can distinguish all cards.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s easy to find out that we have 10 different kind of hints in total(5 colors and 5 values) and 1024 different combination of all that hints(1 &amp;lt;&amp;lt; 10). As a result, we can enumerate all combinations, and try to indicate whether this batch of hints can distinguish all these cards.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cassert&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;map&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;set&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_str&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;12345RGBYW&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;conv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;freopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;input.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;conv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;conv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// print(a &amp;lt;&amp;lt; &amp;#39; &amp;#39; &amp;lt;&amp;lt; b &amp;lt;&amp;lt; &amp;#39; &amp;#39; &amp;lt;&amp;lt; v);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;goto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__builtin_popcount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nl"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="cm"&gt;/*pass*/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="442b-andrey-and-problem"&gt;442B - Andrey and Problem&lt;/h2&gt;
&lt;p&gt;Assuming that the possibility of getting exactly one problem from some of Andrey&amp;rsquo;s friends is &lt;code&gt;p1&lt;/code&gt; and get no problem is &lt;code&gt;p0&lt;/code&gt;. So, if we want to add one friend whose possibility of comming up a problem is &lt;code&gt;pa&lt;/code&gt; to this very friend set, we can get &lt;code&gt;next_p1 = p1 * (1 - pa) + p0 * pa&lt;/code&gt; and &lt;code&gt;next_p0 = p0 * (1 - pa)&lt;/code&gt;. And it easy to indicate that a greater &lt;code&gt;pa&lt;/code&gt; will lead to a greater &lt;code&gt;next_p1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The initial value is that &lt;code&gt;p0 == 1; p1 == 0&lt;/code&gt;. And we add the friends one by one ordered by the possibilites reversely. At last, the max &lt;code&gt;p1&lt;/code&gt; is the final result.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;ps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;good&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;bad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;good&lt;/span&gt;

&lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;good&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
    &lt;span class="n"&gt;good&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;good&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bad&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;good&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="codeforces"/><category term="algorithm"/></entry><entry><title>A simple problem - World at War</title><link href="https://wizmann.top/world-at-war.html" rel="alternate"/><published>2014-06-12T17:42:51+08:00</published><updated>2014-06-12T17:42:51+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-06-12:/world-at-war.html</id><summary type="html">&lt;h2 id="background"&gt;Background&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;This problem is from the book &amp;ldquo;&lt;a href="http://book.douban.com/subject/19952400/"&gt;Algorithm 4th edition&lt;/a&gt;&amp;rdquo; (Exersise 4.1.10)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are N cities and M undirected roads between those cities. People can travel to any city along the roads.&lt;/p&gt;
&lt;p&gt;One day, a war breaks out. Our cities are under attack! As we can&amp;rsquo;t defend …&lt;/p&gt;</summary><content type="html">&lt;h2 id="background"&gt;Background&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;This problem is from the book &amp;ldquo;&lt;a href="http://book.douban.com/subject/19952400/"&gt;Algorithm 4th edition&lt;/a&gt;&amp;rdquo; (Exersise 4.1.10)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are N cities and M undirected roads between those cities. People can travel to any city along the roads.&lt;/p&gt;
&lt;p&gt;One day, a war breaks out. Our cities are under attack! As we can&amp;rsquo;t defend all these N cities, the commander wants you to find the least important city, which means that if this city fell to the enemy, the traffic among other cities would not be affected.&lt;/p&gt;
&lt;p&gt;If there are multiple answers, print any one of them. If there&amp;rsquo;s no that kind of city, print -1.&lt;/p&gt;
&lt;p&gt;&lt;img alt="world-at-war" src="https://github.com/Wizmann/assets/raw/master/wizmann-tk-pic/blog-world-at-war.png"&gt;&lt;/p&gt;
&lt;h2 id="the-spanning-tree-of-a-graph"&gt;The spanning tree of a graph&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;It is a spanning tree of a graph G if it spans G (that is, it includes every vertex of G) and is a subgraph of G (every edge in the tree belongs to G). &lt;br&gt;
&amp;ndash; wikipedia&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="spanning-tree" src="https://github.com/Wizmann/assets/raw/master/wizmann-tk-pic/blog-spanning-tree.png"&gt;&lt;/p&gt;
&lt;p&gt;For example, there is a spanning tree of a graph. These nodes in green is leaf node. So it is easy to know that if we remove a leaf node, the graph won&amp;rsquo;t be affect. The rest of the graph (and the spanning tree) are still connected.&lt;/p&gt;
&lt;p&gt;So the answer is here.&lt;/p&gt;
&lt;h2 id="how-to-generate-a-spanning-tree"&gt;How to generate a spanning tree&lt;/h2&gt;
&lt;p&gt;There are multiple ways to generate a spanning three of a undirected graph. The most famous algorithm is &lt;strong&gt;prim&lt;/strong&gt;, which will generate a MST(minimum spanning tree) with O(n**2) time complexity.&lt;/p&gt;
&lt;p&gt;However, MST is not needed in this scenario, because an arbitrary spanning tree is enough to find one of the leaf nodes.&lt;/p&gt;
&lt;p&gt;Depth first search (a.k.a DFS) is one of the simplest way to generate the spanning tree. We just start from arbitrary node of the graph, and search through the graph until it comes to a dead-end &amp;ndash; the leaf node. Then print the answer.&lt;/p&gt;
&lt;p&gt;Problem solved.&lt;/p&gt;
&lt;h2 id="show-me-the-code"&gt;Show me the code&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;least_important_city&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="algorithm"/><category term="interview"/><category term="graph"/></entry><entry><title>内存屏障初探</title><link href="https://wizmann.top/read-paper-barrier.html" rel="alternate"/><published>2014-05-08T19:05:26+08:00</published><updated>2014-05-08T19:05:26+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-05-08:/read-paper-barrier.html</id><summary type="html">&lt;h2 id="_1"&gt;原文地址&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://ridiculousfish.com/blog/posts/barrier.html"&gt;Barrier February 17th, 2007&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="_2"&gt;前言：多核时代的挑战&lt;/h2&gt;
&lt;p&gt;尽管80核心的浮点运算巨兽仍然遥不可及，多核处理器的时代已经到来。多核处理器的概念并非新鲜事物，在Power Macintosh 9500中就已经采用了多核处理器技术 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;原文地址&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://ridiculousfish.com/blog/posts/barrier.html"&gt;Barrier February 17th, 2007&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="_2"&gt;前言：多核时代的挑战&lt;/h2&gt;
&lt;p&gt;尽管80核心的浮点运算巨兽仍然遥不可及，多核处理器的时代已经到来。多核处理器的概念并非新鲜事物，在Power Macintosh 9500中就已经采用了多核处理器技术。现在，让我们深入理解多核处理器的内在机制。&lt;/p&gt;
&lt;h2 id="_3"&gt;线程技术探讨&lt;/h2&gt;
&lt;h3 id="_4"&gt;名词解释&lt;/h3&gt;
&lt;h4 id="_5"&gt;线程&lt;/h4&gt;
&lt;p&gt;线程是一种拥有共享地址空间的、能被抢占式调度的执行上下文。&lt;/p&gt;
&lt;h4 id="_6"&gt;多线程&lt;/h4&gt;
&lt;p&gt;多线程是一种用于简化控制流、绕过阻塞系统调用的方法，并不专门用于实现程序的并行化。&lt;/p&gt;
&lt;h4 id="_7"&gt;并发多线程&lt;/h4&gt;
&lt;p&gt;物理上并行执行的线程，旨在通过利用多核处理器优化系统性能。&lt;/p&gt;
&lt;h3 id="_8"&gt;“并发多线程”的挑战&lt;/h3&gt;
&lt;p&gt;尽管并发多线程被广泛讨论，其挑战并非源自自然原因，而是我们自己的设计选择所造成的。主要问题在于，针对单线程程序的过度优化在多线程环境中不再适用。&lt;/p&gt;
&lt;p&gt;具体来说，由于CPU的执行速度远超内存响应速度，我们开始对内存内容进行“预测”，从而避免CPU等待内存检查。这里的“预测”实际上是CPU和编译器对内存状态做出的越来越激进的假设。&lt;/p&gt;
&lt;h2 id="_9"&gt;示例分析&lt;/h2&gt;
&lt;h3 id="_10"&gt;写线程示例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// 初始时 variable1 = variable2 = 0;&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;variable2&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_11"&gt;读线程示例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;local2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;local1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;local1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;正常逻辑下，local2 应当始终小于或等于 local1，因为 variable1 总是在 variable2 之后增加。&lt;/p&gt;
&lt;p&gt;然而，现实是否如此？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;ctime&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;pthread.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;sys/time.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;#define ITERATIONS 200000000&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;unused&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(;;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;variable2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;unused&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;timeval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;gettimeofday&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failureCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ITERATIONS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failureCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;gettimeofday&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tv_sec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tv_usec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1000000.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tv_sec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tv_usec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1000000.&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%u failure%s (%2.1f percent of the time) in %2.1f seconds&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="n"&gt;failureCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failureCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;100.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failureCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ITERATIONS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;pthread_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;thread2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;pthread_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;thread1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;pthread_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;thread2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(;;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;输出结果：&lt;code&gt;0 failures (0.0 percent of the time) in 1.2 seconds&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="_12"&gt;貌似是正确的？&lt;/h3&gt;
&lt;p&gt;程序运行的正如我们预期的那样，那么我们可以确信程序是一定正确的吗？&lt;/p&gt;
&lt;p&gt;不能。&lt;/p&gt;
&lt;p&gt;因为程序中的两个线程如果在同一个CPU上被调度，我们永远都会得到正确的结果。&lt;/p&gt;
&lt;h3 id="cpu"&gt;线程与不同的CPU进行绑定&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;unused&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;cpu_set_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpuset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CPU_ZERO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cpuset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CPU_SET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cpuset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sched_setaffinity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cpuset&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cpuset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;unused&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;cpu_set_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpuset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CPU_ZERO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cpuset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CPU_SET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cpuset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sched_setaffinity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cpuset&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cpuset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// p.s. 我机器是i5双核四线程，所以绑在了CPU0和CPU2上&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;结果：&lt;code&gt;0 failures (0.0 percent of the time) in 1.4 seconds&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="_13"&gt;似乎仍然是准确的&lt;/h3&gt;
&lt;p&gt;尽管如此，我们考虑到CPU对变量的操作其实是作用在寄存器上，而variable1和variable2紧密相邻，这可能导致它们位于缓存的同一行。因此，它们有可能会同时被写入缓存并一起写回内存。&lt;/p&gt;
&lt;p&gt;为了观察不同的效果，我们尝试将这两个变量分别放置在堆和栈上。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;percent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;
&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;percent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;
&lt;span class="mf"&gt;2000000000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;percent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;太感人了！&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="_14"&gt;我们的敌人 —— 编译器&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Multithreading bugs are very delicate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;并行多线程的错误总是那么的奇妙，也许你的程序运行了几天安然无恙，但是在某一天某一时突然出现了难以复现的精妙bug。&lt;/p&gt;
&lt;p&gt;如果多个线程调度在同一个CPU核心上，Bug会被掩盖。  &lt;br&gt;
如果多个变量在CPU同一行Cache上，Bug会被掩盖。  &lt;br&gt;
如果你人品足够好的话，Bug同样会被掩盖。&lt;/p&gt;
&lt;p&gt;但是，如果我们排除了以上的情况后，问题就浮现出来了。&lt;/p&gt;
&lt;p&gt;我们来看一看reader的反汇编代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gdb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;disas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;
&lt;span class="n"&gt;Dump&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;assembler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400950&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rbx&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400951&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;eax&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400953&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ecx&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400958&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;esi&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x000000000040095d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ebx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ebx&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x000000000040095f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0xa0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400966&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rdi&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400969&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rdx&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x000000000040096c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;rep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;es&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rdi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x000000000040096f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;edi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;edi&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400971&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;movq&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;$0x4&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400979&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;callq&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mh"&gt;0x400790&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;sched_setaffinity&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x000000000040097e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;lea&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rdi&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400986&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;esi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;esi&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400988&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;callq&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mh"&gt;0x400710&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;gettimeofday&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x000000000040098d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;0x2006e4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x601078&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;variable2_p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400994&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;0x2006e6&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;edx&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x601080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x000000000040099a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;74&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ecx&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x000000000040099c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;76&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x77359400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;eax&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009a1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;nopl&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009a8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ecx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;edx&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009aa&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;adc&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ebx&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009ad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;93&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;eax&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009b0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;96&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;jne&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;0x4009a8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009b2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;lea&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;0x90&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rdi&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009ba&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;106&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;esi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;esi&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009bc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;108&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;callq&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mh"&gt;0x400710&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;gettimeofday&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;113&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;cvtsi2sdq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x98&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm0&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009cb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;cvtsi2sdq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x90&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm1&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009d5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;133&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;movsd&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mh"&gt;0x1a3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm3&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x400b80&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009dd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;141&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ebx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;eax&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009df&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;143&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;cvtsi2sdq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x88&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm2&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009e9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;153&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ebx&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009ec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;156&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x400b3d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ecx&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009f1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;161&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;edi&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009f6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;166&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;divsd&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm0&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009fa&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;170&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ebx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;edx&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x00000000004009fc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;172&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x400b40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;esi&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a01&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;177&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;divsd&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm2&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a05&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;181&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;addsd&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm1&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a09&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;185&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;cvtsi2sdq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm0&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;195&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;subsd&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm1&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;199&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;cvtsi2sd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm0&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a1c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x400b3c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;eax&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;209&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;cmovne&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rcx&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a25&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;213&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;eax&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a2a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;218&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;mulsd&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mh"&gt;0x156&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm0&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x400b88&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;226&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;subsd&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm1&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a36&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;230&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;divsd&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mh"&gt;0x152&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;xmm0&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x400b90&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a3e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;238&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;callq&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mh"&gt;0x400700&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;__printf_chk&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a43&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;243&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;xor&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;edi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;edi&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0000000000400a45&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;245&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;callq&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mh"&gt;0x4006f0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;简而言之，关键在以下几句：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mh"&gt;0x000000000040098d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;0x2006e4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x601078&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;variable2_p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="mh"&gt;0x0000000000400994&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;0x2006e6&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;edx&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x601080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="mh"&gt;0x000000000040099a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;74&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ecx&lt;/span&gt;
&lt;span class="mh"&gt;0x000000000040099c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;76&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x77359400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;eax&lt;/span&gt;
&lt;span class="mh"&gt;0x00000000004009a1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;nopl&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mh"&gt;0x0&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mh"&gt;0x00000000004009a8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ecx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;edx&lt;/span&gt;
&lt;span class="mh"&gt;0x00000000004009aa&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;adc&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ebx&lt;/span&gt;
&lt;span class="mh"&gt;0x00000000004009ad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;93&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;$0x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;eax&lt;/span&gt;
&lt;span class="mh"&gt;0x00000000004009b0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;+&lt;/span&gt;&lt;span class="mi"&gt;96&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;jne&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mh"&gt;0x4009a8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;我们可以看出，循环体在+88～+96行，而对variable1与variable2的取值都放在了循环以外。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注： &lt;br&gt;
adc是带进位加法，adc $0x0, %ebx =&amp;gt; %ebx = $0x0 + %ebx + CF  &lt;br&gt;
cmp的结果正是放在CF（大于表示为溢出），ZF（相等表示为0），PF（小于表示为-1,则低8位全为1,故有偶数个1）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;正是这个“小意外”，导致了我们的结果要不是100%正确，要不是100%错误。&lt;/p&gt;
&lt;h4 id="volitile"&gt;使用volitile（？）&lt;/h4&gt;
&lt;p&gt;让我们修改一下代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;variable2_p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;#define ITERATIONS 500000000LL &lt;/span&gt;&lt;span class="c1"&gt;// 调小一下数据规模，因为volatile太慢了_(:з」∠)_&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;我得出的来的结果是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;percent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;9.6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;而作者得出的结果是：&lt;br&gt;
（时间上的差异不计，因为我们的数据规模不一样，我实验的次数要多一些。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;fish ) ./a.out
12462711 failures (24.9 percent of the time) in 3.7 seconds
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;从作者的结果来看，看起来效果好了很多，虽然慢了30多倍，但是结果并不是全对全错了。&lt;/p&gt;
&lt;p&gt;而从我的结果来看，volatile看似神丹妙药，解决了所有的问题。(both g++ and clang++)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这是为什么呢?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;其原因在于体系结构的差异。volatile只能保证如下两点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;volatile变量的访问不会优化成寄存器访问，而是每次都去访问“内存”（这个引号一会再解释）&lt;/li&gt;
&lt;li&gt;volatile变量间的访问顺序不会被编译器乱序&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而其他的一切，volatile和编译器都不会给出任何保证。&lt;/p&gt;
&lt;p&gt;例如，不同的CPU都有其内部的私有Cache，CPU的内存访问，如果命中了Cache，则不会真正的访问内存。但由于其私有Cache对于其它的CPU是不可见的，使用volatile就埋下的Bug的种子。&lt;/p&gt;
&lt;p&gt;虽然在我们的实验中，程序运行的很好，没有出现Bug。但是，一是由于多线程的Bug都是subtle和delicate的，我不能保证在一个需要7x24工作的服务器程序中，它不会出现任何Bug；二是至少我们的代码是&lt;strong&gt; not portable &lt;/strong&gt;的，如果有一天，我们从x86-64平台切换到了&lt;code&gt;PowerPC&lt;/code&gt;？或是&lt;code&gt;IA64&lt;/code&gt;？我们不能保证在这些体系结构上，编译器和CPU能为我们提供同样的保障。&lt;/p&gt;
&lt;p&gt;于是有人高声疾呼： volatile不能用来做为多线程的同步机制！&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;补充于20240317：在一台老旧的安卓手机上重复了实验，volatile确实无法提供相关的保障&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;~/tmp $ clang++ -O2 a.cc &amp;amp;&amp;amp; ./a.out
99880586 failures (49.9 percent of the time) in 3.0 seconds
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="cpu_1"&gt;小心CPU的行为&lt;/h4&gt;
&lt;p&gt;在先前的实验中，尽管程序的表现与预期一致，但我们无法确保CPU将始终按顺序执行代码。实际上，CPU可能会对操作顺序进行优化，例如，将var1++和var2++的执行顺序调换，这在当前主流的CPU中是常见的做法。&lt;/p&gt;
&lt;p&gt;值得注意的是，由于乱序执行会导致功耗增加，某些处理器如ARM和Intel Atom已经取消了这一机制。然而，我们无法预知未来代码可能会在哪种硬件架构上运行，例如ARM集群，这需要我们保持警惕。&lt;/p&gt;
&lt;h4 id="_15"&gt;避免使用锁&lt;/h4&gt;
&lt;p&gt;通常情况下，通过引入互斥锁（mutex）似乎能够解决并发问题。然而，根据作者的测试，引入互斥锁可能会导致程序速度降低至原来的1/130，而自旋锁（spinlock）也可能使得速度降低至原来的1/4。&lt;/p&gt;
&lt;p&gt;因此，我们应该暂缓，仔细考虑作者接下来的建议。&lt;/p&gt;
&lt;h3 id="_16"&gt;内存屏障的应用&lt;/h3&gt;
&lt;p&gt;在多CPU环境中，处理器往往独立运行，不会协调彼此的操作。&lt;/p&gt;
&lt;p&gt;目前，我们面临两个并不理想的解决方案：一是将所有线程限制在单个CPU上运行，二是通过引入重量级锁来同步操作。这些方法都不尽人意，且效率低下。&lt;/p&gt;
&lt;p&gt;实际上，我们需要做的是，通过内存屏障技术，暂时阻止编译器或CPU对程序中的数据读写操作进行重排序。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(;;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;barrier&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;variable2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;variable2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这样我们保证了，在var1++必然早于var2++。var2++后面也可以加一道barrier，只不过在我们的场景下，提供这种保证是不必须的。&lt;/p&gt;
&lt;p&gt;作者又做了一次试验。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;fish ) ./a.out
260 failures (0.0 percent of the time) in 0.9 seconds
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这次且错误减少了许多。&lt;/p&gt;
&lt;p&gt;我们再把读线程写加上memory barrier.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ITERATIONS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;variable2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;barrier&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variable1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failureCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;看看结果：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;fish ) ./a.out
0 failures (0.0 percent of the time) in 4.2 seconds
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;程序表现出了正确的结果。&lt;/p&gt;
&lt;p&gt;我们可以看出，如果你对线程A的读写顺序做出要求，必然的，你也要对线程B的顺序做要求，以此类推，线程C，线程D……&lt;/p&gt;
&lt;p&gt;所以，&lt;strong&gt;Memory barriers always come in pairs, or triplets or more.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;同样的，线程锁也是这样的，自己锁自己总不是一种愉快的体验（笑&lt;/p&gt;
&lt;h3 id="cpu_2"&gt;CPU的乱序执行&lt;/h3&gt;
&lt;p&gt;我们可以看到PowerPC有三种内存屏障，而DEC Alpha平台有更多。这意味着，CPU使用更激进的策略来重排指令，而强制限制其重排的代价是非常高的。&lt;/p&gt;
&lt;p&gt;而x86平台则非常守序，作者猜测其原因是由于早期x86的指令技术并非完善，而在那时内存与CPU的速度不像现在这样悬殊，所以x86使用了&lt;code&gt;strongly ordered memory&lt;/code&gt;而非像上面几款CPU一样的采用过多的指令重排序。如今，由于x86背上了向前兼容性的包袱，看似我们的&amp;rdquo;好日子&amp;rdquo;一直不会结束。&lt;/p&gt;
&lt;p&gt;x86-64，做为x86的64位升级版，同样没有实现&lt;code&gt;weakly ordered&lt;/code&gt;，或者说，保留了实现&lt;code&gt;weakly ordered&lt;/code&gt;的权利。而&lt;code&gt;IA64&lt;/code&gt;平台，如&lt;code&gt;Itanium&lt;/code&gt;，则实现了&lt;code&gt;weakly ordered&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;作者猜测x86_64之所以保守，是为了与IA64平台对抗。x86_64的对于x86良好的兼容性可以让程序员多活几年，所以x86_64在市场的表现更好。&lt;/p&gt;
&lt;p&gt;作者还表示，而苹果放弃IA64平台转投x86-64多少有一些可惜，因为苹果并没有移植性问题，PowerPC已经逐渐衰落，为什么不试试IA64呢。&lt;/p&gt;
&lt;p&gt;实际上，根据Wikipedia，现在支持IA64的操作系统非常少，只有WinNT Family，Red Hat Linux，Debian/Gentoo/Suse以及其它。而从Windows Server 2008 R2之后，Microsoft也表示不再支持Itanium。所以从现在看来，IA64平台相对x86/x64来说，是失败的。&lt;/p&gt;
&lt;h3 id="_17"&gt;双重检查锁&lt;/h3&gt;
&lt;p&gt;让我们看一下如下的Obj-C代码&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;getSharedObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;LOCK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;UNLOCK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这是非常经典的一种DCLP(Double Checked Lock Pattern)的实现。&lt;/p&gt;
&lt;p&gt;这个看起来不错，但是你已经知道这并不靠谱了。当我们初始化我们的共享单例，先要再修改类内的指针，使其指向一块声明好的内存，再初始化一个sharedObject的instance。&lt;/p&gt;
&lt;p&gt;不过，你是知道的，CPU和编译器会把一切都搞砸，它们会以任意的顺序执行我们的命令，同时处理器之间互相不通气，于是就会出现如下的情况：&lt;/p&gt;
&lt;p&gt;线程A为指针声明了一段空间，但是还没来及初始化这个instance，线程A就被挂起了。&lt;/p&gt;
&lt;p&gt;之后线程B接管一切，发现指针有值，结果因为访问了野指针导致程序挂掉。&lt;/p&gt;
&lt;p&gt;不过根据上面的文章，你们应该知道怎么处理这个问题了 —— 试试内存屏障！&lt;/p&gt;
&lt;p&gt;p.s. 如果大家对obj-c不熟悉的话，可以看我另外一篇文章。那篇文章是关于Scott Meyers大神写的一篇论文，专门用来讨论DCLP问题的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;getSharedObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;LOCK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;OSMemoryBarrier&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;UNLOCK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;OSMemoryBarrier&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;而在《C++ and the Perils of Double-Checked Locking》一文中，Scott Meyers和Andrei Alexandrescu给出的解决方案如下。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Singleton&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Singleton::instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Singleton&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pInstance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// insert memory barrier&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// clear the cache to flush ``pInstance``&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// prevents &amp;quot;downwards migration&amp;quot; of Singleton’s construction (by another thread);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pInstance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Singleton&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// insert memory barrier&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// prevent optimistic that eliminate the temporary variable ``tmp``&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// prevents &amp;quot;upwards migration&amp;quot; of pInstance’s initialization&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;pInstance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;两种解决方案的memory barrier插入的位置不同。但是都不能说是错的。因为一个是传static instance，一个是传pointer。&lt;/p&gt;
&lt;p&gt;其实还有更“暴力”的方法。&lt;/p&gt;
&lt;p&gt;直接来一把大锁，哐当把整个函数锁起来，并且在每一个线程内保留一个&lt;strong&gt;本线程专属&lt;/strong&gt;指向单例的指针（做cache）。这样N个线程只需要调用这个函数N次，线程竞争也相对少很多。并且根据Linux下的futex技术，无竞争下的锁相对节省了不少资源。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Singleton&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Singleton::instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pInstance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;pInstance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Singleton&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pInstance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_18"&gt;我们真的需要这么做吗&lt;/h3&gt;
&lt;p&gt;上面的obj-c代码中，保证双重检查锁正确的，其实是第二个内存屏障。但是，在那里，我们需要的其实是一个&amp;rdquo;data dependency barrier&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;Linux内核中给出很多经过精心优化的内存屏障，我们在这里可以使用。不过，要在使用的时候写好注释，一是为了未来的验证，二是为了记录自己当时的思路。&lt;/p&gt;
&lt;p&gt;毕竟多线程的操作要小心再小心，我们需要充足的理由，更多的小心来应对。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;getSharedObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;LOCK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;OSMemoryBarrier&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;UNLOCK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* data dependency memory barrier here */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sharedObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="_19"&gt;一切都结束了吗？&lt;/h3&gt;
&lt;p&gt;是的。不过让我们总结一下吧。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Mutex Tank" src="https://github.com/Wizmann/assets/raw/master/wizmann-tk-pic/barrier_tank.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;处理器和编译器并不能充分保证代码执行的顺序，它们会把你的代码到处移动。所以&lt;strong&gt;Be warned and wary!&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;多线程的错误是非常subtle和delicate的，所以我们很难设计测试用例&lt;/li&gt;
&lt;li&gt;因此，别指责QA了，他们也不是故意的。RD要对自己的代码负责&lt;/li&gt;
&lt;li&gt;锁很安全，但是也很重&lt;/li&gt;
&lt;li&gt;内存屏障是一种更快的，不阻塞的，不会死锁的一种锁的替代物。它们总要花费更多的心思，并且也不是到处可用的银弹。但是它确实很快，有更好的伸缩性。&lt;/li&gt;
&lt;li&gt;内存屏障往往是成对出现的。了解第二个内存屏障要出现在哪里，有助于你理解你的代码，即使你所使用的体系结构不需要第二个内存屏障。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="_20"&gt;扩展阅读&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.kernel.org/doc/Documentation/memory-barriers.txt"&gt;LINUX KERNEL MEMORY BARRIERS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.17.8112"&gt;Memory Consistency and Event Ordering in Scalable Shared-Memory Multiprocessors&lt;/a&gt;&lt;/p&gt;</content><category term="Blog"/><category term="cpp"/><category term="memory-barrier"/><category term="asm"/><category term="multiprocess"/><category term="multithread"/><category term="thread"/><category term="cocurrency"/></entry><entry><title>Codeforces Round #242 (Div. 2) Tutorials and Solutions</title><link href="https://wizmann.top/cf-242-div-2.html" rel="alternate"/><published>2014-04-30T17:39:00+08:00</published><updated>2014-04-30T17:39:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-04-30:/cf-242-div-2.html</id><summary type="html">&lt;h2 id="a-squats"&gt;A. Squats&lt;/h2&gt;
&lt;p&gt;Trun &lt;code&gt;x =&amp;gt; X&lt;/code&gt; or &lt;code&gt;X =&amp;gt; x&lt;/code&gt; to make the number of &amp;lsquo;x&amp;rsquo; is equal to the number of &amp;lsquo;X&amp;rsquo;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;hamsters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;

&lt;span class="n"&gt;sits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hamsters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;stands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hamsters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;X&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sits&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;stands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hamsters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sits&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;stands …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;h2 id="a-squats"&gt;A. Squats&lt;/h2&gt;
&lt;p&gt;Trun &lt;code&gt;x =&amp;gt; X&lt;/code&gt; or &lt;code&gt;X =&amp;gt; x&lt;/code&gt; to make the number of &amp;lsquo;x&amp;rsquo; is equal to the number of &amp;lsquo;X&amp;rsquo;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;hamsters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;

&lt;span class="n"&gt;sits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hamsters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;stands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hamsters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;X&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sits&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;stands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hamsters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sits&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;stands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sits&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stands&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;X&amp;#39;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hamsters&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;hamsters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swapcase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hamsters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="b-megacity"&gt;B. Megacity&lt;/h2&gt;
&lt;p&gt;Binary search.&lt;/p&gt;
&lt;p&gt;Find the minimal radius of the circle to contain as many city as we need to form a &lt;strong&gt;megacity&lt;/strong&gt;. But beware that you may get wrong answer if you take the lower bound of the binary search, and the answer may not exist if there no way to make a &lt;strong&gt;megacity&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;math&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; 
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;megacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
    &lt;span class="n"&gt;rem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;rem&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rem&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;

&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;cities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;cities&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2e6&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;1e-7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;2.&lt;/span&gt;
    &lt;span class="c1"&gt;#print mid&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;megacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;megacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="c-magic-formulas"&gt;C. Magic Formulas&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Magic Formula" src="https://github.com/Wizmann/assets/raw/master/wizmann-tk-pic/Magic-Formula.png"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1...n&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;for j in 1...n&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1...n&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;First of all, we can easily get the value of &lt;code&gt;U&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Secondly, as &lt;code&gt;n&lt;/code&gt; is up to &lt;code&gt;1e6&lt;/code&gt;. We have to reduce the calculation and the method will shown by code.&lt;/p&gt;
&lt;p&gt;At last, we xor them all together to get the final result.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000010&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xorsum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;xorsum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;xorsum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xorsum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xorsum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="d-biathlon-track"&gt;D. Biathlon Track&lt;/h2&gt;
&lt;p&gt;Binary search again.&lt;/p&gt;
&lt;p&gt;I calculate the wrong time complexity and get many &lt;code&gt;TLE&lt;/code&gt;s using brute force algorithm.&lt;/p&gt;
&lt;p&gt;The idea is to fix the left-up point A, &lt;code&gt;(ax, ay)&lt;/code&gt;, and fix the y-axis of the right-buttom point B, &lt;code&gt;(bx, by)&lt;/code&gt;. And then, using binary search to get the x-axis of the B to get the nearest cost (aka &amp;ldquo;distance covering time&amp;rdquo;) to the desired time &lt;code&gt;t&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The time complexity is &lt;code&gt;O(logn * n^3)&lt;/code&gt;. A bad ass code is below.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DIRS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;NORTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SOUTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WEST&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;land&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kr"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tu&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;count_time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NORTH&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NORTH&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;land&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;land&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SOUTH&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SOUTH&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;land&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;land&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EAST&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EAST&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;land&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;land&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;WEST&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;WEST&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;land&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;land&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NORTH&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NORTH&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SOUTH&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SOUTH&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EAST&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EAST&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;WEST&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;costxy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;WEST&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;freopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;input.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d%d%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d%d%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;land&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;count_time&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsbx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsby&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lbx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rbx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lbx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rbx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lbx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;half&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;half&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;half&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;half&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lbx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rbx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// printf(&amp;quot;%d %d %d %d =&amp;gt; %d\n&amp;quot;, ay, ax, by, bx, cost);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;//print(ans);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;rsax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ay&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsbx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsby&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;//printf(&amp;quot;%d %d %d %d\n&amp;quot;, rsay + 1, rsax + 1, rsby + 1, rsbx + 1);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d %d %d %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsby&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rsbx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="codeforces"/><category term="algorithm"/><category term="算法"/><category term="题解"/></entry><entry><title>Codeforces Round #240 (Div. 2) Tutorials and Solutions(incomplete and incorrect)</title><link href="https://wizmann.top/cf-240-div-2.html" rel="alternate"/><published>2014-04-08T14:39:11+08:00</published><updated>2014-04-08T14:39:11+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-04-08:/cf-240-div-2.html</id><summary type="html">&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;It has been months that I didn&amp;rsquo;t participate in the contest on CF, now I&amp;rsquo;m back. :)&lt;/p&gt;
&lt;p&gt;This round of contest makes me confused that the problem B and C is a little bit too twisted, if you can&amp;rsquo;t catch the vital point, you will get a …&lt;/p&gt;</summary><content type="html">&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;It has been months that I didn&amp;rsquo;t participate in the contest on CF, now I&amp;rsquo;m back. :)&lt;/p&gt;
&lt;p&gt;This round of contest makes me confused that the problem B and C is a little bit too twisted, if you can&amp;rsquo;t catch the vital point, you will get a lot of WAs in the end.&lt;/p&gt;
&lt;p&gt;Additionally, the problem D is too easy, just a simple DP and the time limit is too long for an unoptimized solution.&lt;/p&gt;
&lt;p&gt;And as usual, I have no idea to the problem E. :(&lt;/p&gt;
&lt;h2 id="a-mashmokh-and-lights"&gt;A. Mashmokh and Lights&lt;/h2&gt;
&lt;p&gt;The description is too long for a problem A, but it is as easy as it used to be.&lt;/p&gt;
&lt;p&gt;Just decalre an array to keep the records of who is the first to turn off the light.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;bs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="b-mashmokh-and-tokens"&gt;B. Mashmokh and Tokens&lt;/h2&gt;
&lt;p&gt;It is quite confused that Mashmokh just save the tokens for NOTHING?! I took it for granted that Mashmokh should save all the extra token for a final exchange. But I was wrong. The problem just asks for how many tokens is useless for the tokens-salary exchange everyday.&lt;/p&gt;
&lt;p&gt;Uh, so sad. If I was Mashmokh, I just give all my tokens to my boss as the saved tokens  would never counts.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="c-mashmokh-and-numbers"&gt;C. Mashmokh and Numbers&lt;/h2&gt;
&lt;p&gt;You need a full-time QA for this problem because some of the scenarios will lead to hours of debuging. :(&lt;/p&gt;
&lt;p&gt;The  thought of the problem is easy enough, just print two numbers with the gcd equal to &lt;code&gt;g&lt;/code&gt; and a sequence of squential numbers with m pairs that each pair has a gcd equals to &lt;code&gt;1&lt;/code&gt;. At last, just make sure that &lt;code&gt;g + m == k&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, there are some &lt;strong&gt;special&lt;/strong&gt; test cases.&lt;/p&gt;
&lt;p&gt;n = 1, k = 0. &lt;br&gt;
You can pass this case if you print any positive number.                      &lt;/p&gt;
&lt;p&gt;n = 1, k - (n / 2) + 1 &amp;lt;= 0. &lt;br&gt;
It will lead to &amp;ldquo;-1&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;And the scenarios that the n is odd.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="d-mashmokh-and-acm"&gt;D. Mashmokh and ACM&lt;/h2&gt;
&lt;p&gt;A simple DP problem. The formula is quite easy.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a0&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i - 1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a1&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i - 1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ai&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i - 1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ai&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The time complexity is &lt;code&gt;m * n * (1 + 1/2 + 1/3 + ... 1/n)&lt;/code&gt;, and the sum of series &lt;code&gt;1 + 1/2 + ...&lt;/code&gt; is called harmonic number of n which approximately equals to &lt;code&gt;ln(n)&lt;/code&gt;. So the final time complexity is &lt;code&gt;m * n * ln(n)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Further, we can reuse the space of dp array to gain a better CPU cache optimizism.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;ctime&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;map&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout&amp;lt;&amp;lt;x&amp;lt;&amp;lt;endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin&amp;gt;&amp;gt;x&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1000000007L&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="codeforces"/><category term="algorithm"/><category term="算法"/><category term="题解"/></entry><entry><title>"alloca" vs "placement new"</title><link href="https://wizmann.top/alloca-vs-placement-new.html" rel="alternate"/><published>2014-04-07T21:08:59+08:00</published><updated>2014-04-07T21:08:59+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-04-07:/alloca-vs-placement-new.html</id><summary type="html">&lt;h2 id="what"&gt;WHAT?!&lt;/h2&gt;
&lt;p&gt;For most time, we use &lt;code&gt;malloc&lt;/code&gt; or &lt;code&gt;new&lt;/code&gt; for memory allocation, which will get it on &lt;em&gt;heap&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;However, access memory on &lt;em&gt;heap&lt;/em&gt; is not as effective as the memory on &lt;em&gt;stack&lt;/em&gt;, because the heap is &amp;ldquo;free-floating region of memory&amp;rdquo;. To the contrary, memory on &lt;em&gt;stack&lt;/em&gt; is managed by CPU …&lt;/p&gt;</summary><content type="html">&lt;h2 id="what"&gt;WHAT?!&lt;/h2&gt;
&lt;p&gt;For most time, we use &lt;code&gt;malloc&lt;/code&gt; or &lt;code&gt;new&lt;/code&gt; for memory allocation, which will get it on &lt;em&gt;heap&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;However, access memory on &lt;em&gt;heap&lt;/em&gt; is not as effective as the memory on &lt;em&gt;stack&lt;/em&gt;, because the heap is &amp;ldquo;free-floating region of memory&amp;rdquo;. To the contrary, memory on &lt;em&gt;stack&lt;/em&gt; is managed by CPU automacitally and tightly. As a result, the further of the &lt;em&gt;stack&lt;/em&gt; compared to &lt;em&gt;heap&lt;/em&gt; is that we can have a faster read/write speed due to the fact that &lt;em&gt;stack&lt;/em&gt; memory is more likely to optimized by &lt;strong&gt;CPU cache&lt;/strong&gt;, in addition, it only uses a single instruction to allocate or deallocate &lt;em&gt;stack&lt;/em&gt; memory. Just like this.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allocate&lt;/span&gt;
&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deallocate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="alloca"&gt;alloca&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;alloca()&lt;/code&gt; function allocates memory from the &lt;em&gt;stack&lt;/em&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;alloca&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It&amp;rsquo;s quite the same as the &lt;code&gt;malloc&lt;/code&gt; way. But we shouldn&amp;rsquo;t free the memory allocated on the &lt;em&gt;stack&lt;/em&gt;; these memory will be automatically deallocated when you leave the function(&lt;strong&gt;not the code block&lt;/strong&gt;).&lt;/p&gt;
&lt;h2 id="placement-new"&gt;placement new&lt;/h2&gt;
&lt;p&gt;The placement new is one of the overloads of the &lt;code&gt;new&lt;/code&gt; functions; this new syntax can do something as the &lt;code&gt;alloca()&lt;/code&gt; function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The placement new can be also used in some other scenarios but won&amp;rsquo;t be mentioned here.&lt;/p&gt;
&lt;h2 id="variable-length-array"&gt;variable-length array&lt;/h2&gt;
&lt;p&gt;C90 and C++ both support the variable-length array which will be allocated on &lt;em&gt;stack&lt;/em&gt;, and it will be deallocted whhen you leave the &lt;strong&gt;clode block&lt;/strong&gt;, such as &amp;ldquo;if&amp;rdquo;, &amp;ldquo;while&amp;rdquo;, etc.&lt;/p&gt;
&lt;p&gt;This is much simplified, but be ware if you use both variable-length array and &lt;code&gt;alloca()&lt;/code&gt; in the same function, the deallocation of the array will also free anything more recenly allocated by alloca.&lt;/p&gt;
&lt;h2 id="defects"&gt;Defects&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Stack&lt;/em&gt; has its limitation. If the allocation on &lt;em&gt;stack&lt;/em&gt; causes &lt;strong&gt;stack overflow&lt;/strong&gt; error, then the behavior of the program is undefined.&lt;/p&gt;
&lt;p&gt;Further, the variable-length array and &lt;code&gt;alloca()&lt;/code&gt; are not included in &lt;em&gt;ANSI-C&lt;/em&gt; standard and therefore could limit portability.&lt;/p&gt;
&lt;p&gt;The Google C++ style guide encourage developers to use &lt;code&gt;scoped_ptr&lt;/code&gt; or &lt;code&gt;scopted_array&lt;/code&gt; instead of variable-length array and &lt;code&gt;alloca()&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="some-experiment"&gt;Some experiment&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// compile with: g++ -std=c++0x -O2 -Wall -g -o &amp;quot;foo.cc&amp;quot; &amp;quot;foo&amp;quot;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="cp"&gt;#if defined(__i386__)&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__inline__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdtsc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;__asm__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.byte 0x0f, 0x31&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;=A&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#elif defined(__x86_64__)&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__inline__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdtsc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;__asm__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__volatile__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rdtsc&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;=a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;=d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;


&lt;span class="c1"&gt;//#define MEMORY_ON_HEAP&lt;/span&gt;
&lt;span class="c1"&gt;//#define MEMORY_ON_STACK&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;102400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdtsc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;#ifdef MEMORY_ON_HEAP &lt;/span&gt;&lt;span class="c1"&gt;// RDSTC: 20586280&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;#endif&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;#ifdef MEMORY_ON_STACK &lt;/span&gt;&lt;span class="c1"&gt;// RDSTC: 3660502&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;alloca&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;#endif&lt;/span&gt;


&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdtsc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can use &lt;code&gt;info register esp&lt;/code&gt; in gdb to inspect the &lt;em&gt;stack&lt;/em&gt; pointer before and after you call the allocation function or declare a variable-length array.&lt;/p&gt;</content><category term="Blog"/><category term="cpp"/><category term="memory"/><category term="stack"/><category term="heap"/><category term="allocate"/><category term="alloca"/><category term="c++"/></entry><entry><title>GeoHash算法</title><link href="https://wizmann.top/geo-hash-algorithm.html" rel="alternate"/><published>2014-02-04T00:10:00+08:00</published><updated>2014-02-04T00:10:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-02-04:/geo-hash-algorithm.html</id><summary type="html">&lt;h2 id="geohash"&gt;GeoHash&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Geohash is a latitude/longitude geocode system invented by Gustavo Niemeyer when writing the web service at geohash.org, and put into the public domain. It is a hierarchical spatial data structure which subdivides space into buckets of grid shape.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;简单说，GeoHash是一个将经纬度信息编码成一个string的算法。从而便于储 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="geohash"&gt;GeoHash&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Geohash is a latitude/longitude geocode system invented by Gustavo Niemeyer when writing the web service at geohash.org, and put into the public domain. It is a hierarchical spatial data structure which subdivides space into buckets of grid shape.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;简单说，GeoHash是一个将经纬度信息编码成一个string的算法。从而便于储存、查找。&lt;/p&gt;
&lt;h2 id="geohash_1"&gt;GeoHash算法的步骤&lt;/h2&gt;
&lt;p&gt;GeoHash对经度纬度分别编码，原理是迭代做二分，进而逼近真实值。&lt;/p&gt;
&lt;p&gt;我们以纬度举例。&lt;/p&gt;
&lt;p&gt;由于地球纬度区间是[-90,90]，所以取区间中点&lt;code&gt;pivot&lt;/code&gt;。如果某地点P的纬度大于&lt;code&gt;pivot&lt;/code&gt;的值，则编码的第1位为&lt;code&gt;1&lt;/code&gt;，反之为&lt;code&gt;0&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;然后缩小范围，迭代N次。得到最后的结果。&lt;/p&gt;
&lt;p&gt;经度的范围是[-180, 180]。我们重复上面的过程，也可以得到经度编码。&lt;/p&gt;
&lt;p&gt;最后我们把经度和纬度的编码进行交错组合，偶数位放经度，奇数位放纬度。得到最后的GeoHash编码。&lt;/p&gt;
&lt;p&gt;例如，经纬度&lt;code&gt;(57.64911,10.40744)&lt;/code&gt;可以使用base32编码为 &lt;code&gt;u4pruydqqvj&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="geohash_2"&gt;GeoHash算法的用途&lt;/h2&gt;
&lt;p&gt;由于GeoHash使用经纬度交错编码，所以我们使用某一个&lt;b&gt;前辍&lt;/b&gt;，就可以划定一个经纬度范围。&lt;/p&gt;
&lt;p&gt;&lt;img alt="GeoHash-grid" src="https://github.com/Wizmann/assets/raw/master/wizmann-tk-pic/blog-geohash-grid.jpg"&gt;&lt;/p&gt;
&lt;p&gt;如果我们对GeoHash编码这一列进行索引加速，则可以在较快的时间内查找到某一个范围内的所有grid，进而获得POI等信息。&lt;/p&gt;
&lt;h2 id="geohash_3"&gt;GeoHash的压缩思想&lt;/h2&gt;
&lt;p&gt;GeoHash的交错编码为区间查找提供了遍历。而对经纬度的逼近编码则提供了非常好的压缩特性。&lt;/p&gt;
&lt;p&gt;易得，一个点位于&lt;code&gt;pivot&lt;/code&gt;的左右/上下的机率是相同的。所以编码的每一位的信息量都是&lt;code&gt;-logPr[s]&lt;/code&gt;=&amp;gt;&lt;code&gt;1bit&lt;/code&gt;，达到了数据压缩的下限。&lt;/p&gt;
&lt;p&gt;又由于二分逼近的良好性能，使得压缩/解压缩的速度可以达到极限。&lt;/p&gt;
&lt;p&gt;不过在实际应用中，POI不可能完全平均分布，所以GeoHash的压缩只是一种接近最优解的方案。但是由于二分逼近法带来的可索引性，GeoHash绝对可以称的上是一个精妙完美的设计了。&lt;/p&gt;
&lt;h2 id="-poi"&gt;应用 - 拉取目标周围的POI&lt;/h2&gt;
&lt;p&gt;我们在一些LBS应用中，经常需要拉取某一点周围的POI。&lt;/p&gt;
&lt;p&gt;假设我们将POI存储为一个&lt;code&gt;pvlist&lt;/code&gt;映射。并且获得了某点的GeoHash值。那么我们怎么取得周围的POI呢？&lt;/p&gt;
&lt;p&gt;理想状态下，“附近的POI”都是在一个以某点为圆心的圆进行查找。但是由于GeoHash划分的范围是一个矩形，所以我们使用一个&lt;code&gt;3×3&lt;/code&gt;的大矩形来替代圆形范围。&lt;/p&gt;
&lt;p&gt;其中&lt;code&gt;3×3&lt;/code&gt;矩形中最中间的矩形是我们确定的那个点。&lt;/p&gt;
&lt;p&gt;然后，我们根据给出的半径&lt;code&gt;r&lt;/code&gt;确定GeoHash的精确度。使得我们的&lt;code&gt;3×3&lt;/code&gt;大矩形可以包含理想的圆形范围。&lt;/p&gt;
&lt;p&gt;于是下一步的目标就是找到某点GeoHash的&lt;strong&gt;8个&lt;/strong&gt;临近的GeoHash。&lt;/p&gt;
&lt;p&gt;由上文我们可以得出，GeoHash的经纬度是分别编码的。以一个&lt;code&gt;4×4&lt;/code&gt;的地图为例。&lt;/p&gt;
&lt;p&gt;这是在纬度上的划分。&lt;/p&gt;
&lt;p&gt;&lt;img alt="纬度" src="https://github.com/Wizmann/assets/raw/master/wizmann-tk-pic/blog-geohash-latitude-grid.png"&gt;&lt;/p&gt;
&lt;p&gt;可以看出，连续的&lt;code&gt;GeoHash Grid&lt;/code&gt;的纬度编码也是连续的。&lt;/p&gt;
&lt;p&gt;经度同理。&lt;/p&gt;
&lt;p&gt;所以我们只需要&lt;code&gt;decode&lt;/code&gt;我们的GeoHash编码，将&lt;code&gt;longitude&lt;/code&gt;和&lt;code&gt;latitude&lt;/code&gt;编码分别进行&lt;code&gt;-1/+1&lt;/code&gt;的操作就可以获得&lt;strong&gt;附近的POI&lt;/strong&gt;的GeoHash码/前辍了。&lt;/p&gt;
&lt;h2 id="_1"&gt;总结&lt;/h2&gt;
&lt;p&gt;GeoHash的三个特性，&lt;b&gt;可索引&lt;/b&gt;，&lt;b&gt;压缩&lt;/b&gt;，&lt;b&gt;便于存储&lt;/b&gt;。&lt;/p&gt;
&lt;p&gt;还有，好久不写文了。&lt;/p&gt;
&lt;h2 id="_2"&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://book.douban.com/subject/11554138/"&gt;HBase in Action&lt;/a&gt;, Chpt. 8&lt;/li&gt;
&lt;li&gt;&lt;a href="http://book.douban.com/subject/3729518/"&gt;深入搜索引擎&lt;/a&gt;, Chpt. 2&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Geohash"&gt;GeoHash - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.cnblogs.com/LBSer/p/3310455.html"&gt;GeoHash核心原理解析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.google.com/p/python-geohash/"&gt;python-geohash&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/><category term="GeoHash"/><category term="POI"/><category term="压缩"/><category term="索引"/></entry><entry><title>如何判断一个网站的地理信息</title><link href="https://wizmann.top/find-the-geo-location-of-a-host.html" rel="alternate"/><published>2014-01-24T00:00:00+08:00</published><updated>2014-01-24T00:00:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-01-24:/find-the-geo-location-of-a-host.html</id><summary type="html">&lt;h2 id="_1"&gt;啥？&lt;/h2&gt;
&lt;p&gt;面试题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;有一个网站，如何判断这个网站的地理信息&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_2"&gt;方法&lt;/h2&gt;
&lt;h3 id="dns"&gt;使用反向DNS&lt;/h3&gt;
&lt;p&gt;当我们只有网站的IP地址时，我们可以使用&lt;strong&gt;反向DNS&lt;/strong&gt;来获得 …&lt;/p&gt;</summary><content type="html">&lt;h2 id="_1"&gt;啥？&lt;/h2&gt;
&lt;p&gt;面试题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;有一个网站，如何判断这个网站的地理信息&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="_2"&gt;方法&lt;/h2&gt;
&lt;h3 id="dns"&gt;使用反向DNS&lt;/h3&gt;
&lt;p&gt;当我们只有网站的IP地址时，我们可以使用&lt;strong&gt;反向DNS&lt;/strong&gt;来获得这个IP地址对应的域名。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;反向域名解析，Reverse DNS。反向域名解析与通常的正向域名解析相反，提供IP地址到域名的对应。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们可以使用&lt;code&gt;dig -x&lt;/code&gt;来进行查询&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;dig&lt;span class="w"&gt; &lt;/span&gt;-x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;75&lt;/span&gt;.126.43.235

&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;DiG&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.8.1-P1&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;-x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;75&lt;/span&gt;.126.43.235
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;global&lt;span class="w"&gt; &lt;/span&gt;options:&lt;span class="w"&gt; &lt;/span&gt;+cmd
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Got&lt;span class="w"&gt; &lt;/span&gt;answer:
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&amp;gt;HEADER&lt;span class="s"&gt;&amp;lt;&amp;lt;- opco&lt;/span&gt;de:&lt;span class="w"&gt; &lt;/span&gt;QUERY,&lt;span class="w"&gt; &lt;/span&gt;status:&lt;span class="w"&gt; &lt;/span&gt;NOERROR,&lt;span class="w"&gt; &lt;/span&gt;id:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;26688&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;flags:&lt;span class="w"&gt; &lt;/span&gt;qr&lt;span class="w"&gt; &lt;/span&gt;rd&lt;span class="w"&gt; &lt;/span&gt;ra&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;QUERY:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;ANSWER:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;AUTHORITY:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;ADDITIONAL:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;

&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;QUESTION&lt;span class="w"&gt; &lt;/span&gt;SECTION:
&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="m"&gt;235&lt;/span&gt;.43.126.75.in-addr.arpa.&lt;span class="w"&gt;    &lt;/span&gt;IN&lt;span class="w"&gt;  &lt;/span&gt;PTR

&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ANSWER&lt;span class="w"&gt; &lt;/span&gt;SECTION:
&lt;span class="m"&gt;235&lt;/span&gt;.43.126.75.in-addr.arpa.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3518&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;IN&lt;span class="w"&gt; &lt;/span&gt;PTR&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;75&lt;/span&gt;.126.43.235-static.reverse.softlayer.com.

&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Query&lt;span class="w"&gt; &lt;/span&gt;time:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;76&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;msec
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;SERVER:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.8.4.4#53&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.8.4.4&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;WHEN:&lt;span class="w"&gt; &lt;/span&gt;Fri&lt;span class="w"&gt; &lt;/span&gt;Jan&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;:15:22&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2014&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;MSG&lt;span class="w"&gt; &lt;/span&gt;SIZE&lt;span class="w"&gt;  &lt;/span&gt;rcvd:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;我们可以从接续出来的域名中，获得一些信息，例如公司名/机构名，以及&lt;code&gt;.cn&lt;/code&gt;, &lt;code&gt;.us&lt;/code&gt;等有可能标识地理位置的信息。&lt;/p&gt;
&lt;p&gt;但是，反向DNS不一定成功。&lt;/p&gt;
&lt;h2 id="dns-loc"&gt;查询DNS LOC信息&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;In the Domain Name System, a LOC record (RFC 1876) is a means for expressing geographic location information for a domain name.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以我们可以尝试使用&lt;code&gt;dig loc&lt;/code&gt;命令来查询位置信息。（不一定成功&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;dig&lt;span class="w"&gt; &lt;/span&gt;loc&lt;span class="w"&gt; &lt;/span&gt;SW1A2AA.find.me.uk

&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;DiG&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.8.1-P1&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;loc&lt;span class="w"&gt; &lt;/span&gt;SW1A2AA.find.me.uk
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;global&lt;span class="w"&gt; &lt;/span&gt;options:&lt;span class="w"&gt; &lt;/span&gt;+cmd
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Got&lt;span class="w"&gt; &lt;/span&gt;answer:
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&amp;gt;HEADER&lt;span class="s"&gt;&amp;lt;&amp;lt;- opco&lt;/span&gt;de:&lt;span class="w"&gt; &lt;/span&gt;QUERY,&lt;span class="w"&gt; &lt;/span&gt;status:&lt;span class="w"&gt; &lt;/span&gt;NOERROR,&lt;span class="w"&gt; &lt;/span&gt;id:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;49682&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;flags:&lt;span class="w"&gt; &lt;/span&gt;qr&lt;span class="w"&gt; &lt;/span&gt;rd&lt;span class="w"&gt; &lt;/span&gt;ra&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;QUERY:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;ANSWER:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;AUTHORITY:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;ADDITIONAL:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;

&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;QUESTION&lt;span class="w"&gt; &lt;/span&gt;SECTION:
&lt;span class="p"&gt;;&lt;/span&gt;SW1A2AA.find.me.uk.&lt;span class="w"&gt;        &lt;/span&gt;IN&lt;span class="w"&gt;  &lt;/span&gt;LOC

&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ANSWER&lt;span class="w"&gt; &lt;/span&gt;SECTION:
SW1A2AA.find.me.uk.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;21600&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;IN&lt;span class="w"&gt;  &lt;/span&gt;LOC&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;51&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;.748&lt;span class="w"&gt; &lt;/span&gt;N&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;39&lt;/span&gt;.611&lt;span class="w"&gt; &lt;/span&gt;W&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.00m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.00m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.00m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.00m

&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Query&lt;span class="w"&gt; &lt;/span&gt;time:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1232&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;msec
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;SERVER:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.8.4.4#53&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.8.4.4&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;WHEN:&lt;span class="w"&gt; &lt;/span&gt;Fri&lt;span class="w"&gt; &lt;/span&gt;Jan&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;:21:44&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2014&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;MSG&lt;span class="w"&gt; &lt;/span&gt;SIZE&lt;span class="w"&gt;  &lt;/span&gt;rcvd:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="_3"&gt;随便看看&lt;/h2&gt;
&lt;p&gt;查看我们要调查的网站，找寻可用的线索。（囧&lt;/p&gt;
&lt;h2 id="whois"&gt;使用whois服务&lt;/h2&gt;
&lt;p&gt;http://whois.chinaz.com/sina.com&lt;/p&gt;
&lt;p&gt;我们可以看到域名的注册信息，其中也必然透露了线索。&lt;/p&gt;
&lt;h2 id="traceroutewhois"&gt;traceroute与whois配合使用&lt;/h2&gt;
&lt;p&gt;可以根据包的转发状况来获得最终的地理位置&lt;/p&gt;
&lt;h2 id="time-of-day-service"&gt;使用Time of day service&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;telnet www.bupt.edu.cn 13&lt;/code&gt;可以获得主机的当前时间，从而判断主机所在的经度。（不一定成功。。。&lt;/p&gt;
&lt;h2 id="_4"&gt;参考链接&lt;/h2&gt;
&lt;p&gt;http://www.private.org.il/IP2geo.html&lt;/p&gt;
&lt;p&gt;http://www.ipgeo.com/&lt;/p&gt;</content><category term="Blog"/><category term="面试"/></entry><entry><title>Codeforces Round #223 (Div. 2) 不完全不正确题解</title><link href="https://wizmann.top/cf-223-div-2.html" rel="alternate"/><published>2014-01-18T14:47:00+08:00</published><updated>2014-01-18T14:47:00+08:00</updated><author><name>Wizmann</name></author><id>tag:wizmann.top,2014-01-18:/cf-223-div-2.html</id><summary type="html">&lt;p&gt;由于大号已经进Div. 1了，所以接下来的几场Div. 2都是用小号做的。&lt;/p&gt;
&lt;p&gt;等有实力切D题了，再去打一区。（弱&lt;/p&gt;
&lt;p&gt;事情一直很多，所以题解落后了好久才发。&lt;/p&gt;
&lt;h2 id="a-sereja-and-dima"&gt;A. Sereja …&lt;/h2&gt;</summary><content type="html">&lt;p&gt;由于大号已经进Div. 1了，所以接下来的几场Div. 2都是用小号做的。&lt;/p&gt;
&lt;p&gt;等有实力切D题了，再去打一区。（弱&lt;/p&gt;
&lt;p&gt;事情一直很多，所以题解落后了好久才发。&lt;/p&gt;
&lt;h2 id="a-sereja-and-dima"&gt;A. Sereja and Dima&lt;/h2&gt;
&lt;p&gt;纯模拟，Python随便搞&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;pokers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pokers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pokers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;pokers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;pokers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;pokers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;pokers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="b-sereja-and-stairs"&gt;B. Sereja and Stairs&lt;/h2&gt;
&lt;p&gt;题目要求实现一个数组，使前一半为递增，后一半为递减。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;a[1] &amp;lt; a[2] &amp;lt; ... &amp;lt; a[i - 1] &amp;lt; a[i] &amp;gt; a[i + 1] &amp;gt; ... &amp;gt; a[n -  1] &amp;gt; a[n]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;所以我们观察到，某一个数&lt;code&gt;x&lt;/code&gt;在数组&lt;code&gt;a&lt;/code&gt;中最多可以出现两次，其中一次在左边的序列，一次在右边的序列。&lt;/p&gt;
&lt;p&gt;所以我们就对给出的数组&lt;code&gt;s&lt;/code&gt;进行一次统计，找出每一个数出现的次数。&lt;/p&gt;
&lt;p&gt;并分别讨论出现一次和出现两次的情况。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5120&lt;/span&gt;

&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;cnt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="n"&gt;maxi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxi&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;maxi&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="c-sereja-and-prefixes"&gt;C. Sereja and Prefixes&lt;/h2&gt;
&lt;p&gt;给定一个空序列&lt;code&gt;A&lt;/code&gt;，然后这个序列上可以有两种操作。&lt;/p&gt;
&lt;p&gt;一是&lt;code&gt;A.push_back(x)&lt;/code&gt;，二是&lt;code&gt;A.push_back_batch(A[0]...A[i])&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;由于操作的次数是&lt;code&gt;10^5&lt;/code&gt;，于是我们将序列&lt;code&gt;A&lt;/code&gt;存成一个如下的形式。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;a -&amp;gt; b -&amp;gt; c -&amp;gt; copy(0...i) -&amp;gt; d -&amp;gt; copy(0 ... j)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;我们可以看出，如果询问的位置&lt;code&gt;pos&lt;/code&gt;是一个数，则我们可以直接返回结果。如果询问的位置&lt;code&gt;pos&lt;/code&gt;位于一个&lt;code&gt;copy&lt;/code&gt;块里面，那么这个数一定会在&lt;code&gt;A[0...i]&lt;/code&gt;中出现，则我们可以处理&lt;code&gt;pos&lt;/code&gt; -&amp;gt; &lt;code&gt;pos'&lt;/code&gt;，使&lt;code&gt;pos'&lt;/code&gt;位于&lt;code&gt;A[0...i]&lt;/code&gt;区间内。如此循环，直到&lt;code&gt;pos&lt;/code&gt;是一个数为止。&lt;/p&gt;
&lt;p&gt;然后这题用的算法貌似不是最快的，但是我觉得是最好理解的一种。&lt;/p&gt;
&lt;p&gt;使用一个大根堆循环取&lt;code&gt;query&lt;/code&gt;中最大的值，然后进行处理。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;queue&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;map&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100010&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rep&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;rep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;rep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(){}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(){}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iq&lt;/span&gt;&lt;span class="p"&gt;){}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;friend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;priority_queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;is_value&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%lld&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="d-sereja-and-tree"&gt;D. Sereja and Tree&lt;/h2&gt;
&lt;p&gt;暴力乱搞，因为树的高度只有7000，所以怎么搞都大概能过。但是为什么做的人好少。&lt;/p&gt;
&lt;p&gt;可能是题目表述的不太好吧。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;queue&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;map&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stack&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;set&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7010&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LINE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;501000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(){}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;il&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ival&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;il&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ir&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ival&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LINE&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LINE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ins&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;intersect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LINE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;ins&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intersect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ins&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ins&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ins&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rr&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;ins&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="e-sereja-and-brackets"&gt;E. Sereja and Brackets&lt;/h2&gt;
&lt;p&gt;不出意外的又看错题了。。。_(:з」∠)_&lt;/p&gt;
&lt;p&gt;最长的括号区间居然是可以在中间删除一些括号的区间。这样题目就变成了一道比较简单的&lt;code&gt;离线化+树状数组&lt;/code&gt;了。&lt;/p&gt;
&lt;p&gt;代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;queue&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;map&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stack&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define print(x) cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl&lt;/span&gt;
&lt;span class="cp"&gt;#define input(x) cin &amp;gt;&amp;gt; x&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;llint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ppair&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ppair&lt;/span&gt;&lt;span class="p"&gt;(){}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ppair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;il&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;il&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ir&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;friend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ppair&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ppair&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kr"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;lowbit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;BIT&lt;/span&gt;&lt;span class="c1"&gt;//点更新，区间查询&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;baum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;baum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;baum&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;baum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="n"&gt;lowbit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="n"&gt;baum&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="n"&gt;lowbit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;//查询区间和&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ppair&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ppair&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;(&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ppair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;BIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;scanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ppair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/><category term="codeforces"/><category term="algorithm"/><category term="算法"/><category term="题解"/></entry></feed>