<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://hate13.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://hate13.com/" rel="alternate" type="text/html" hreflang="zh-Hans" /><updated>2026-09-19T06:17:27+00:00</updated><id>https://hate13.com/feed.xml</id><title type="html">哈特13</title><subtitle>hate13&apos;s Blog
</subtitle><author><name>朱元朝</name><email>452181625@qq.com</email></author><entry><title type="html">Gap 期间做了什么</title><link href="https://hate13.com/2026/02/01/Gap-%E6%9C%9F%E9%97%B4%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88.html" rel="alternate" type="text/html" title="Gap 期间做了什么" /><published>2026-02-01T00:00:00+00:00</published><updated>2026-02-01T00:00:00+00:00</updated><id>https://hate13.com/2026/02/01/Gap%20%E6%9C%9F%E9%97%B4%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88</id><content type="html" xml:base="https://hate13.com/2026/02/01/Gap-%E6%9C%9F%E9%97%B4%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88.html"><![CDATA[<p>Gap 4 个月做了什么</p>

<!--more-->

<p>回想起来，感觉也没干啥，很快就过去了</p>

<ul>
  <li>回家：10 月份回了趟家，在家待了几天</li>
  <li>去玩
    <ul>
      <li>10 月去了趟新疆，风景绝美</li>
      <li>11 月去了趟理小路</li>
      <li>01 月去了雅安龙苍沟</li>
      <li>其他时间去三岔湖、都江堰蒲虹路、龙泉山转了转</li>
    </ul>
  </li>
  <li>结婚
    <ul>
      <li>1 月份在新疆办婚礼</li>
      <li>2 月份过年在老家办婚礼</li>
      <li>2.14 领证，参与了天府新区的活动，上了一次大屋檐屏幕</li>
    </ul>
  </li>
  <li>找工作：斥巨资买了个 Macbook Air M4，连着一段时间，去了好几个图书馆和咖啡馆</li>
</ul>]]></content><author><name>朱元朝</name><email>452181625@qq.com</email></author><category term="生活" /><summary type="html"><![CDATA[Gap 4 个月做了什么]]></summary></entry><entry><title type="html">Bye ByteDance</title><link href="https://hate13.com/2025/09/30/ByeByteDance.html" rel="alternate" type="text/html" title="Bye ByteDance" /><published>2025-09-30T00:00:00+00:00</published><updated>2025-09-30T00:00:00+00:00</updated><id>https://hate13.com/2025/09/30/ByeByteDance</id><content type="html" xml:base="https://hate13.com/2025/09/30/ByeByteDance.html"><![CDATA[<p>2018/04-2025/09，Bye ByteDance，祝大家越来越好</p>

<p>先休息一段时间，下一站待定</p>

<!--more-->]]></content><author><name>朱元朝</name><email>452181625@qq.com</email></author><category term="工作" /><summary type="html"><![CDATA[2018/04-2025/09，Bye ByteDance，祝大家越来越好 先休息一段时间，下一站待定]]></summary></entry><entry><title type="html">2024总结</title><link href="https://hate13.com/2024/11/29/2024%E6%80%BB%E7%BB%93.html" rel="alternate" type="text/html" title="2024总结" /><published>2024-11-29T00:00:00+00:00</published><updated>2024-11-29T00:00:00+00:00</updated><id>https://hate13.com/2024/11/29/2024%E6%80%BB%E7%BB%93</id><content type="html" xml:base="https://hate13.com/2024/11/29/2024%E6%80%BB%E7%BB%93.html"><![CDATA[<p>2024 这一年做了很多事情，记录一下
<!--more--></p>

<h2 id="回四川">回四川</h2>
<p>其实很早就想着回来，但是一直没有付出实践，5/28 这一天认认真真进行了分析，有这么几个原因让我下定了决心</p>

<ul>
  <li>孤独，生活不健康</li>
  <li>离家近一点，离家人近一点</li>
  <li>人生每个阶段重要的事情不一样，还有很多其他重要的事情要做</li>
</ul>

<p>最后在 10/11/12 月，完成了面试和交接，把东西寄出去，在 12/23 踏上了回来的路</p>

<p>当时发了一条动态：</p>

<blockquote>
  <p>北京，再见啦。从 2017 到 2023，从西二旗到知春路，感谢一路上遇到的小伙伴们</p>
</blockquote>

<h2 id="约饭">约饭</h2>

<p>回来后第一件事情就是约饭，前 2 个月基本上每周末都有约：</p>

<ul>
  <li>玩得好的朋友</li>
  <li>多年不见的高中同学</li>
  <li>亲戚</li>
  <li>…</li>
</ul>

<h2 id="做饭">做饭</h2>
<p>之前在北京的时候就想自己学做饭，但是受限于合租，一直没机会，回来之后迅速买了一堆厨房用的东西（差生文具多）</p>

<p>有段时间每天上班都在想周末做什么吃的，在公司食堂吃到好吃的也会记下来如果简单就周末自己尝试做做</p>

<p>虽然到现在也没有学会几道菜，只会几个简单的，哈哈哈</p>

<ul>
  <li>蛋炒饭</li>
  <li>辣椒炒肉</li>
  <li>花菜炒腊肉</li>
  <li>清炒儿菜</li>
  <li>炒土豆丝</li>
  <li>炝炒凤尾</li>
  <li>清炒小白菜</li>
  <li>凉拌苋菜</li>
  <li>凉拌黄瓜</li>
  <li>黄瓜豆腐汤</li>
  <li>…</li>
</ul>

<h2 id="骑车">骑车</h2>
<p>骑自行车算是为数不多的爱好之一</p>

<p>在北京觉得买自行车比较麻烦，只能骑共享单车，骑过长安街、北京四环、中国地图路书、卢沟桥… 骑得比较多的路线还有朝阳门 -&gt; 知春路，三元桥 -&gt; 知春路…</p>

<p>回来之后先在咸鱼买了一辆喜德盛 极速 300，骑了大约 1200 公里就给卖了，虽然称为平把公路车，但是和公路车还是差得挺多的，之后买了一辆千里达龙卷风 700</p>

<p>一年下来骑了 2000+ 公里，刷了一圈绿道，进入 11 月之后太冷了就没怎么骑了</p>

<h2 id="买车">买车</h2>
<p>之前一直对买车没多大兴趣，但是回家的时候就特别难受，从成都到达州要抢票，到了达州回家还要坐好几个小时的大巴车，或者让家里来接，过完春节出门又是一样，感觉很累</p>

<p>过年的时候在手机上看了挺久，一开始想买辆 SUV，比如吉利星越 L，后来觉得捷途旅行者方盒子车好看，但是不能越野，后来看了坦克 300 是真的帅，就再也回不去了</p>

<p>本来想等混动 Hi4T，后来价格出来了太贵了而且限量，就买了燃油版，到现在开了 5000 公里</p>

<h2 id="装修">装修</h2>
<p>装修一个非常复杂的事情，但迟早得做</p>

<p>从 4 月份开始，一直搞到 12 月，终于差不多了，打算年底搬进去，正好租房月底也到期了</p>

<p>虽然主体工程包给装修公司了，但是还是有好多要自己操心处理的</p>

<p>硬装阶段：装修方案、选主材、水电点位、工地巡检..<br />
软装阶段：一大堆家电家具，每个周末都要收一堆快递，收快递拆快递约安装..</p>

<h2 id="找对象">找对象</h2>
<p>慢慢来吧，哈哈哈哈</p>

<h2 id="工作">工作</h2>
<p>平平无奇，到新团队有一些不适应</p>

<h2 id="回学校">回学校</h2>
<p>周末回学校转了转，看到新生在军训，感叹时间真快，怀念大学生活</p>]]></content><author><name>朱元朝</name><email>452181625@qq.com</email></author><category term="生活" /><summary type="html"><![CDATA[2024 这一年做了很多事情，记录一下]]></summary></entry><entry><title type="html">异星工厂</title><link href="https://hate13.com/2020/08/31/%E5%BC%82%E6%98%9F%E5%B7%A5%E5%8E%82.html" rel="alternate" type="text/html" title="异星工厂" /><published>2020-08-31T00:00:00+00:00</published><updated>2020-08-31T00:00:00+00:00</updated><id>https://hate13.com/2020/08/31/%E5%BC%82%E6%98%9F%E5%B7%A5%E5%8E%82</id><content type="html" xml:base="https://hate13.com/2020/08/31/%E5%BC%82%E6%98%9F%E5%B7%A5%E5%8E%82.html"><![CDATA[<p><strong><a href="https://store.steampowered.com/app/427520/Factorio/">「异星工厂」Factorio</a></strong> 是一款建造工业生产流水线并保持其高效运转的游戏</p>

<p><img src="https://hate13-blog-1251885630.cos.ap-chengdu.myqcloud.com/factorio.jpg" alt="factorio" /></p>

<!--more-->

<p>闲来没事做，在 stream 上找了个游戏玩，90RMB</p>

<p>很好玩啊，玩了 20 个小时终于通关了新手教程，哈哈哈哈</p>

<h2 id="简介">简介</h2>

<blockquote>
  <p><strong>「异星工厂」Factorio</strong> 是一款建造工业生产流水线并保持其高效运转的游戏。</p>

  <p>在游戏中，你可以抠矿、搞科研、盖工厂、建设自动生产流水线，同时还要与异星虫子们互相伤害。</p>

  <p>你将从一无所有艰辛起步。挥斧砍树，抡镐抠矿，手搓机械臂和传送带，然而像这样一直搞下去并没有什么卵用。因此，你需要高效的大规模发电厂，庞大的石油化工体系，壮观的全自动化产业链，以及替你东奔西走的机器人大队，让你成为物资储备丰盈工业帝国的真正操控者！</p>

  <p>然而，总有一群刁民想害你。这个星球上的土著虫群对你在自家后院里瞎折腾的行为很不爽，总有一天这群刁民会联合起来找你麻烦。因此，你要制造武器、建立防御、准备镇压，让它们知道谁才是真正的主宰者。</p>

  <p>你可以在<strong>多人游戏</strong>中加入不同的阵营，在大触们的带领下与朋友们分工协作， 一起建设恢弘无比的工业园区。</p>

  <p>Factorio的<strong>模组支持</strong>吸引了全世界的设计师参与到对游戏的完善和革新中来，从优化调整到游戏辅助，甚至对游戏的彻底翻新，日新月异的模组将为你不断提供新的乐趣。
除了游戏核心的自由模式和沙盒模式之外，<strong>任务包</strong>还提供了更多不同形式的游戏挑战，这已经作为一个免费的DLC提供给玩家了。</p>

  <p>对随机生成的地图不满意？不满足于原生游戏任务？这都不是事儿。通过内置的<strong>地图编辑器</strong>，你可以任意修改地图，配置地形、建筑、敌人等各种元素。如果你是大触，还可以添加自定义脚本，让你的游戏更具独创性、更加阴吹思婷！</p>

  <p><strong>不打折声明：</strong>我们没有任何打折或降价的计划。</p>
</blockquote>

<h2 id="工厂建设与软件开发">工厂建设与软件开发</h2>

<p>异星工厂非常适合程序员，工厂建设和软件开发有很多相似之处</p>

<h3 id="重视基础">重视基础</h3>

<p>在异星工厂中，煤矿、铁矿、铜矿等是发展工业的基础</p>

<p>在软件开发中，网络、操作系统、数据库等是编程的基础</p>

<h3 id="解耦">解耦</h3>

<p>在异星工厂中，各物品之间通过「总线」的方式进行解耦</p>

<p>在软件开发中，各服务或模块之间通过「接口」的方式进行解耦</p>

<h3 id="可扩展性">可扩展性</h3>

<p>在异星工厂中，构建生产线的时候总是需要额外预留一些空间，保持可扩展性</p>

<p>在软件开发中，编写代码的时候也需要保持良好的可扩展性</p>

<h3 id="重构">重构</h3>

<p>在异星工厂中，总是需要反复推倒重建</p>

<p>在软件开发中，所有的设计总是不完美的，当软件到达一定复杂度的时候，总是需要反复重构</p>

<h3 id="自动化">自动化</h3>

<p>在异星工厂中，很多产品都可以手搓生产，缺点是慢，提高效率需要构建生产线自动化生产</p>

<p>在软件开发中，很多任务都可以手动一步步执行，如果任务执行的频率高，可以通过编写脚本的方式使其自动化</p>]]></content><author><name>朱元朝</name><email>452181625@qq.com</email></author><category term="游戏" /><summary type="html"><![CDATA[「异星工厂」Factorio 是一款建造工业生产流水线并保持其高效运转的游戏]]></summary></entry><entry><title type="html">工作小结 17-20</title><link href="https://hate13.com/2020/07/15/%E5%B7%A5%E4%BD%9C%E5%B0%8F%E7%BB%93-17-20.html" rel="alternate" type="text/html" title="工作小结 17-20" /><published>2020-07-15T00:00:00+00:00</published><updated>2020-07-15T00:00:00+00:00</updated><id>https://hate13.com/2020/07/15/%E5%B7%A5%E4%BD%9C%E5%B0%8F%E7%BB%93%2017-20</id><content type="html" xml:base="https://hate13.com/2020/07/15/%E5%B7%A5%E4%BD%9C%E5%B0%8F%E7%BB%93-17-20.html"><![CDATA[<p><strong>2017/07/05 ~ 2020/07/04</strong></p>

<p>时间很快，仿佛昨天才毕业，今天就已工作三年了</p>

<!--more-->

<h1 id="三年">三年</h1>

<h2 id="17-19">17-19</h2>

<h4 id="17-18"><a href="https://hate13.com/2018/05/28/%E5%B7%A5%E4%BD%9C%E5%B0%8F%E7%BB%93-17-18.html">17-18</a></h4>

<h4 id="18-19"><a href="https://hate13.com/2019/05/25/%E5%B7%A5%E4%BD%9C%E5%B0%8F%E7%BB%93-18-19.html">18-19</a></h4>

<h2 id="三年来我做了什么">三年来我做了什么</h2>

<h3 id="工作">工作</h3>

<p>工作三年，算上实习时间，三年多了</p>

<ol>
  <li>
    <p>16/10/28 - 17/03/16 <br />
人生第一次工作，现在回想起来感觉还不错，体验了很多人生第一次</p>

    <p><strong>第一次租房</strong>：从小学四年级到大学，一直住学校，没在外面住过，没租过房。来北京前，在自如上看了一下房子，感觉好贵，最低 2000+，带着 4 千多块钱，下地铁推着箱子就去租房了（风中凌乱），最终就住在了融泽嘉园，离公司走路 40 分钟左右</p>

    <p><strong>第一次入职</strong>：入职前一天还在和同学说笑，入职什么流程、到公司没人领找谁、怎么称呼同事和老大，不过实际还好，比较顺利</p>

    <p><strong>第一次提交线上代码</strong>：在学校没做过什么项目，写的代码只是在本地运行，上班终于体会到了把代码提交到线上运行的感觉</p>

    <p><strong>第一次领工资</strong>：月底发工资，而且正好当天需要交下个月的房租，当时只剩下几十块钱，实习工资不多，领到第一份工资立马就交房租了</p>

    <p>…</p>
  </li>
  <li>
    <p>17/07/05 - 18/03/23<br />
第一份正式工作，正式入职时参加了校招的为期 5 天的入职培训，还挺好玩的，也认识了一些同学。其中 3 天在室外，第三天凌晨 3 点出发去爬山，剩余 2 天在室内。可惜工作上不太顺利，技术上也没学到什么，比较惆怅，年后提了<a href="https://hate13.com/2018/03/23/%E5%86%8D%E8%A7%81%E7%99%BE%E5%BA%A6.html">离职</a>，裸辞了。离职的那天，3 点多就下班了，第一次这么早下班，一方面感觉终于放松了，一方面又觉得心里空空的</p>
  </li>
  <li>
    <p>18/03/24 - 18/04/08<br />
离职了之后，由于没有电脑（来北京时只带了一个 U 盘），去顺义同学那边住了一小段时间，边复习边找工作，面了几家公司，最终去了头条</p>
  </li>
  <li>
    <p>18/04/09 - 20/07/04<br />
由于穷，加上社保最好不要断，拿到头条 offer 之后很快就入职了。刚来头条时感觉和百度差异很大的，感觉工作还不错，于是一直待到了现在</p>
  </li>
</ol>

<h3 id="学习">学习</h3>

<p>程序员搞计算机，必须得不断地学习。三年来，感觉自己的学习状态也发生了很多变化</p>

<ol>
  <li>刚工作时遇到很多之前没见过的东西，什么都要学、什么都想学，但一开始没找到好的方法，后面慢慢地找到了<a href="https://hate13.com/2019/09/28/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0%E5%B7%A5%E5%85%B7.html">一些比较适合自己的学习方法和工具</a></li>
  <li>后来，随着对工作的熟悉，觉得工作中的东西都会了，也没有特别多的技术点，逐渐进入了一种不知道学什么和不知道怎么学的状态</li>
  <li>再后来，换了一份工作，又接触到了很多新的东西，在一段时间内又学到了很多</li>
  <li>现在，工作挺累的，另外生活上也比较累，学习动力下降了很多，知道有很多东西要学，但是有点不想动了</li>
</ol>

<p>有一次，组里 leader 组织了一些学习方法的分享，说到了为什么要学习，其中有一点就是<strong>缓解焦虑</strong>。确实，长时间不学习会让自己变得比较焦虑，觉得在虚度时光，没有成长</p>

<p>我现在的状态也是，学习动力明显要比刚毕业那会儿下降了很多，时间一长就会有一些焦虑</p>

<p>上面主要说的都是计算机技术上的学习，除了它，还有很多要学习的东西，可是感觉自己这些方面<strong>成长特别特别慢，或者说几乎没有成长</strong> 👎</p>

<h3 id="生活">生活</h3>

<p><u>看过一些书，走过一些路，认识了一些人</u></p>

<h4 id="读书">读书</h4>

<p>很早之前就立了关于读书的 flag，但是打脸了，哈哈哈</p>

<p>19 年前后，或许是因为无聊，开始尝试着<a href="https://hate13.com/book.html">读一些书</a>。其中技术类书和非技术类书都有：</p>

<ul>
  <li>前者的收益比较明显，看完一本不错的书就能学到很多东西</li>
  <li>后者“<a href="https://hate13.com/2020/03/21/%E5%85%B3%E4%BA%8E%E8%AF%BB%E4%B9%A6.html">我现在也说不清楚读这些书能给我带来什么实质的好处，甚至读完就忘得差不多了。但在这个过程中，能感受作者的一些思想、了解书中主人公的经历，觉得挺好的。或许在未来的某一天，我会因此受益</a>”</li>
</ul>

<h4 id="旅行">旅行</h4>

<p>三年来，去过一些地方，不多</p>

<ol>
  <li>
    <p>北京周边<br />
读书时参加比赛（公费旅游）来过两次北京，好多地方当时就去过了。工作了之后反而不怎么想出门，一方面不知道去哪，另一方面不想动，只是偶尔出去逛一逛。19 年中秋骑着共享单车绕着四环骑了一圈，期待下一次挑战更远的行程</p>
  </li>
  <li>
    <p>长沙<br />
毕业一年后的的十一，和三个室友各自从北京/上海/广州/成都相距长沙</p>
  </li>
  <li>
    <p>天津<br />
路过了几次，去玩了玩</p>
  </li>
  <li>
    <p>青岛<br />
19 年十一，去了下青岛，强烈推荐啤酒博物馆</p>
  </li>
  <li>
    <p>成都<br />
回了几次四川，和朋友聚了聚</p>
  </li>
  <li>
    <p><del>腾冲</del><br />
因为<a href="http://www2.zhihu.com/question/60166769/answer/949638454">我的团长我的团，想去拍摄地腾冲玩一玩</a>，本来机票都买好了，不过因为疫情没去成，希望以后还有机会</p>
  </li>
  <li>
    <p>重庆<br />
江城</p>
  </li>
</ol>

<h4 id="人">人</h4>

<h5 id="友情">友情</h5>

<p>世界真是奇妙，在不同的地方总是能遇到一些相似的人，感谢</p>

<h5 id="感情">感情</h5>

<p>哎，绕不过的话题</p>

<p>随着在北京待的时间变长，热情和新鲜感逐渐被消磨</p>

<ul>
  <li>周一到周五，每天晚上 9 点多回到出租屋玩手机，第二天接着上班</li>
  <li>周末也不怎么出门，吃饭、睡觉、玩手机</li>
</ul>

<p>一个人的生活，变得挺无聊的，也想能找到一个人，但是挺难的。因此待久了就想逃离，想去另外一个城市</p>

<p>随着年龄增长，家里也会偶尔催，可我这样的人再也没有那种运气了吧</p>

<p>不过有人也说“<em>一个人都过不好，怎么过好两个人</em>”，想想也对，可能生活无聊的原因不在一个人还是两个人</p>

<h1 id="以后">以后</h1>

<p>关于以后，<a href="https://hate13.com/2019/10/01/Next.html">平时也立了很多 flag 了</a>，不重复了</p>

<p>加油啊，三年后再来看 👊</p>]]></content><author><name>朱元朝</name><email>452181625@qq.com</email></author><category term="人生" /><summary type="html"><![CDATA[2017/07/05 ~ 2020/07/04 时间很快，仿佛昨天才毕业，今天就已工作三年了]]></summary></entry><entry><title type="html">电脑组装</title><link href="https://hate13.com/2020/06/26/%E7%94%B5%E8%84%91%E7%BB%84%E8%A3%85.html" rel="alternate" type="text/html" title="电脑组装" /><published>2020-06-26T00:00:00+00:00</published><updated>2020-06-26T00:00:00+00:00</updated><id>https://hate13.com/2020/06/26/%E7%94%B5%E8%84%91%E7%BB%84%E8%A3%85</id><content type="html" xml:base="https://hate13.com/2020/06/26/%E7%94%B5%E8%84%91%E7%BB%84%E8%A3%85.html"><![CDATA[<p>放假无聊，想玩玩游戏，但是没有电脑</p>

<p>于是想着配台电脑，完美地错过了 618，拼多多真香 -_-||</p>

<p><img src="https://hate13-blog-1251885630.cos.ap-chengdu.myqcloud.com/amd_r5.png" alt="amd-r5" /></p>

<!--more-->

<h2 id="需求">需求</h2>

<p>只想玩玩一般的游戏，加上可能在北京待不了太久了，所以大部分配件都用最便宜的就好</p>

<p>等以后稳定了点儿，再慢慢升级吧</p>

<p>除了 CPU，之前都用的是 intel，这次试一试 amd，amd yes ???</p>

<h2 id="配置单">配置单</h2>

<p>总价 <strong>3500¥</strong> 左右</p>

<ul>
  <li>CPU AMD 3600X</li>
  <li>主板 B450m-迫击炮</li>
  <li>显卡 影驰 GTX750ti 2G</li>
  <li>内存 威龙 8G 3200</li>
  <li>SSD 金士顿 240G SSD</li>
  <li>红米显示器</li>
  <li>电源 酷冷战剑 2 500w</li>
  <li>机箱 大水牛</li>
  <li>网卡 TP-LINK 6280 1300M</li>
  <li>键盘 雷柏 v500 青轴</li>
  <li>鼠标 飞利浦</li>
</ul>

<h2 id="装机">装机</h2>

<p>第一次装机，比想象中的麻烦一点，不过还算顺利，一次点亮</p>

<p>装系统则比较麻烦，需要制作 U 盘启动盘，工作电脑是 mac，刚开始用 <a href="https://www.balena.io/etcher/">balenaEtcher</a> 有一些问题</p>

<p>后来专门用 virtualBox 装了个 windows 虚拟机，然后在虚拟机里面使用 <a href="https://rufus.ie/">rufus</a> 才搞定</p>]]></content><author><name>朱元朝</name><email>452181625@qq.com</email></author><category term="生活" /><summary type="html"><![CDATA[放假无聊，想玩玩游戏，但是没有电脑 于是想着配台电脑，完美地错过了 618，拼多多真香 -_-||]]></summary></entry><entry><title type="html">关于读书</title><link href="https://hate13.com/2020/03/21/%E5%85%B3%E4%BA%8E%E8%AF%BB%E4%B9%A6.html" rel="alternate" type="text/html" title="关于读书" /><published>2020-03-21T00:00:00+00:00</published><updated>2020-03-21T00:00:00+00:00</updated><id>https://hate13.com/2020/03/21/%E5%85%B3%E4%BA%8E%E8%AF%BB%E4%B9%A6</id><content type="html" xml:base="https://hate13.com/2020/03/21/%E5%85%B3%E4%BA%8E%E8%AF%BB%E4%B9%A6.html"><![CDATA[<p><a href="https://www.zhihu.com/question/25564898">读书的意义是什么？</a></p>

<!--more-->

<p>大学之前，我基本没看过什么书。</p>

<p>在大学前三年，一样地，也基本没看过书，当时一直在搞 ACM，花了很多时间学习各种竞赛算法。</p>

<p>大三到大四，由于需要找工作，当时看了很多技术书，其中有经典的计算机基础书籍，比如<a href="https://book.douban.com/subject/5333562/">«深入理解计算机系统»</a>，也有一些工程类的书，比如<a href="https://book.douban.com/subject/25723064/">«大型网站技术架构»</a>，学到了很多计算机知识。</p>

<p>毕业到工作一年左右，也看过一些书，也都是技术相关的。</p>

<p>在很长一段时间内，感觉自己陷入了一个极端。只“相信”技术书，对于一些非技术类的书，感觉内容都比较空，不知所云，毫无用处。不像技术书那么“实在”，能让我在看完后，真真切切地学到很多东西。</p>

<p>后来，工作上越来越忙，连技术书也不怎么看了，虽然手机里一直存着很多想看的书的 pdf，但都没时间看。</p>

<p>再后来，微信推出了一个<a href="https://weread.qq.com/">微信读书 App</a>，觉得挺好用的。无聊之余，开始强迫自己看一些书，特别是非技术类的。</p>

<p>读完的第一本非技术书是杨洁导演的<a href="https://book.douban.com/subject/20424572/">«敢问路在何方-我的30年西游路»</a>，讲述的是 86 版西游记的拍摄历程，看完之后，深感不易，“致敬，整个拍摄过程又何尝不是历经了九九八十一难呢”。</p>

<p>慢慢地，后来又陆陆续续地看了一些书，大多也都是非技术类的，比如：</p>

<ul>
  <li>
    <p><a href="https://book.douban.com/subject/33477229/">上帝掷骰子吗？ : 量子物理史话</a></p>
  </li>
  <li>
    <p><a href="https://book.douban.com/subject/25985021/">人类简史 : 从动物到上帝</a></p>
  </li>
  <li>
    <p><a href="https://book.douban.com/subject/6798611/">史蒂夫·乔布斯传</a></p>
  </li>
  <li>
    <p><a href="https://book.douban.com/subject/1041482/">万历十五年</a></p>
  </li>
  <li>
    <p><a href="https://book.douban.com/subject/5414391/">寻路中国 : 从乡村到工厂的自驾之旅</a></p>
  </li>
</ul>

<p>虽然我现在也说不清楚读这些书能给我带来什么实质的好处，甚至读完就忘得差不多了。</p>

<p>但在这个过程中，能感受作者的一些思想、了解书中主人公的经历，觉得挺好的。</p>

<p>或许在未来的某一天，我会因此受益。</p>]]></content><author><name>朱元朝</name><email>452181625@qq.com</email></author><category term="读书" /><summary type="html"><![CDATA[读书的意义是什么？]]></summary></entry><entry><title type="html">面试常见手写代码总结</title><link href="https://hate13.com/2020/03/21/%E9%9D%A2%E8%AF%95%E5%B8%B8%E8%A7%81%E6%89%8B%E5%86%99%E4%BB%A3%E7%A0%81%E6%80%BB%E7%BB%93.html" rel="alternate" type="text/html" title="面试常见手写代码总结" /><published>2020-03-21T00:00:00+00:00</published><updated>2020-03-21T00:00:00+00:00</updated><id>https://hate13.com/2020/03/21/%E9%9D%A2%E8%AF%95%E5%B8%B8%E8%A7%81%E6%89%8B%E5%86%99%E4%BB%A3%E7%A0%81%E6%80%BB%E7%BB%93</id><content type="html" xml:base="https://hate13.com/2020/03/21/%E9%9D%A2%E8%AF%95%E5%B8%B8%E8%A7%81%E6%89%8B%E5%86%99%E4%BB%A3%E7%A0%81%E6%80%BB%E7%BB%93.html"><![CDATA[<!--more-->

<h2 id="排序"><a href="https://hate13.com/2020/01/10/ACM-常用算法.html#排序">排序</a></h2>

<h2 id="贪心">贪心</h2>

<h2 id="二分">二分</h2>

<h3 id="求两个有序数组的第-k-大">求两个有序数组的第 K 大</h3>

<h2 id="二指针">二指针</h2>

<h3 id="最长不重复子串"><a href="https://hate13.com/2020/01/10/LeetCode-%E9%A2%98%E8%A7%A3.html#3-%E6%97%A0%E9%87%8D%E5%A4%8D%E5%AD%97%E7%AC%A6%E7%9A%84%E6%9C%80%E9%95%BF%E5%AD%90%E4%B8%B2">最长不重复子串</a></h3>

<h4 id="调整数组顺序使奇数位于偶数前面"><a href="https://hate13.com/2020/01/10/LeetCode-%E9%A2%98%E8%A7%A3.html#%E9%9D%A2%E8%AF%95%E9%A2%9821-%E8%B0%83%E6%95%B4%E6%95%B0%E7%BB%84%E9%A1%BA%E5%BA%8F%E4%BD%BF%E5%A5%87%E6%95%B0%E4%BD%8D%E4%BA%8E%E5%81%B6%E6%95%B0%E5%89%8D%E9%9D%A2">调整数组顺序使奇数位于偶数前面</a></h4>

<h2 id="链表">链表</h2>

<h3 id="单链表翻转"><a href="https://hate13.com/2020/01/10/LeetCode-%E9%A2%98%E8%A7%A3.html#206-%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8">单链表翻转</a></h3>

<h3 id="单链表判环"><a href="https://hate13.com/2020/01/10/LeetCode-题解.html#142-环形链表-ii">单链表判环</a></h3>

<h3 id="两个链表是否相交"><a href="https://hate13.com/2020/01/10/LeetCode-%E9%A2%98%E8%A7%A3.html#160-%E7%9B%B8%E4%BA%A4%E9%93%BE%E8%A1%A8">两个链表是否相交</a></h3>

<h3 id="找出两个链表的相同元素">找出两个链表的相同元素</h3>

<h3 id="有序链表转二叉搜索树">有序链表转二叉搜索树</h3>

<h2 id="队列与栈">队列与栈</h2>

<h3 id="两个栈实现队列"><a href="https://hate13.com/2020/01/10/LeetCode-%E9%A2%98%E8%A7%A3.html#232-%E7%94%A8%E6%A0%88%E5%AE%9E%E7%8E%B0%E9%98%9F%E5%88%97">两个栈实现队列</a></h3>

<h3 id="定长数组实现队列">定长数组实现队列</h3>

<h3 id="最小值栈"><a href="https://hate13.com/2020/01/10/LeetCode-题解.html#155-最小栈">最小值栈</a></h3>

<h2 id="堆">堆</h2>

<h3 id="topn"><a href="https://hate13.com/2020/01/10/ACM-%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95.html#%E5%A0%86%E6%8E%92%E5%BA%8F">TopN</a></h3>

<h2 id="哈希表">哈希表</h2>

<h3 id="lru">LRU</h3>

<h2 id="二叉树">二叉树</h2>

<h3 id="蛇形遍历二叉树">蛇形遍历二叉树</h3>

<h3 id="二叉树中相距最远距离">二叉树中相距最远距离</h3>

<h3 id="二叉树中的最长路径">二叉树中的最长路径</h3>

<h3 id="分层遍历二叉树">分层遍历二叉树</h3>

<h3 id="最大二叉搜索树">最大二叉搜索树</h3>

<h3 id="二叉搜索树的删除">二叉搜索树的删除</h3>

<h2 id="数学">数学</h2>

<h3 id="二进制">二进制</h3>

<h4 id="2-的幂"><a href="https://hate13.com/2020/01/10/LeetCode-%E9%A2%98%E8%A7%A3.html#231-2%E7%9A%84%E5%B9%82">2 的幂</a></h4>

<h4 id="1-的个数"><a href="https://hate13.com/2020/01/10/LeetCode-%E9%A2%98%E8%A7%A3.html#191-%E4%BD%8D1%E7%9A%84%E4%B8%AA%E6%95%B0">1 的个数</a></h4>

<h4 id="二分快速幂"><a href="https://hate13.com/2020/01/10/LeetCode-%E9%A2%98%E8%A7%A3.html#50-powx-n">二分快速幂</a></h4>

<h3 id="全排列">全排列</h3>

<h4 id="不考虑重复元素"><a href="https://hate13.com/2020/01/10/LeetCode-%E9%A2%98%E8%A7%A3.html#46-%E5%85%A8%E6%8E%92%E5%88%97">不考虑重复元素</a></h4>

<h4 id="有重复元素"><a href="https://hate13.com/2020/01/10/LeetCode-%E9%A2%98%E8%A7%A3.html#47-%E5%85%A8%E6%8E%92%E5%88%97-ii">有重复元素</a></h4>

<h4 id="下一个排列">下一个排列</h4>

<h3 id="素数筛选"><a href="https://hate13.com/2020/01/10/ACM-%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95.html#%E7%B4%A0%E6%95%B0%E7%AD%9B">素数筛选</a></h3>

<h2 id="字符串">字符串</h2>

<h3 id="kmp">KMP</h3>

<h2 id="其他">其他</h2>

<h3 id="中缀转后缀">中缀转后缀</h3>]]></content><author><name>朱元朝</name><email>452181625@qq.com</email></author><category term="学习" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">工作杂想</title><link href="https://hate13.com/2020/03/06/%E5%B7%A5%E4%BD%9C%E6%9D%82%E6%83%B3.html" rel="alternate" type="text/html" title="工作杂想" /><published>2020-03-06T00:00:00+00:00</published><updated>2020-03-06T00:00:00+00:00</updated><id>https://hate13.com/2020/03/06/%E5%B7%A5%E4%BD%9C%E6%9D%82%E6%83%B3</id><content type="html" xml:base="https://hate13.com/2020/03/06/%E5%B7%A5%E4%BD%9C%E6%9D%82%E6%83%B3.html"><![CDATA[<p>最近感觉在工作中遇到了很多问题，非技术问题，感觉需要好好反思、总结一下</p>

<p><img src="https://hate13-blog-1251885630.cos.ap-chengdu.myqcloud.com/reflect_on.jpg" alt="反省" /></p>

<!--more-->

<h2 id="多思考">多思考</h2>

<h2 id="多沟通">多沟通</h2>

<h2 id="多推进">多推进</h2>]]></content><author><name>朱元朝</name><email>452181625@qq.com</email></author><category term="工作" /><summary type="html"><![CDATA[最近感觉在工作中遇到了很多问题，非技术问题，感觉需要好好反思、总结一下]]></summary></entry><entry><title type="html">ACM 常用算法</title><link href="https://hate13.com/2020/01/10/ACM-%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95.html" rel="alternate" type="text/html" title="ACM 常用算法" /><published>2020-01-10T00:00:00+00:00</published><updated>2020-01-10T00:00:00+00:00</updated><id>https://hate13.com/2020/01/10/ACM%20%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95</id><content type="html" xml:base="https://hate13.com/2020/01/10/ACM-%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95.html"><![CDATA[<p><a href="https://zh.wikipedia.org/zh-sg/%E5%9B%BD%E9%99%85%E5%A4%A7%E5%AD%A6%E7%94%9F%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AB%9E%E8%B5%9B">ACM</a> 打酱油选手，简单复习一下已经忘了很久的常用算法</p>

<p><img src="https://hate13-blog-1251885630.cos.ap-chengdu.myqcloud.com/acm.jpg" alt="acm" /></p>

<!--more-->

<h1 id="基础算法">基础算法</h1>

<h2 id="枚举">枚举</h2>

<p>有些问题不好直接求解答案，但是若给出答案，很容易验证答案是否正确，此时就可以枚举答案范围内的所有值进行验证</p>

<h2 id="模拟">模拟</h2>

<h3 id="简单">简单</h3>

<h3 id="复杂">复杂</h3>

<h2 id="递归与分治">递归与分治</h2>

<p>分治是指将一个复杂的问题拆分为多个子问题，先递归对这些子问题求解，然后再将子问题的解合并为最终的解</p>

<p>典型的问题就是 <a href="https://hate13.com/2020/01/10/ACM-%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95.html#%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F">归并排序</a></p>

<h2 id="构造">构造</h2>

<h2 id="倍增">倍增</h2>

<h2 id="前缀和">前缀和</h2>

<p>前缀和是一种预处理手段，在某些情况能大大降低查询的时间复杂度</p>

<p>ps: 下标从 1 开始要好写一点，不用刻意处理数组边界</p>

<h3 id="一维">一维</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 一维：sum[i] 表示前 i 项的和</span>
<span class="c1">// 递推：sum[i] = sum[i - 1] + a[i]</span>
<span class="c1">// 查询：sum[l..r] = sum[1..r] - sum[1..l - 1]</span>
<span class="kt">void</span> <span class="nf">pre_solve_one</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">data</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span> <span class="c1">// 1..5</span>

    <span class="kt">int</span> <span class="n">sum</span><span class="p">[</span><span class="n">N</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">sum</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">sum</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
    <span class="p">}</span>

    <span class="c1">// sum[1..5] = sum[5] - sum[0] = 17</span>
    <span class="c1">// sum[3..5] = sum[5] - sum[2] = 11</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">sum</span><span class="p">[</span><span class="mi">5</span><span class="p">],</span> <span class="n">sum</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">-</span> <span class="n">sum</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="二维">二维</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#define N 100
</span>
<span class="c1">// 二维：sum[i][j] 表示从左上角 (1,1) 开始到坐标 (i, j) 之间的元素和</span>
<span class="c1">// 递推：sum[i][j] = sum[i - 1][j] + sum[i][j - 1] + a[i][j] - sum[i - 1][j - 1]</span>
<span class="c1">// 查询：sum[(x1,y1)..(x2,y2)] = sum[x2][y2] - sum[x1-1][y2] - sum[x1][y2-1] + sum[x1-1][y1-1]</span>
<span class="c1">//</span>
<span class="c1">// 举例：</span>
<span class="c1">// (1,1) | (1,2) (1,3) (1,4)</span>
<span class="c1">// (2,1) | (2,2) (2,3) (2,4)</span>
<span class="c1">// (3,1) | (3,2) (3,3) (3,4)</span>
<span class="c1">// -------------------</span>
<span class="c1">// (4,1) | (4,2) (4,3) (4,4)</span>
<span class="c1">// (5,1) | (5,2) (5,3) (5,4)</span>
<span class="c1">//</span>
<span class="c1">// sum[(4,2)..(5,3)]</span>
<span class="c1">//  = sum[(1,1)..(5,3)] - sum[(1,1)..(3,3)] - sum[(1,1)..(5,1)] + sum[(1,1)..(3,1)]</span>
<span class="c1">//  = sum[5][3] - sum[3][3] - sum[5][1] + sum[3][1]</span>
<span class="kt">void</span> <span class="nf">pre_solve_two</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span> <span class="n">m</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">data</span><span class="p">[][</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
            <span class="p">{},</span>
            <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span>  <span class="mi">2</span><span class="p">,</span>  <span class="mi">3</span><span class="p">,</span>  <span class="mi">4</span><span class="p">},</span>
            <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span>  <span class="mi">6</span><span class="p">,</span>  <span class="mi">7</span><span class="p">,</span>  <span class="mi">8</span><span class="p">},</span>
            <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span>  <span class="mi">10</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">12</span><span class="p">},</span>
            <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">14</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">16</span><span class="p">},</span>
            <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">17</span><span class="p">,</span> <span class="mi">18</span><span class="p">,</span> <span class="mi">19</span><span class="p">,</span> <span class="mi">20</span><span class="p">},</span>
    <span class="p">};</span>
    <span class="kt">int</span> <span class="n">sum</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">sum</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">sum</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">sum</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">-</span> <span class="n">sum</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">];</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">sum</span><span class="p">[</span><span class="mi">5</span><span class="p">][</span><span class="mi">4</span><span class="p">],</span> <span class="n">sum</span><span class="p">[</span><span class="mi">5</span><span class="p">][</span><span class="mi">3</span><span class="p">]</span> <span class="o">-</span> <span class="n">sum</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">3</span><span class="p">]</span> <span class="o">-</span> <span class="n">sum</span><span class="p">[</span><span class="mi">5</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">sum</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">1</span><span class="p">]);</span> <span class="c1">// 210 66</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="树">树</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 树上前缀和：sum[i] 表示从根节点到节点 i 之间的路径权值和</span>
<span class="c1">// 如果是边权，sum(x..y) = sum[x] + sum[y] - 2 * sum[lca(x, y)]</span>
<span class="c1">// 如果是点权，sum(x..y) = sum[x] + sum[y] - 2 * sum[fa[lca(x, y)]] + data[lca(x, y)]</span>
<span class="c1">//</span>
<span class="c1">// 举例：</span>
<span class="c1">//     1</span>
<span class="c1">//    / \</span>
<span class="c1">//   2   3</span>
<span class="c1">//  / \</span>
<span class="c1">// 4   5</span>
<span class="c1">//      \</span>
<span class="c1">//       6</span>
<span class="kt">void</span> <span class="nf">pre_solve_tree</span><span class="p">()</span> <span class="p">{</span>

<span class="p">}</span>
</code></pre></div></div>

<h2 id="二指针">二指针</h2>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 顾名思义：二指针即使用两个指针进行遍历，两层循环
 * - 内层循环右指针 j 不断贪心，直到求得从下标 i 开始满足条件的最优值
 * - 外层循环左指针 i 缓慢向前移动
 *
 * 比如给定一个字符串，求不重复元素的最大区间
 *
 * 示例：
 *
 *  a b c d a e f
 * ij
 *
 *  i       j        abcd = 4
 *    i         j  bcdaef = 6
 *             ij
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
#define max(a, b) ((a) &gt; (b) ? (a) : (b))
#define N 100
</span>
<span class="kt">int</span> <span class="nf">get_max</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">len</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">ans</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">vis</span><span class="p">[</span><span class="mi">256</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">len</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">j</span> <span class="o">&lt;</span> <span class="n">len</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">vis</span><span class="p">[</span><span class="n">s</span><span class="p">[</span><span class="n">j</span><span class="p">]])</span> <span class="p">{</span>
            <span class="n">vis</span><span class="p">[</span><span class="n">s</span><span class="p">[</span><span class="n">j</span><span class="o">++</span><span class="p">]]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">ans</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">ans</span><span class="p">,</span> <span class="n">j</span> <span class="o">-</span> <span class="n">i</span><span class="p">);</span>
        <span class="n">vis</span><span class="p">[</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span> <span class="p">()</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="n">s</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"abcdaef"</span><span class="p">;</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">get_max</span><span class="p">(</span><span class="n">s</span><span class="p">));</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="二分">二分</h2>

<h3 id="二分查找">二分查找</h3>

<p>在网上搜索二分查找，可以看到各式各样的写法，其中一些写法是有问题的，参考：<a href="https://www.zhihu.com/question/36132386">二分查找有几种写法</a></p>

<p>推荐下面这种“左开右闭”的写法，另外注意二分查找的前提是数组有序</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="c1">// 二分查找</span>
<span class="c1">// 若存在返回下标，否则返回-1</span>
<span class="c1">// 分析：</span>
<span class="c1">//   如果 key = data[m]，表示找到了直接返回</span>
<span class="c1">//   如果 key &lt; data[m]，表示 key 可能位于左区间 [l, m)</span>
<span class="c1">//   如果 key &gt; data[m]，表示 key 可能位于右区间 [m + 1, r)</span>
<span class="kt">int</span> <span class="nf">binarySearch</span><span class="p">(</span><span class="kt">int</span> <span class="n">data</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">key</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">l</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">n</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">l</span> <span class="o">&lt;</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// 防溢出：l + ((r - l) &gt;&gt; 1)</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">key</span> <span class="o">==</span> <span class="n">data</span><span class="p">[</span><span class="n">m</span><span class="p">])</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">m</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">key</span> <span class="o">&lt;</span> <span class="n">data</span><span class="p">[</span><span class="n">m</span><span class="p">])</span> <span class="p">{</span>
            <span class="n">r</span> <span class="o">=</span> <span class="n">m</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">l</span> <span class="o">=</span> <span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// 返回 &gt;= key 的首个元素下标</span>
<span class="c1">// 区间左开右闭，比如：[l......m......r)</span>
<span class="c1">// 分析：</span>
<span class="c1">//   如果 key &lt;= data[m]，首个大于等于 key 的首个元素一定位于 [l, m]，继续查找左区间 [l, m)。如果最终 [l, m) 中的元素都小于 key 咋办？没关系，这会使得二分过程中 l 不断向右 (即 m) 逼近，最终 "l = m + 1" 使得 l = m</span>
<span class="c1">//   如果 key &gt;  data[m]，左区间 [l, m] 都比 key 小，不可能了，继续查找右区间 [m+1, r)</span>
<span class="c1">//</span>
<span class="c1">// 这种情况下，可能最后不存在 key，不断逼近，l 停止的位置就是刚好大于 key 的数的位置</span>
<span class="kt">int</span> <span class="nf">lowerBound</span><span class="p">(</span><span class="kt">int</span> <span class="n">data</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">key</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">l</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">n</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">l</span> <span class="o">&lt;</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">key</span> <span class="o">&lt;=</span> <span class="n">data</span><span class="p">[</span><span class="n">m</span><span class="p">])</span> <span class="p">{</span>
            <span class="n">r</span> <span class="o">=</span> <span class="n">m</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">l</span> <span class="o">=</span> <span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">l</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// 返回 &gt; key 的首个元素下标</span>
<span class="c1">// 区间左开右闭，比如：[l......m......r)</span>
<span class="c1">// 分析：</span>
<span class="c1">//   如果 key &gt;= data[m]，答案显然不可能位于 [l, m]，继续查找右区间 [m+1, r)</span>
<span class="c1">//   如果 key  &lt; data[m]，则答案一定位于 [l, m]，继续查找左区间 [l, m)。如果最终 [l, m) 中的元素都小于 key 咋办？同上</span>
<span class="c1">//</span>
<span class="c1">// 在这种情况下，停止时 l 一定是 key 后面，可能存在 key，也可能不存在 key</span>
<span class="kt">int</span> <span class="nf">upperBound</span><span class="p">(</span><span class="kt">int</span> <span class="n">data</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">key</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">l</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">n</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">l</span> <span class="o">&lt;</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">key</span> <span class="o">&gt;=</span> <span class="n">data</span><span class="p">[</span><span class="n">m</span><span class="p">])</span> <span class="p">{</span>
            <span class="n">l</span> <span class="o">=</span> <span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">r</span> <span class="o">=</span> <span class="n">m</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">l</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">data</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">};</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">binarySearch</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">5</span><span class="p">),</span> <span class="n">binarySearch</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">8</span><span class="p">));</span> <span class="c1">// -1 7</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">lowerBound</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">lowerBound</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">5</span><span class="p">));</span> <span class="c1">// 2 5</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">upperBound</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">upperBound</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">6</span><span class="p">));</span> <span class="c1">// 5 7</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="二分答案">二分答案</h3>

<p>参考上面的<a href="https://hate13.com/2020/01/10/ACM-%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95.html#%E6%9E%9A%E4%B8%BE">枚举</a>，如果答案满足一定的单调性，则可以通过二分优化</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="n">bool</span> <span class="nf">check</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">find</span><span class="p">(</span><span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">l</span> <span class="o">&lt;</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">check</span><span class="p">(</span><span class="n">m</span><span class="p">))</span> <span class="p">{</span>
            <span class="c1">// ans = m; // 可能有时不太好处理这种左开右闭写法的边界问题，干脆直接加一个 ans 变量记录答案</span>
            <span class="n">r</span> <span class="o">=</span> <span class="n">m</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">l</span> <span class="o">=</span> <span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">l</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="排序">排序</h2>

<h3 id="冒泡排序">冒泡排序</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 冒泡排序
 *
 * 时间复杂度 O(n^2)，空间复杂度 O(1)，稳定排序
 * 思路：从小到大排序，每趟从左到右遍历，遍历过程中比较相邻两个元素，如果左边大于右边则交换，结束时归位一个最大值到右边，重复 n-1 趟使得所有值归位
 * 优化：可以检查每趟遍历是否发生过交换，如果一次交换都没有，表示数组已经有序了，可以提前终止外层循环，如果一开始就有序则一趟遍历就结束了
 *
 * 举例：
 * 1 8 2 9 5 7 6 3 4
 *
 * 1 2 8 9 5 7 6 3 4  9 &gt; 5，交换
 * 1 2 8 5 9 7 6 3 4  9 &gt; 7，交换
 * 1 2 8 5 7 9 6 3 4  9 &gt; 6，交换
 * 1 2 8 5 7 6 9 3 4  9 &gt; 3，交换
 * 1 2 8 5 7 6 3 9 4  9 &gt; 4，交换
 * 1 2 8 5 7 6 3 4 9  归位元素 9，看起来就好像把 9 从左边冒泡到右边
 * 
 * 1 2 8 5 7 6 3 4 9  8 &gt; 5，交换
 * 1 2 5 8 7 6 3 4 9  8 &gt; 7，交换
 * 1 2 5 7 8 6 3 4 9  8 &gt; 6，交换
 * 1 2 5 7 6 8 3 4 9  8 &gt; 3，交换
 * 1 2 5 7 6 3 8 4 9  8 &gt; 4，交换
 * 1 2 5 7 6 3 4 8 9  归位元素 8
 *
 * ...
 *
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">void</span> <span class="nf">bubble_sort</span><span class="p">(</span><span class="kt">int</span> <span class="n">data</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>         <span class="c1">// 循环 n-1 次，每次循环归位一个元素到 n-j-1 位置(下标从 0 开始)</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">-</span> <span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 每趟冒泡时只需要考虑 [0, n-j-1] 区间，因为后面的元素都已排序，完成后归位到 n-j-1 处</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span> <span class="p">{</span>
                <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
                <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">];</span>
                <span class="n">data</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">a</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">};</span>
    <span class="n">bubble_sort</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">9</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="选择排序">选择排序</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 选择排序
 *
 * 时间复杂度 O(n^2)，空间复杂度 O(1)，不稳定排序
 * 思路：从小到大排序，每趟循环直接选择一个最小值元素，然后放到对应位置即可
 * 对比：和冒泡不同的是选择排序是找到最值元素和直接交换，而不是从左到右冒泡过去，相对来说选择排序交换次数更小，但冒泡排序可以通过检测是否交换进行一点小优化
 * 参考：https://www.zhihu.com/question/21027517
 *
 * 举例：
 * 7 8 2 9 5 1 6 3 4
 *
 * 1 8 2 9 5 7 6 3 4  第一趟循环找到最小值为 1，交换 7 和 1，归位 1
 * 1 2 8 9 5 7 6 3 4  第二趟循环找到最小值为 2，交换 8 和 2，归位 2
 * 1 2 3 9 5 7 6 8 4  第三趟循环找到最小值为 3，交换 8 和 3，归位 3
 * 1 2 3 4 5 7 6 8 9  第四趟循环找到最小值为 4，交换 9 和 4，归位 4
 *
 * ...
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">void</span> <span class="nf">select_sort</span><span class="p">(</span><span class="kt">int</span> <span class="n">data</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">min_k</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">data</span><span class="p">[</span><span class="n">min_k</span><span class="p">])</span> <span class="p">{</span> <span class="c1">// 判断右边是否有更小的元素</span>
                <span class="n">min_k</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">min_k</span> <span class="o">!=</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 如果右边有更小的元素，则交换归位第 i 个元素</span>
            <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
            <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">min_k</span><span class="p">];</span>
            <span class="n">data</span><span class="p">[</span><span class="n">min_k</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">a</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">};</span>
    <span class="n">select_sort</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">9</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

</code></pre></div></div>

<h3 id="插入排序">插入排序</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 插入排序
 *
 * 时间复杂度O(n^2)，空间复杂度O(1)，稳定排序
 * 将数组划分为有序区和无序区，然后每趟从无序区中取出元素插入有序区即可，每趟归位一个元素
 *
 * 举例：
 *
 *     i
 * 1 | 8 2 9 5 7 6 3 4
 *
 *       i
 * 1 8 | 2 9 5 7 6 3 4
 *
 *         i
 * 1 2 8 | 9 5 7 6 3 4
 *
 *           i
 * 1 2 8 9 | 5 7 6 3 4
 *
 *             i
 * 1 2 5 8 9 | 7 6 3 4
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">void</span> <span class="nf">insert_sort</span><span class="p">(</span><span class="kt">int</span> <span class="n">data</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 从第 2 个元素开始往有序区插入(单个元素肯定有序)</span>
        <span class="kt">int</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>        <span class="c1">// 当前待插入的元素</span>
        <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">j</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">tmp</span> <span class="o">&lt;</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="p">{</span> <span class="c1">// 往前遍历有序区，寻找插入位置</span>
            <span class="n">data</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>        <span class="c1">// 如果待插入元素小于当前元素，则将当前元素往后移一位</span>
            <span class="n">j</span><span class="o">--</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">data</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">tmp</span><span class="p">;</span> <span class="c1">// 插入到指定位置</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">a</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">};</span>
    <span class="n">insert_sort</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">9</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="归并排序">归并排序</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 归并排序
 *
 * 稳定时间复杂度 O(nlogn)，空间复杂度 O(n)，稳定排序
 * 思路：利用分治的思路，将数组不断二分，先排序左半部分，再排序右半部分，最后二路归并
 *
 * 举例：
 * [1 3 5 7] + [2 4 6 8 9] =&gt; [1 2 3 4 5 6 7 8 9]
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#define N 10010
</span><span class="kt">int</span> <span class="n">tmp</span><span class="p">[</span><span class="n">N</span><span class="p">];</span> <span class="c1">// 临时保存归并结果，每次归并 [l, m, r] 时即占用 [l, r] 区间</span>

<span class="kt">void</span> <span class="nf">merge</span><span class="p">(</span><span class="kt">int</span> <span class="n">data</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">m</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">l</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">k</span> <span class="o">=</span> <span class="n">l</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;=</span> <span class="n">m</span> <span class="o">&amp;&amp;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">r</span><span class="p">)</span> <span class="n">tmp</span><span class="p">[</span><span class="n">k</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">?</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="o">++</span><span class="p">]</span> <span class="o">:</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="o">++</span><span class="p">];</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">)</span> <span class="n">tmp</span><span class="p">[</span><span class="n">k</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="o">++</span><span class="p">];</span>       <span class="c1">// 左半部分更长</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">j</span> <span class="o">&lt;=</span> <span class="n">r</span><span class="p">)</span> <span class="n">tmp</span><span class="p">[</span><span class="n">k</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="o">++</span><span class="p">];</span>       <span class="c1">// 右半部分更长</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">k</span> <span class="o">=</span> <span class="n">l</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;=</span> <span class="n">r</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">)</span> <span class="n">data</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">tmp</span><span class="p">[</span><span class="n">k</span><span class="p">];</span> <span class="c1">// 归并完成后赋值到原数据</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">merge_sort</span><span class="p">(</span><span class="kt">int</span> <span class="n">data</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">&lt;</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>                    <span class="c1">// l = r 代表一个元素</span>
        <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span>
        <span class="n">merge_sort</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">m</span><span class="p">);</span>     <span class="c1">// 左半部分排序</span>
        <span class="n">merge_sort</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span> <span class="c1">// 右半部分排序</span>
        <span class="n">merge</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>       <span class="c1">// 合并两部分</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">a</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">};</span>
    <span class="n">merge_sort</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="快速排序">快速排序</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 快速排序
 *
 * 不稳定排序
 * 平均时间复杂度可证明为：O(N * logN)，最差时间复杂度：O(N^2)
 * 空间复杂度：O(1)，若考虑栈最好情况为为：O(logN)，最差为：O(N)
 * 复杂度分析：http://blog.csdn.net/hn_gsf/article/details/52249621
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">void</span> <span class="nf">swap</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">l</span><span class="p">];</span>
    <span class="n">data</span><span class="p">[</span><span class="n">l</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">r</span><span class="p">];</span>
    <span class="n">data</span><span class="p">[</span><span class="n">r</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/*
 * 实现方式 1
 *
 * 思想：每次在待排序区间 [l, r] 选定一个基准值 data[x]，将比 data[x] 小的数放在 data[x] 左边，比 data[x] 大的数放在右边，经过处理后 data[x] 的位置就唯一了，其下标记为 m，然后递归处理区间 [l, m-1]、[m+1, r]
 * 实现：每次使用两个指针 i=l, j=r，循环处理，j-- 向左，当找到比 data[x] 小的数将其交换到左边，i++ 向右，当找到比 data[i] 大的数将其交换到右边，当 i=j 时即满足 data[l..i-1] &lt; data[i=j] &lt; data[j+1..r]
 *
 * 在最优情况下，递归深度为 logN 层，每层处理的时间复杂度为 O(N)，即总复杂度为 O(N * logN)
 * 在最差情况下，即待排序数组为正序或倒序时，需要递归 n-1 层，即每次划分的时候只单向移动一个单位，即分治退化成链，每层需要比较 n-i 次，总时间复杂度为 O(N^2)
 *
 * 举例：
 *
 * 取 data[x]=data[l]=5
 *
 * l               r
 * i               j
 * 5 9 8 2 4 7 1 3 6
 *
 * i             j    &lt;=
 * 5 9 8 2 4 7 1 3 6
 * 3 9 8 2 4 7 1 5 6  找到第一个比 5 小的数 3，交换 3 到左边
 *
 *   i           j    =&gt;
 * 3 9 8 2 4 7 1 5 6
 * 3 5 8 2 4 7 1 9 6  找到第一个比 5 大的数 9，交换 9 到右边
 *
 *   i         j      &lt;=
 * 3 5 8 2 4 7 1 9 6
 * 3 1 8 2 4 7 5 9 6  找到第一个比 5 小的数 1，交换 1 到左边
 *
 *     i       j      =&gt;
 * 3 1 8 2 4 7 5 9 6
 * 3 1 5 2 4 7 8 9 6  找到第一个比 5 大的数 8，交换 8 到右边
 *
 *     i   j          &lt;=
 * 3 1 5 2 4 7 8 9 6
 * 3 1 4 2 5 7 8 9 6  找到第一个比 5 小的数 4，交换 4 到左边
 *
 *         ij
 * 3 1 4 2 5 7 8 9 6
 *
 * 具体实现上有点细微的区别，每次交换的数都是 data[x]，所以并不需要真正交换，直接赋值即可，最后将 i=j 处赋值回 data[x] 即可：
 *
 * l               r
 * i               j
 * 5 9 8 2 4 7 1 3 6
 *
 * i             j
 * 3 9 8 2 4 7 1 _ 6
 *
 *   i           j
 * 3 _ 8 2 4 7 1 9 6
 *
 *   i         j
 * 3 1 8 2 4 7 _ 9 6
 *
 *     i       j
 * 3 1 _ 2 4 7 8 9 6
 *
 *     i   j
 * 3 1 4 2 _ 7 8 9 6
 *
 *         ji
 * 3 1 4 2 5 7 8 9 6
 *
 * 最差时间复杂度举例：
 *
 * l               r
 * i               j
 * 1 2 3 4 5 6 7 8 9
 *
 *   i             j
 *   2 3 4 5 6 7 8 9
 *
 *     i           j
 *     3 4 5 6 7 8 9
 *
 * ...
 *
 */</span>
<span class="kt">void</span> <span class="n">quick_sort_1</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">&lt;</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 此处可随机基准值防止最坏情况：交换 l 和后面某个位置的值</span>
        <span class="c1">// int pivot = (l + r) &gt;&gt; 1;</span>
        <span class="c1">// swap(data, l, pivot);</span>

        <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">l</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="n">r</span><span class="p">,</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">l</span><span class="p">];</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">!=</span> <span class="n">j</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">j</span> <span class="o">&gt;</span> <span class="n">i</span> <span class="o">&amp;&amp;</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">tmp</span><span class="p">)</span> <span class="n">j</span><span class="o">--</span><span class="p">;</span> <span class="c1">// 右边如果比基准值大，则不需要交换，j 继续向左</span>
            <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>                   <span class="c1">// 找到第一个需要交换的 j，交换到左边</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span> <span class="o">&amp;&amp;</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">tmp</span><span class="p">)</span> <span class="n">i</span><span class="o">++</span><span class="p">;</span> <span class="c1">// 左边如果比基准值小，则不需要交换，i 继续向右</span>
            <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>                   <span class="c1">// 找到第一个需要交换的 i，交换到右边</span>
        <span class="p">}</span>
        <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">tmp</span><span class="p">;</span>
        <span class="n">quick_sort_1</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
        <span class="n">quick_sort_1</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="cm">/*
 * 实现方式 2
 *
 * 实现 1 中其实是直接与基准值本身进行交换，比如：[5] 1 8 2 3 6 =&gt; 3 1 8 2 [5] 6 =&gt; 3 1 [5] 2 8 6 =&gt; 3 1 2 [5] 8 6
 *
 * 这里不同的循环将左边比基准值大的数和右边比基准值小的数进行交换，循环结束时除了基准值外满足排序要求，且此时 i=j 指向从右往左第一个比基准值小的数，于是将其和基准值交换即使得满足最终要求
 *
 * 举例：
 *
 * l               r
 * i               j
 * 5 9 8 2 4 7 1 3 6
 *
 *   i           j
 * 5 9 8 2 4 7 1 3 6  从右到左找到第一个比 5 小的数 3，从左到右找到第一个比 5 大的数，将两者进行交换
 * 5 3 8 2 4 7 1 9 6
 *
 *     i       j
 * 5 3 8 2 4 7 1 9 6
 * 5 3 1 2 4 7 8 9 6
 *
 *         ij
 * 5 3 1 2 4 7 8 9 6  循环停止时的序列，i=j，4 &lt; 5，所以直接将 5 和 data[ij] 交换
 * 4 3 1 2 5 7 8 9 6
 */</span>
<span class="kt">void</span> <span class="n">quick_sort_2</span><span class="p">(</span><span class="kt">int</span> <span class="n">data</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">&lt;</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">l</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="n">r</span><span class="p">,</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">l</span><span class="p">];</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">j</span> <span class="o">&gt;</span> <span class="n">i</span> <span class="o">&amp;&amp;</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">tmp</span><span class="p">)</span> <span class="n">j</span><span class="o">--</span><span class="p">;</span> <span class="c1">// 不需要交换，j 继续向左</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span> <span class="o">&amp;&amp;</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">tmp</span><span class="p">)</span> <span class="n">i</span><span class="o">++</span><span class="p">;</span> <span class="c1">// 不需要交换，i 继续向右</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">!=</span> <span class="n">j</span><span class="p">)</span> <span class="p">{</span>                        <span class="c1">// 交换</span>
                <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
                <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
                <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="n">swap</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span> <span class="c1">// 最后将基准值换到 i=j 处使得满足最终条件</span>
        <span class="n">quick_sort_2</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
        <span class="n">quick_sort_2</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="cm">/*
 * 实现方式 3，实现起来更简单
 *
 * 思想和方式 2 差不多，不同的时在实现上只需要用一个指针从左到右处理，遇到右边有比基准值更小的数则挨着基准值依次交换到左边，最后将基准值同最后一个比基准值小的数进行交换达到排序要求
 *
 * 举例：
 *
 * l i             r
 * 5 9 8 2 4 7 1 3 6
 *
 * l     i
 * 5 9 8 2 4 7 1 3 6  遇到一个比 5 小的数 2，交换到左边
 * 5 2 8 9 4 7 1 3 6
 *   la  i
 *
 * l la    i
 * 5 2 8 9 4 7 1 3 6  遇到一个比 5 小的数 4，依次交换到左边
 * 5 2 4 9 8 7 1 3 6
 *     la
 *
 * l   la      i
 * 5 2 4 9 8 7 1 3 6  遇到一个比 5 小的数 1，依次交换到左边
 * 5 2 4 1 8 7 9 3 6
 *       la
 *
 * l     la      i
 * 5 2 4 1 8 7 9 3 6  遇到一个比 5 小的数 3，依次交换到左边
 * 5 2 4 1 3 7 9 8 6
 *         la
 *
 * l       la      i
 * 5 2 4 1 3 7 9 8 6  last 表示比基准值小的上一个数，所以这里将其和基准值交换
 * 3 2 4 1 5 7 9 8 6
 */</span>
<span class="kt">void</span> <span class="n">quick_sort_3</span><span class="p">(</span><span class="kt">int</span> <span class="n">data</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">&lt;</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">last</span> <span class="o">=</span> <span class="n">l</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">l</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">r</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 从左向右处理</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">data</span><span class="p">[</span><span class="n">l</span><span class="p">])</span> <span class="p">{</span>       <span class="c1">// 遇到右边有比基准值更小的数则挨着基准值依次交换到左边</span>
                <span class="n">swap</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="o">++</span><span class="n">last</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="n">swap</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">last</span><span class="p">);</span> <span class="c1">// 与基准值交换</span>
        <span class="n">quick_sort_3</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">last</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
        <span class="n">quick_sort_3</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">last</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="cm">/*
 * 利用快排的思想查找第 k 大或前 k 大
 * 平均复杂度：O(n)
 *
 * 第 k 大，倒序排序
 * 第 k 小，正序排序
 */</span>
<span class="kt">int</span> <span class="n">find_kth</span><span class="p">(</span><span class="kt">int</span> <span class="n">data</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">,</span> <span class="kt">int</span> <span class="n">k</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">&lt;</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">l</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="n">r</span><span class="p">,</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">l</span><span class="p">];</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">!=</span> <span class="n">j</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">j</span> <span class="o">&gt;</span> <span class="n">i</span> <span class="o">&amp;&amp;</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">tmp</span><span class="p">)</span> <span class="n">j</span><span class="o">--</span><span class="p">;</span>
            <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span> <span class="o">&amp;&amp;</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">tmp</span><span class="p">)</span> <span class="n">i</span><span class="o">++</span><span class="p">;</span>
            <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">tmp</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">k</span> <span class="o">==</span> <span class="n">i</span><span class="p">)</span> <span class="k">return</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>                         <span class="c1">// 如果 data[i] 最终就在第 k 个数处</span>
        <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">k</span> <span class="o">&lt;</span> <span class="n">i</span><span class="p">)</span> <span class="k">return</span> <span class="n">find_kth</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">k</span><span class="p">);</span> <span class="c1">// 如果在左边，递归处理左边</span>
        <span class="k">else</span> <span class="k">return</span> <span class="n">find_kth</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">k</span><span class="p">);</span>            <span class="c1">// 如果在右边，递归处理右边</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="c1">// unreachable</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">test_quick_sort_1</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">a</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span>
    <span class="n">quick_sort_1</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">test_quick_sort_2</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">a</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span>
    <span class="n">quick_sort_2</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">test_quick_sort_3</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">a</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span>
    <span class="n">quick_sort_3</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">test_find_kth</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">a</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span>
    <span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">find_kth</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span> <span class="c1">// 这里下标从 0 开始，定义第 0 大为 9，第 1 大为 8，第 2 大为 7...</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">ret</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">test_quick_sort_1</span><span class="p">();</span>
    <span class="n">test_quick_sort_2</span><span class="p">();</span>
    <span class="n">test_quick_sort_3</span><span class="p">();</span>
    <span class="n">test_find_kth</span><span class="p">();</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="堆排序">堆排序</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 堆
 *
 * 最大堆：父节点 &gt; 左右儿子
 * 最小堆：父节点 &lt; 左右儿子
 *
 * 注意：堆不一定都是完全二叉树，只要满足节点和子节点的大小关系的二叉树就是堆，完全二叉树对应的堆叫做二叉堆，因此可直接用数组实现
 * 先利用已有元素构建的堆是一棵完全二叉树(后续的都是 push、pop，不能随机插入子节点，不影响平衡性)，因此显然平衡，复杂度为：O(logN)
 *
 * 主要操作：(前两种为内部逻辑，服务于插入、删除等操作)
 * 上浮
 * 下沉
 *
 * 初始化
 * 插入
 * 删除
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#define N 10010
</span>
<span class="k">struct</span> <span class="nc">Heap</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">size</span><span class="p">;</span>    <span class="c1">// 元素个数</span>
    <span class="kt">int</span> <span class="n">data</span><span class="p">[</span><span class="n">N</span><span class="p">];</span> <span class="c1">// 堆元素，此处为最小堆</span>

    <span class="c1">// 举例：</span>
    <span class="c1">//</span>
    <span class="c1">//        97 76 65 49 50 27 38 13</span>
    <span class="c1">// 第一趟：97 76 65 13 50 27 38 49 &lt;= 调整49所在节点</span>
    <span class="c1">// 第二趟：97 76 27 13 50 65 38 49 &lt;= 调整65所在节点</span>
    <span class="c1">// 第三趟：97 13 27 49 50 65 38 76 &lt;= 调整76所在节点</span>
    <span class="c1">// 第四趟：13 49 27 76 50 65 38 97 &lt;= 调整97所在节点</span>
    <span class="kt">void</span> <span class="n">build</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">[],</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">size</span> <span class="o">=</span> <span class="n">n</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">size</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="p">}</span>

        <span class="c1">// 根据已有数据构造堆，复杂度为：O(n)</span>
        <span class="c1">// 参考：http://blog.csdn.net/leosha/article/details/46116959</span>
        <span class="c1">// 从最后一个非叶子节点开始调整(叶子节点没必须再往下调整，已经是底端了)，因为下标从 0 开始所以 -1</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">size</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">down</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
            <span class="n">print</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 向下调整</span>
    <span class="c1">// 下标从 0 开始的左右儿子下标为 2 * rt + 1、2 * rt + 2</span>
    <span class="c1">// 下标从 1 开始其实更简单，可以同线段树写为 2 * rt、2 * rt + 1</span>
    <span class="kt">void</span> <span class="n">down</span><span class="p">(</span><span class="kt">int</span> <span class="n">rt</span><span class="p">,</span> <span class="kt">int</span> <span class="n">sz</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">l</span> <span class="o">=</span> <span class="n">rt</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span> <span class="o">|</span> <span class="mi">1</span><span class="p">;</span>
        <span class="kt">int</span> <span class="n">r</span> <span class="o">=</span> <span class="n">l</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">&gt;=</span> <span class="n">sz</span><span class="p">)</span> <span class="n">l</span> <span class="o">=</span> <span class="n">rt</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">r</span> <span class="o">&gt;=</span> <span class="n">sz</span><span class="p">)</span> <span class="n">r</span> <span class="o">=</span> <span class="n">rt</span><span class="p">;</span> <span class="c1">// trick，如果超出范围了不算取 rt 本身就行了</span>

        <span class="c1">// 此处为最小堆，如果子节点更小，交换子节点，继续向下调整，使其满足父节点 &lt; 子节点</span>
        <span class="c1">// 举例：</span>
        <span class="c1">//     9           5         5</span>
        <span class="c1">//    / \   =&gt;    / \   =&gt;  / \</span>
        <span class="c1">//   5  6        9  6      7  6</span>
        <span class="c1">//  / \         / \       / \</span>
        <span class="c1">// 7  8        7  8      9  8</span>
        <span class="kt">int</span> <span class="n">mi</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">l</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">data</span><span class="p">[</span><span class="n">r</span><span class="p">]</span> <span class="o">?</span> <span class="n">l</span> <span class="o">:</span> <span class="n">r</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="n">mi</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">data</span><span class="p">[</span><span class="n">rt</span><span class="p">])</span> <span class="p">{</span>
            <span class="n">swap</span><span class="p">(</span><span class="n">mi</span><span class="p">,</span> <span class="n">rt</span><span class="p">);</span>
            <span class="n">down</span><span class="p">(</span><span class="n">mi</span><span class="p">,</span> <span class="n">sz</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 向上调整</span>
    <span class="c1">// 添加元素时先将元素放到末尾，然后向上调整，使其满足堆的性质</span>
    <span class="kt">void</span> <span class="n">up</span><span class="p">(</span><span class="kt">int</span> <span class="n">rt</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
            <span class="c1">// 得到父节点，当下标从 1 开始时 p = rt / 2</span>
            <span class="c1">// 如果到根节点了或已经满足父节点 &lt; 子节点时停止向上调整</span>
            <span class="c1">// 举例：</span>
            <span class="c1">//     5         5         5         2</span>
            <span class="c1">//    / \       / \       / \       / \</span>
            <span class="c1">//   7  6  =&gt;  7  6  =&gt;  7  2  =&gt;  7  5</span>
            <span class="c1">//  / \       / \ /     / \ /     / \ /</span>
            <span class="c1">// 9  8      9  8 2    9  8 6    9  8 6</span>
            <span class="kt">int</span> <span class="n">p</span> <span class="o">=</span> <span class="p">(</span><span class="n">rt</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">p</span> <span class="o">==</span> <span class="n">rt</span> <span class="o">||</span> <span class="n">data</span><span class="p">[</span><span class="n">p</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">data</span><span class="p">[</span><span class="n">rt</span><span class="p">])</span> <span class="k">break</span><span class="p">;</span>
            <span class="n">swap</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">rt</span><span class="p">);</span>
            <span class="n">rt</span> <span class="o">=</span> <span class="n">p</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 添加元素</span>
    <span class="c1">// 添加到末尾，从 0 开始，下标为 size - 1，然后向上调整</span>
    <span class="kt">void</span> <span class="n">push</span><span class="p">(</span><span class="kt">int</span> <span class="n">c</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">data</span><span class="p">[</span><span class="n">size</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">c</span><span class="p">;</span>
        <span class="n">up</span><span class="p">(</span><span class="n">size</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="c1">// 添加元素到固定容量的堆中，用于计算 topN，比如最小堆可用来计算最大的 N 个元素</span>
    <span class="c1">// 先判断元素个数，如果小于堆容量，则直接将元素添加到堆尾，然后向上调整堆</span>
    <span class="c1">// 否则和堆顶元素判断</span>
    <span class="c1">//   如果比堆顶元素还小，则直接丢弃</span>
    <span class="c1">//   否则将堆顶元素赋值为当前值，然后向下调整堆</span>
    <span class="kt">void</span> <span class="n">push_2</span><span class="p">(</span><span class="kt">int</span> <span class="n">c</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">c</span> <span class="o">&lt;=</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">return</span><span class="p">;</span>
        <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">c</span><span class="p">;</span>
        <span class="n">down</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="c1">// 弹出堆顶元素(最小值)</span>
    <span class="c1">// 将最后一个元素赋值到堆顶，然后向下调整</span>
    <span class="c1">// 举例：</span>
    <span class="c1">//     5         8        6</span>
    <span class="c1">//    / \       / \      / \</span>
    <span class="c1">//   7  6  =&gt;  7  6  =&gt; 7  8</span>
    <span class="c1">//  / \       /        /</span>
    <span class="c1">// 9  8      9        9</span>
    <span class="kt">int</span> <span class="n">pop</span><span class="p">()</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="o">--</span><span class="n">size</span><span class="p">];</span>
        <span class="n">down</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">c</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// 堆排序，复杂度：O(nlogn)，空间复杂度：O(1)，不稳定排序</span>
    <span class="c1">// 不断地交换堆顶元素到堆的最后一个元素，然后向下调整即可</span>
    <span class="c1">// 由于是最小堆，交换后最后的元素最小，为倒序排序</span>
    <span class="c1">// 注意这里是原地排序，会破坏堆的结构</span>
    <span class="kt">void</span> <span class="n">sort</span><span class="p">()</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">sz</span> <span class="o">=</span> <span class="n">size</span><span class="p">;</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">sz</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">swap</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">--</span><span class="n">sz</span><span class="p">);</span>
            <span class="n">down</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sz</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="n">swap</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="kt">int</span> <span class="n">j</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
        <span class="n">data</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="n">print</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">size</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="p">}</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="p">}</span>

<span class="p">};</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">a</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">97</span><span class="p">,</span> <span class="mi">76</span><span class="p">,</span> <span class="mi">65</span><span class="p">,</span> <span class="mi">49</span><span class="p">,</span> <span class="mi">50</span><span class="p">,</span> <span class="mi">27</span><span class="p">,</span> <span class="mi">38</span><span class="p">,</span> <span class="mi">13</span><span class="p">};</span>
    <span class="k">struct</span> <span class="nc">Heap</span> <span class="n">h</span><span class="p">;</span>
    <span class="n">h</span><span class="p">.</span><span class="n">build</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span>            <span class="c1">// 利用已知数据构建堆</span>
    <span class="n">h</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">20</span><span class="p">);</span>               <span class="c1">// 添加新的元素</span>
    <span class="n">h</span><span class="p">.</span><span class="n">print</span><span class="p">();</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">h</span><span class="p">.</span><span class="n">pop</span><span class="p">());</span>  <span class="c1">// 最小值出堆：13</span>
    <span class="n">h</span><span class="p">.</span><span class="n">print</span><span class="p">();</span>
    <span class="n">h</span><span class="p">.</span><span class="n">push_2</span><span class="p">(</span><span class="mi">56</span><span class="p">);</span>             <span class="c1">// 添加新的元素，同时保持元素总数不变，这里 56 进 27 出</span>
    <span class="n">h</span><span class="p">.</span><span class="n">print</span><span class="p">();</span>
    <span class="n">h</span><span class="p">.</span><span class="n">sort</span><span class="p">();</span>                 <span class="c1">// 堆排序</span>
    <span class="n">h</span><span class="p">.</span><span class="n">print</span><span class="p">();</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="置换排序">置换排序</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* 
 * 置换原理解释：原状态与目标状态形成一个置换群
 *
 * 比如：
 * 2 1 6 5 3 4
 * 1 2 6 3 4 5
 *
 * 得到置换群，其循环节为 3：
 * 2 1   6   5 3 4
 * 1 2   6   3 4 5
 *
 * 显然要从原状态得到目标状态，只需要在每个置换内部交换，这样交换次数才最少，因为置换之间交换是没有意义的
 * 置换内交换有两种方法：
 *
 * 比如：
 * 3 4 2 1 5 7 6 =&gt; 1 2 3 4 5 6 7
 *
 * 第一种方法，从左到右，每次归位当前位置的元素：
 * 1 的位置不是 1，而是 3，于是 1 和 3 交换，得到：1 4 2 3 7 6 5     归位 1
 * 2 的位置不是 2，而是 4，于是 2 和 4 交换，得到：1 2 4 3 7 6 5     归位 2
 * 3 的位置不是 3，而是 4，于是 3 和 4 交换，得到：1 2 3 4 7 6 5     归位 3、4，(1 2 3 4) 属于一个置换，置换内排序完成
 * ..
 * 5 的位置就是 5，不变                                           (5) 属于一个置换
 * 6 的位置不是 6，而是 7，于是 6 和 7 交换，得到：1 2 3 4 5 6 7     (6 7) 属于一个置换，置换内排序完成
 * 共交换 4 次，每次归位一个元素
 *
 * 第二种方法，从左到右，每次归位当前位置值的元素：
 * 1 的位置不是 1，而是 3，于是 3 和 a[3] 交换，得到：2 4 3 1 5 7 6  归位 3
 * 1 的位置不是 1，而是 2，于是 2 和 a[2] 交换，得到：4 2 3 1 5 7 6  归位 2
 * 1 的位置不是 1，而是 4，于是 4 和 a[4] 交换，得到：1 2 3 4 5 7 6  归位 4、1，(1 2 3 4) 属于一个置换，置换内排序完成
 * ..
 * 5 的位置就是 5，不变                                           (5) 属于一个置换
 * 6 的位置不是 6，而是 7，于是 7 和 a[7] 交换，得到：1 2 3 4 5 6 7  (6 7) 属于一个置换，置换内排序完成
 * 共交换 4 次，每次归位一个元素，复杂度：O(N)
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define N 10010
</span>
<span class="kt">int</span> <span class="n">n</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">T</span><span class="p">;</span>
    <span class="n">scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">T</span><span class="p">);</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">T</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">n</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="kt">int</span> <span class="n">cnt</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">!=</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 置换群，形成环，多次交换</span>
                <span class="n">swap</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">a</span><span class="p">[</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]]);</span>
                <span class="n">cnt</span><span class="o">++</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">cnt</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h1 id="贪心">贪心</h1>

<p>贪心即从局部出发，计算当前的局部最优解，最终得到整个问题的最优解</p>

<p>注意，和动态规划不同的是：</p>

<ul>
  <li>贪心可以直接从局部最优得到整体最优，</li>
  <li>动态规划总是需要记录所有子问题的最优解，每次迭代时，需要从多个子路径中得到当前状态的最优解，最终得到整个问题的最优解</li>
</ul>

<p>很多时候贪心题目都比较难证明，需要大胆猜想，另外贪心问题常常都需要排序</p>

<h1 id="搜索">搜索</h1>

<h2 id="dfs">DFS</h2>

<p>一种图遍历的算法，它的思想是从图中的起点开始，沿着一条路径走到底，如果发现不能到达目标解，那就返回到上一个节点，然后搜索另一条路径</p>

<p>例题：在一个 n * m 的迷宫中，’#’ 为墙，’-‘ 为路，求起点 S 到终点 E 的最小步数</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstring&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define min(a, b) ((a) &lt; (b) ? (a) : (b))
#define N 1010
#define M 1010
</span>
<span class="kt">int</span> <span class="n">ans</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">sx</span><span class="p">,</span> <span class="n">sy</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">ex</span><span class="p">,</span> <span class="n">ey</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">mpt</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">M</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">dir</span><span class="p">[</span><span class="mi">4</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span> <span class="p">{</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">}</span> <span class="p">};</span>

<span class="kt">void</span> <span class="n">dfs</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">,</span> <span class="kt">int</span> <span class="n">step</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o">==</span> <span class="n">ex</span> <span class="o">&amp;&amp;</span> <span class="n">y</span> <span class="o">==</span> <span class="n">ey</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 终点</span>
        <span class="n">ans</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">ans</span><span class="p">,</span> <span class="n">step</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">step</span> <span class="o">&gt;=</span> <span class="n">ans</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span> <span class="c1">// 超过当前最小步数，剪枝</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">tx</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">dir</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span>
        <span class="kt">int</span> <span class="n">ty</span> <span class="o">=</span> <span class="n">y</span> <span class="o">+</span> <span class="n">dir</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">1</span><span class="p">];</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">tx</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">tx</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">&amp;&amp;</span> <span class="n">ty</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">ty</span> <span class="o">&lt;</span> <span class="n">m</span> <span class="o">&amp;&amp;</span> <span class="n">mpt</span><span class="p">[</span><span class="n">tx</span><span class="p">][</span><span class="n">ty</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">'#'</span><span class="p">)</span> <span class="p">{</span>
            <span class="kt">char</span> <span class="n">t</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="n">tx</span><span class="p">][</span><span class="n">ty</span><span class="p">];</span>
            <span class="n">mpt</span><span class="p">[</span><span class="n">tx</span><span class="p">][</span><span class="n">ty</span><span class="p">]</span> <span class="o">=</span> <span class="sc">'#'</span><span class="p">;</span>     <span class="c1">// 标记为墙，避免重复访问，这里也可以单独使用一个 vis 数组用于标记</span>
            <span class="n">dfs</span><span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="n">ty</span><span class="p">,</span> <span class="n">step</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span> <span class="c1">// 递归搜索</span>
            <span class="n">mpt</span><span class="p">[</span><span class="n">tx</span><span class="p">][</span><span class="n">ty</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span><span class="p">;</span>       <span class="c1">// 回溯，尝试另外的路径</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="cm">/*
 * 5 5
 * S-###
 * -----
 * ##---
 * E#---
 * ---##
 */</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">scanf</span><span class="p">(</span><span class="s">"%d%d"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">n</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">m</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">scanf</span><span class="p">(</span><span class="s">"%s"</span><span class="p">,</span> <span class="n">mpt</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">m</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">mpt</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'S'</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">sx</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
                <span class="n">sy</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">mpt</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'E'</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">ex</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
                <span class="n">ey</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">ans</span> <span class="o">=</span> <span class="n">n</span> <span class="o">*</span> <span class="n">m</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">dfs</span><span class="p">(</span><span class="n">sx</span><span class="p">,</span> <span class="n">sy</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">ans</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="bfs">BFS</h2>

<p>和 DFS 不一样的是，BFS 是一种分层搜索，从起点开始，一层层向外搜索，直到终点
同一层的节点到起点的距离相等，由于是通过队列维护遍历过程，所以上一层节点遍历完成之后才会遍历下一层节点</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstring&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;queue&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define N 1010
#define M 1010
</span>
<span class="k">struct</span> <span class="nc">Node</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">d</span><span class="p">;</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="nc">Queue</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">front</span><span class="p">,</span> <span class="n">rear</span><span class="p">;</span>
    <span class="n">Node</span> <span class="n">nodes</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">sx</span><span class="p">,</span> <span class="n">sy</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">ex</span><span class="p">,</span> <span class="n">ey</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">mpt</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">M</span><span class="p">];</span>
<span class="kt">bool</span> <span class="n">vis</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">M</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">dir</span><span class="p">[</span><span class="mi">4</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span> <span class="p">{</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">}</span> <span class="p">};</span>

<span class="c1">// 使用 STL 实现</span>
<span class="kt">int</span> <span class="n">bfs</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">queue</span><span class="o">&lt;</span><span class="n">Node</span><span class="o">&gt;</span> <span class="n">q</span><span class="p">;</span>
    <span class="n">Node</span> <span class="n">now</span><span class="p">,</span> <span class="n">next</span><span class="p">;</span>
    <span class="n">now</span><span class="p">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">sx</span><span class="p">;</span>
    <span class="n">now</span><span class="p">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">sy</span><span class="p">;</span>
    <span class="n">now</span><span class="p">.</span><span class="n">d</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">vis</span><span class="p">[</span><span class="n">sx</span><span class="p">][</span><span class="n">sy</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">now</span><span class="p">);</span> <span class="c1">// 起点进队</span>
    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">q</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="n">now</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span>
        <span class="n">q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">now</span><span class="p">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">ex</span> <span class="o">&amp;&amp;</span> <span class="n">now</span><span class="p">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">ey</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 到达终点，返回</span>
            <span class="k">return</span> <span class="n">now</span><span class="p">.</span><span class="n">d</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">next</span> <span class="o">=</span> <span class="n">now</span><span class="p">;</span>
            <span class="n">next</span><span class="p">.</span><span class="n">x</span> <span class="o">+=</span> <span class="n">dir</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span>
            <span class="n">next</span><span class="p">.</span><span class="n">y</span> <span class="o">+=</span> <span class="n">dir</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">1</span><span class="p">];</span>
            <span class="n">next</span><span class="p">.</span><span class="n">d</span><span class="o">++</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">next</span><span class="p">.</span><span class="n">x</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">next</span><span class="p">.</span><span class="n">x</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">&amp;&amp;</span> <span class="n">next</span><span class="p">.</span><span class="n">y</span> <span class="o">&gt;=</span><span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">next</span><span class="p">.</span><span class="n">y</span> <span class="o">&lt;</span> <span class="n">m</span> <span class="o">&amp;&amp;</span> <span class="n">mpt</span><span class="p">[</span><span class="n">next</span><span class="p">.</span><span class="n">x</span><span class="p">][</span><span class="n">next</span><span class="p">.</span><span class="n">y</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">'#'</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">vis</span><span class="p">[</span><span class="n">next</span><span class="p">.</span><span class="n">x</span><span class="p">][</span><span class="n">next</span><span class="p">.</span><span class="n">y</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">vis</span><span class="p">[</span><span class="n">next</span><span class="p">.</span><span class="n">x</span><span class="p">][</span><span class="n">next</span><span class="p">.</span><span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
                <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">next</span><span class="p">);</span>             <span class="c1">// 进队下个节点</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="c1">// 无法到达终点</span>
<span class="p">}</span>

<span class="c1">// 使用数组实现</span>
<span class="c1">// 记录层数的两种方式：</span>
<span class="c1">// - 在每个节点中记录当前层数</span>
<span class="c1">// - 使用两个变量记录每层节点的数量</span>
<span class="c1">// - 使用两层循环，内层循环每次出队 q.size() 次，即将当前层的节点全部出队，将下一层节点进队</span>
<span class="kt">int</span> <span class="n">bfs_2</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">Queue</span> <span class="n">q</span><span class="p">;</span>
    <span class="n">Node</span> <span class="n">now</span><span class="p">,</span> <span class="n">next</span><span class="p">;</span>
    <span class="n">memset</span><span class="p">(</span><span class="n">vis</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">vis</span><span class="p">));</span>
    <span class="kt">int</span> <span class="n">now_step_num</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">next_step_num</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">step</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="n">now</span><span class="p">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">sx</span><span class="p">;</span>
    <span class="n">now</span><span class="p">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">sy</span><span class="p">;</span>
    <span class="n">now</span><span class="p">.</span><span class="n">d</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">vis</span><span class="p">[</span><span class="n">sx</span><span class="p">][</span><span class="n">sy</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">front</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">rear</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">nodes</span><span class="p">[</span><span class="o">++</span><span class="n">q</span><span class="p">.</span><span class="n">rear</span><span class="p">]</span> <span class="o">=</span> <span class="n">now</span><span class="p">;</span> <span class="c1">// 起点进队</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">q</span><span class="p">.</span><span class="n">front</span> <span class="o">!=</span> <span class="n">q</span><span class="p">.</span><span class="n">rear</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">now</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">nodes</span><span class="p">[</span><span class="o">++</span><span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">];</span> <span class="c1">// 出队</span>
        <span class="c1">// printf("&gt;&gt;&gt; now: %d %d %d %d\n", now.x, now.y, now.d, step);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">now</span><span class="p">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">ex</span> <span class="o">&amp;&amp;</span> <span class="n">now</span><span class="p">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">ey</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">now</span><span class="p">.</span><span class="n">d</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">next</span> <span class="o">=</span> <span class="n">now</span><span class="p">;</span>
            <span class="n">next</span><span class="p">.</span><span class="n">x</span> <span class="o">+=</span> <span class="n">dir</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span>
            <span class="n">next</span><span class="p">.</span><span class="n">y</span> <span class="o">+=</span> <span class="n">dir</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">1</span><span class="p">];</span>
            <span class="n">next</span><span class="p">.</span><span class="n">d</span><span class="o">++</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">next</span><span class="p">.</span><span class="n">x</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">next</span><span class="p">.</span><span class="n">x</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">&amp;&amp;</span> <span class="n">next</span><span class="p">.</span><span class="n">y</span> <span class="o">&gt;=</span><span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">next</span><span class="p">.</span><span class="n">y</span> <span class="o">&lt;</span> <span class="n">m</span> <span class="o">&amp;&amp;</span> <span class="n">mpt</span><span class="p">[</span><span class="n">next</span><span class="p">.</span><span class="n">x</span><span class="p">][</span><span class="n">next</span><span class="p">.</span><span class="n">y</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">'#'</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">vis</span><span class="p">[</span><span class="n">next</span><span class="p">.</span><span class="n">x</span><span class="p">][</span><span class="n">next</span><span class="p">.</span><span class="n">y</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">vis</span><span class="p">[</span><span class="n">next</span><span class="p">.</span><span class="n">x</span><span class="p">][</span><span class="n">next</span><span class="p">.</span><span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
                <span class="n">q</span><span class="p">.</span><span class="n">nodes</span><span class="p">[</span><span class="o">++</span><span class="n">q</span><span class="p">.</span><span class="n">rear</span><span class="p">]</span> <span class="o">=</span> <span class="n">next</span><span class="p">;</span> <span class="c1">// 入队</span>
                <span class="n">next_step_num</span><span class="o">++</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="n">now_step_num</span><span class="o">--</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">now_step_num</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 若当前层出队完了，换到下一层，下一层从 0 计数</span>
            <span class="n">now_step_num</span> <span class="o">=</span> <span class="n">next_step_num</span><span class="p">;</span>
            <span class="n">next_step_num</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
            <span class="n">step</span><span class="o">++</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="c1">// 无法到达终点</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">scanf</span><span class="p">(</span><span class="s">"%d%d"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">n</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">m</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">scanf</span><span class="p">(</span><span class="s">"%s"</span><span class="p">,</span> <span class="n">mpt</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">m</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">mpt</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'S'</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">sx</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
                <span class="n">sy</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">mpt</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'E'</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">ex</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
                <span class="n">ey</span> <span class="o">=</span> <span class="n">j</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">bfs</span><span class="p">());</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">bfs_2</span><span class="p">());</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="双向搜索">双向搜索</h2>

<h2 id="dlx">DLX</h2>

<h2 id="剪枝">剪枝</h2>

<h3 id="奇偶剪枝">奇偶剪枝</h3>

<h3 id="记忆化">记忆化</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 记忆化：在搜索中，往往会重复搜索，因此可以使用一个数组记录下来，防止重复搜索。记忆化很多时候可以很方便地改写为动态规划
 * 
 * 下面用最简单的斐波拉契举例，可以看出两者差异是巨大的
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;time.h&gt;</span><span class="cp">
#define MAXN 50
#define LL long long
</span>
<span class="c1">// 1 2 3 4 5 6 7</span>
<span class="c1">// 1 1 2 3 5 8 13 ...</span>
<span class="n">LL</span> <span class="nf">fibonacci</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">||</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">fibonacci</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">fibonacci</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">2</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">LL</span> <span class="n">dp</span><span class="p">[</span><span class="n">MAXN</span><span class="p">];</span>
<span class="n">LL</span> <span class="n">fibonacci_2</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">])</span> <span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">];</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">||</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">=</span> <span class="n">fibonacci_2</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">fibonacci_2</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">2</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">40</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">t1</span> <span class="o">=</span> <span class="n">clock</span><span class="p">();</span>
    <span class="kt">int</span> <span class="n">ans1</span> <span class="o">=</span> <span class="n">fibonacci</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">t2</span> <span class="o">=</span> <span class="n">clock</span><span class="p">();</span>
    <span class="kt">int</span> <span class="n">ans2</span> <span class="o">=</span> <span class="n">fibonacci_2</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">t3</span> <span class="o">=</span> <span class="n">clock</span><span class="p">();</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"ans1 = %d, used %d ms</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">ans1</span><span class="p">,</span> <span class="p">(</span><span class="n">t2</span> <span class="o">-</span> <span class="n">t1</span><span class="p">));</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"ans2 = %d, used %d ms</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">ans1</span><span class="p">,</span> <span class="p">(</span><span class="n">t3</span> <span class="o">-</span> <span class="n">t2</span><span class="p">));</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h1 id="动态规划">动态规划</h1>

<h2 id="背包问题">背包问题</h2>

<p>背包问题是典型的动态规划，经典资料：<a href="https://github.com/tianyicui/pack/blob/master/V2.pdf">背包九讲</a></p>

<h3 id="01背包">01背包</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 有 N 物品，每件物品都有一定的价值、同时会占用一定的空间，问容量为 s 的背包最最多能装下价值为多少的物品？
 *
 * 二维形式
 *
 * dp[i][j] 表示将前 i 件物品放入容量为 j 的背包可获得的最大价值，这里先都假设不必刚好装满
 *
 * 状态转移方程：dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]) if j &gt;= w[i]
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define N 110
</span>
<span class="kt">int</span> <span class="n">w</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">v</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">s</span><span class="p">;</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">s</span> <span class="o">&gt;&gt;</span> <span class="n">n</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="c1">// n 件物品</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">s</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 容量小于 s</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">j</span><span class="p">)</span> <span class="c1">// 第 i 件物品能放下</span>
                <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">_cpp_max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">j</span> <span class="o">-</span> <span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span> <span class="o">+</span> <span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">]);</span> <span class="c1">// 取放或不放的最大价值</span>
            <span class="k">else</span> <span class="c1">// 放不下</span>
                <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">];</span> <span class="c1">// 取前 i - 1 件物品放入容量为 j 的背包的最大价值</span>
        <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="n">s</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="c1">// 输出前 n 件物品放入容量为 s 的背包的最大价值</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/*
 * 一维形式
 *
 * 在上面的实现中，1 2..n 件物品中所有的状态都保存下来了，其实没有必要，我们最终只需要得到前 n 件物品产生的最大价值
 * 空间优化：使用 dp[j] 代替 dp[i][j]，不需要每轮循环的状态数据都进行保留，只要保证当 i = n，使用 dp[j](当轮赋值) 时 dp[j - ..](上轮的值)存在即可，故 j = s、j &gt;= 0 需要倒序
 *
 * dp[j] 表示把物品放入容量为j背包的最大价值
 * 状态转移方程：dp[j] = max(dp[j], dp[j - w[i]] + v[i]) if j &gt;= w[i]
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define N 110
</span>
<span class="kt">int</span> <span class="n">w</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">v</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">s</span><span class="p">;</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">s</span> <span class="o">&gt;&gt;</span> <span class="n">n</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 枚举每一个物品，然后更新每一个背包的最大价值</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">s</span><span class="p">;</span> <span class="n">j</span> <span class="o">&gt;=</span> <span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="n">j</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 枚举能放下的背包状态，更新这些背包的最大价值，一层层更新，相当于把每一个容量的背包的最大价值得到了，容量大的背包需要建立在容量小的背包的基础上，而最后我们只需要容量为 S 的背包的最大价值</span>
            <span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">dp</span><span class="p">[</span><span class="n">j</span> <span class="o">-</span> <span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span> <span class="o">+</span> <span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="c1">// 取放与不放的最大价值，此 dp[j - w[i]] 实质上是表示的是 i - 1 循环时的状态数据</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">dp</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="c1">// 输出放入容量为 s 的最大物品价值</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/*
 * 在某些情况下，要求背包必须刚好装满
 *
 * 状态转移过程是一样的，不同的地方在于初始化：
 * 之前，我们对 dp 整个数组初始化为 0，表示容量为 i 的背包能装下物品的最大价值为 0，在递推过程中，对于每件物品，可以选择放或不放，最终背包不一样刚好被装满
 * 现在，初始化 dp[0] = 0，其它元素为 -INF，表示除了容量为 0 的背包初始价值为 0，其他状态的背包都未定义，在递推过程中，某些状态的背包如果只依赖这些不存在的状态，即这些状态也会变为未定义 -INF，最终我们可以通过判断 dp[s] 是否小于 0 即可
 */</span>
</code></pre></div></div>

<h2 id="区间dp">区间DP</h2>

<h2 id="树形dp">树形DP</h2>

<h2 id="状压dp">状压DP</h2>

<h2 id="数位dp">数位DP</h2>

<h1 id="数学">数学</h1>

<h2 id="gcd">GCD</h2>

<h2 id="素数">素数</h2>

<h3 id="素数筛">素数筛</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="c1">// 求小于等于 N 的素数的个数</span>
<span class="c1">// (1) 最简单的方法，循环遍历判断每个数是否是素数</span>
<span class="c1">// 单次判断的复杂度为：O(√n)</span>
<span class="kt">int</span> <span class="nf">solve_1</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">ans</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">bool</span> <span class="n">ok</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">j</span> <span class="o">*</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">i</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">%</span> <span class="n">j</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">ok</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">ok</span><span class="p">)</span> <span class="n">ans</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>

<span class="cp">#define LL long long
#define MAXN 1500000
</span>
<span class="c1">// (2) 埃拉托斯特尼筛法，时间复杂度：O(N * logN * logN)</span>
<span class="c1">// 根据素数的定义，即只能被 1 和 自己 整除的正整数，另外 0 和 1 一般认为不是素数</span>
<span class="c1">// 那么可以先预处理一下，先把 2 3 4 5... 的倍数置为合数</span>
<span class="n">bool</span> <span class="n">is_prime</span><span class="p">[</span><span class="n">MAXN</span> <span class="o">+</span> <span class="mi">1</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">prime</span><span class="p">[</span><span class="n">MAXN</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">tot</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">solve_2</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">tot</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">is_prime</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 从 2 开始遍历，把其倍数标记为合数</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">is_prime</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="p">{</span> <span class="c1">// 优化 1：只标记素数的倍数为合数，合数的倍数已经被包含在其中了，不用重复标记，如 4 * 3 = （2 * 2) * 3 = 2 * 6</span>
            <span class="n">prime</span><span class="p">[</span><span class="n">tot</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">((</span><span class="n">LL</span><span class="p">)</span> <span class="n">i</span> <span class="o">*</span> <span class="n">i</span> <span class="o">&gt;</span> <span class="n">n</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
            <span class="c1">// 优化 2：使用 j += i 代替 j++; is_prime[i * j] = false</span>
            <span class="c1">// 优化 3：从 i * i 开始，标记 [i * i, i * (i + 1), i * (i + 2) ... ]，因为 [2 * i, (i - 1) * i ] 已经被筛过了，比如 i = 7, 7 * 2 ... 7 * 6 已经分别被 i = 2, 2 * 7 ... i = 6, 6 * 7 标记过了</span>
            <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">i</span> <span class="o">*</span> <span class="n">i</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span> <span class="o">+=</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">is_prime</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">ans</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">is_prime</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">ans</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// 或使用 prime</span>
    <span class="c1">// for (int i = 0; i &lt; tot &amp;&amp; prime[i] &lt;= n; i++) {</span>
    <span class="c1">//    ans++;</span>
    <span class="c1">// }</span>
    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// 线性筛法，时间复杂度：O(N)，空间复杂度：O(N)</span>
<span class="c1">// 上面的 埃拉托斯特尼筛法 中，仍然存在部分合数被重复标记，比如 36 = 2 * 18 = 3 * 12</span>
<span class="c1">// 这是因为 36 有多个质因子，会在 i = 2 和 i = 3 时同时被标记(虽然有常数优化 3，但仍然没能避免重复筛选)</span>
<span class="c1">// 所以我们可以再优化下，保证每个合数被其最小质因子标记即可</span>
<span class="kt">int</span> <span class="nf">solve_3</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">tot</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">is_prime</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 从 2 开始遍历，开始筛选</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">is_prime</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="p">{</span> <span class="c1">// 如果是素数，加入素数数组</span>
            <span class="n">prime</span><span class="p">[</span><span class="n">tot</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">tot</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 遍历当前素数，将当前素数的 i 的倍数标记为合数</span>
            <span class="k">if</span> <span class="p">((</span><span class="n">LL</span><span class="p">)</span> <span class="n">i</span> <span class="o">*</span> <span class="n">prime</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">n</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
            <span class="n">is_prime</span><span class="p">[</span><span class="n">i</span> <span class="o">*</span> <span class="n">prime</span><span class="p">[</span><span class="n">j</span><span class="p">]]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
            <span class="c1">// 重点：如果 i 能被 prime[j] 整除(此时 prime[j] 是 i 的最小质因子)，退出循环</span>
            <span class="c1">// 举个例子：i = 6, prime[j] = 2, is_prime[6 * 2] = false, 6 % 2 == 0, break。这是因为后面的合数如 is_prime[6 * 3] 中 6 = 2 * 3，6 * 2 = 2 * 3 * 3 = 9 * 2，即可以被 i = 9 时 9 * 2 标记，从而避免重复标记</span>
            <span class="c1">// 正式居于此，虽然有两层循环，但每个数最多被标记一次，时间复杂度：O(N)</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">%</span> <span class="n">prime</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">ans</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">is_prime</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">ans</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">100000</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">r1</span> <span class="o">=</span> <span class="n">solve_1</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">r2</span> <span class="o">=</span> <span class="n">solve_2</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">r3</span> <span class="o">=</span> <span class="n">solve_3</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d %d %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">r1</span><span class="p">,</span> <span class="n">r2</span><span class="p">,</span> <span class="n">r3</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="合数分解">合数分解</h3>

<h3 id="miller-rabin测试">Miller-Rabin测试</h3>

<h2 id="母函数">母函数</h2>

<h2 id="容斥原理">容斥原理</h2>

<h2 id="鸽巢原理">鸽巢原理</h2>

<h2 id="快速幂">快速幂</h2>

<h3 id="乘法快速幂">乘法快速幂</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="c1">// 快速计算 a^n，复杂度 O(logN)</span>
<span class="c1">//</span>
<span class="c1">// 一般循环遍历相乘需要做 n 次乘法，如果 n 太大就比较慢了</span>
<span class="c1">// 那么可以做一个变换，将 n 用二进制表示，如：a^13 = a^(1101)_2 = a^8 * a^4 * 1 * a^1</span>
<span class="c1">// 这样就可以优化计算了，将 n 转化为二进制，从低位到高位，如果这一位为1，则乘上 a，同时每次循环 a 都自乘一次</span>
<span class="kt">int</span> <span class="nf">quick_pow</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">b</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="n">ret</span> <span class="o">*=</span> <span class="n">a</span><span class="p">;</span>
        <span class="n">a</span> <span class="o">*=</span> <span class="n">a</span><span class="p">;</span>
        <span class="n">b</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">quick_pow</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">13</span><span class="p">));</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="矩阵快速幂">矩阵快速幂</h3>

<h2 id="扩展欧几里得">扩展欧几里得</h2>

<h2 id="逆元">逆元</h2>

<h2 id="中国剩余定理">中国剩余定理</h2>

<h2 id="卢卡斯定理">卢卡斯定理</h2>

<h2 id="欧拉函数">欧拉函数</h2>

<h2 id="高斯消元">高斯消元</h2>

<h2 id="莫比乌斯反演">莫比乌斯反演</h2>

<h1 id="数据结构">数据结构</h1>

<p>##</p>

<h2 id="链表">链表</h2>

<h2 id="哈希表">哈希表</h2>

<h2 id="队列与栈">队列与栈</h2>

<h2 id="堆">堆</h2>

<h2 id="字典树">字典树</h2>

<h3 id="数组">数组</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 字典树：顾名思义，就是一棵像字典一样的树</span>
<span class="c1">// 字典树可用于高效查找字符串或字符串前缀，时间复杂度：O(n)</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstring&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define N 1000010
#define M 26
</span>
<span class="kt">int</span> <span class="n">sz</span><span class="p">;</span>       <span class="c1">// sz 表示待分配的字典树节点下标</span>
<span class="kt">int</span> <span class="n">ch</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">M</span><span class="p">];</span> <span class="c1">// ch 用于存储字典树，如 ch[2][3] 表示字典树中第 2 个节点的第 3 个子节点</span>
<span class="kt">int</span> <span class="n">val</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>   <span class="c1">// val 用于存储字典树对应节点的附属信息</span>

<span class="c1">// 初始化字典树</span>
<span class="c1">// 0 为根节点，一个虚拟的空节点</span>
<span class="kt">void</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// memset(ch[0], 0, sizeof(ch[0]));</span>
    <span class="n">sz</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">get_id</span><span class="p">(</span><span class="kt">char</span> <span class="n">c</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">c</span> <span class="o">-</span> <span class="sc">'a'</span><span class="p">;</span> <span class="p">}</span>

<span class="c1">// 插入新的串到树中</span>
<span class="kt">void</span> <span class="n">insert</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">p</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">l</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">l</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 依次遍历字符串，从根节点开始，如果不存在即新建节点</span>
        <span class="kt">int</span> <span class="n">id</span> <span class="o">=</span> <span class="n">get_id</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ch</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="n">id</span><span class="p">])</span> <span class="p">{</span>
            <span class="n">ch</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="n">id</span><span class="p">]</span> <span class="o">=</span> <span class="n">sz</span><span class="o">++</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">p</span> <span class="o">=</span> <span class="n">ch</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="n">id</span><span class="p">];</span>
        <span class="n">val</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">++</span><span class="p">;</span> <span class="c1">// 以 s[0..i] 为前缀的字符串出现次数+1</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 在树中查找前缀串</span>
<span class="kt">int</span> <span class="n">find</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">p</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">l</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">l</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">id</span> <span class="o">=</span> <span class="n">get_id</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ch</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="n">id</span><span class="p">])</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// 不存在</span>
        <span class="n">p</span> <span class="o">=</span> <span class="n">ch</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="n">id</span><span class="p">];</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">val</span><span class="p">[</span><span class="n">p</span><span class="p">];</span> <span class="c1">// 返回指定前缀串出现的次数</span>
<span class="p">}</span>

<span class="cm">/*
 * abc
 * abcde
 * qwer
 *
 * a
 * abc
 * abcde
 * empty
 */</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="n">s</span><span class="p">[</span><span class="mi">12</span><span class="p">];</span>
    <span class="n">init</span><span class="p">();</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">gets</span><span class="p">(</span><span class="n">s</span><span class="p">),</span> <span class="n">strlen</span><span class="p">(</span><span class="n">s</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">insert</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">gets</span><span class="p">(</span><span class="n">s</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">find</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="指针">指针</h3>

<h2 id="分块">分块</h2>

<h2 id="rmq">RMQ</h2>

<h3 id="一维-1">一维</h3>

<h3 id="二维-1">二维</h3>

<h2 id="线段树">线段树</h2>

<p>线段树是一种典型的以空间换时间的数据结构，可用于动态修改、查询一段区间的最大值/最小值/和等</p>

<h3 id="单点更新">单点更新</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 线段树-单点更新
 *
 * 线段树是一种完全二叉树：除最后一层的节点可能只存在左子树，上层为满二叉树
 * 因此可直接使用数组实现，满足：节点 rt 的子节点为 rt * 2、rt * 2 + 1(下标从 1 开始)
 *
 * 示例：
 *
 *                    1(1~7)
 *                /           \
 *           2(1~4)            3(5~7)
 *         /       \          /      \
 *      4(1~2)   5(3~4)      6(5~6)  7(7)
 *      /  \     /   \       /     \
 *  8(1)  9(2)  10(3) 11(4) 12(5) 13(6)
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstring&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define N 200010
</span>
<span class="kt">int</span> <span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">sum</span><span class="p">[</span><span class="n">N</span> <span class="o">&lt;&lt;</span> <span class="mi">2</span><span class="p">];</span> <span class="c1">// 可以通过完全二叉树的节点公式计算得到最多 4 * N 个节点</span>

<span class="kt">void</span> <span class="nf">pushup</span><span class="p">(</span><span class="kt">int</span> <span class="n">rt</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">sum</span><span class="p">[</span><span class="n">rt</span><span class="p">]</span> <span class="o">=</span> <span class="n">sum</span><span class="p">[</span><span class="n">rt</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">sum</span><span class="p">[</span><span class="n">rt</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span> <span class="o">|</span> <span class="mi">1</span><span class="p">];</span>
<span class="p">}</span>

<span class="c1">// 构建线段树</span>
<span class="kt">void</span> <span class="n">build</span><span class="p">(</span><span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">,</span> <span class="kt">int</span> <span class="n">rt</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">==</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">sum</span><span class="p">[</span><span class="n">rt</span><span class="p">]</span> <span class="o">=</span> <span class="n">a</span><span class="p">[</span><span class="n">l</span><span class="p">];</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">build</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">rt</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">build</span><span class="p">(</span><span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">rt</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span> <span class="o">|</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">pushup</span><span class="p">(</span><span class="n">rt</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// 单点更新</span>
<span class="kt">void</span> <span class="n">update</span><span class="p">(</span><span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">,</span> <span class="kt">int</span> <span class="n">rt</span><span class="p">,</span> <span class="kt">int</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">int</span> <span class="n">c</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">==</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">sum</span><span class="p">[</span><span class="n">rt</span><span class="p">]</span> <span class="o">=</span> <span class="n">c</span><span class="p">;</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">pos</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">)</span> <span class="n">update</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">rt</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">c</span><span class="p">);</span>
    <span class="k">else</span> <span class="n">update</span><span class="p">(</span><span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">rt</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span> <span class="o">|</span> <span class="mi">1</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">c</span><span class="p">);</span>
    <span class="n">pushup</span><span class="p">(</span><span class="n">rt</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// 区间查询</span>
<span class="kt">int</span> <span class="n">query</span><span class="p">(</span><span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">,</span> <span class="kt">int</span> <span class="n">rt</span><span class="p">,</span> <span class="kt">int</span> <span class="n">L</span><span class="p">,</span> <span class="kt">int</span> <span class="n">R</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">L</span> <span class="o">==</span> <span class="n">l</span> <span class="o">&amp;&amp;</span> <span class="n">r</span> <span class="o">==</span> <span class="n">R</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">sum</span><span class="p">[</span><span class="n">rt</span><span class="p">];</span>
    <span class="p">}</span>
    <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">R</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">)</span> <span class="k">return</span> <span class="n">query</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">rt</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="n">R</span><span class="p">);</span>                                   <span class="c1">// 完全在左区间：l L R m r</span>
    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">L</span> <span class="o">&gt;</span> <span class="n">m</span><span class="p">)</span> <span class="k">return</span> <span class="n">query</span><span class="p">(</span><span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">rt</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span> <span class="o">|</span> <span class="mi">1</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="n">R</span><span class="p">);</span>                       <span class="c1">// 完全在右区间：l m L R r</span>
    <span class="k">else</span> <span class="k">return</span> <span class="n">query</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">rt</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span><span class="p">,</span> <span class="n">L</span><span class="p">,</span> <span class="n">m</span><span class="p">)</span> <span class="o">+</span> <span class="n">query</span><span class="p">(</span><span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">rt</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span> <span class="o">|</span> <span class="mi">1</span><span class="p">,</span> <span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">R</span><span class="p">);</span> <span class="c1">// 横跨左右区间：l L m R r</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
    <span class="n">a</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">a</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">a</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
    <span class="n">a</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="n">a</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
    <span class="n">a</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
    <span class="n">a</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>

    <span class="n">build</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">query</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">7</span><span class="p">));</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">query</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">));</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">query</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">));</span>
    <span class="n">update</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">query</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">7</span><span class="p">));</span> <span class="c1">// 0 2 3 4 5 6 7</span>
    <span class="n">update</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">query</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">7</span><span class="p">));</span> <span class="c1">// 0 2 10 4 5 6 7</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="区间更新">区间更新</h3>

<h3 id="区间合并">区间合并</h3>

<h2 id="树状数组">树状数组</h2>

<h3 id="改点求段">改点求段</h3>

<h3 id="改段求点">改段求点</h3>

<h2 id="并查集">并查集</h2>

<h3 id="简单-1">简单</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 并查集是一种树形的数据结构，可以方便地维护集合的合并和查询问题</span>
<span class="c1">// 举例：给出 N 组朋友关系，朋友的朋友即朋友，判断其中 a 和 b 是否是朋友关系</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstring&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define N 5010
</span>
<span class="c1">// f[x] 表示节点 x 所在集合的根节点</span>
<span class="kt">int</span> <span class="n">f</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>

<span class="c1">// 初始化并查集</span>
<span class="c1">// 初始化时每个集合只有自身一个节点</span>
<span class="kt">void</span> <span class="nf">init</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">f</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// 查询节点 x 所在集合的根节点</span>
<span class="c1">// 这里涉及到路径压缩</span>
<span class="c1">//</span>
<span class="c1">// 假设有如图所示的集合关系，查询节点 6 所在集合根节点时会不断往上直到找到根节点 1，这可能会在集合路径较长时导致查询缓慢</span>
<span class="c1">//</span>
<span class="c1">//        1</span>
<span class="c1">//      / | \</span>
<span class="c1">//     2  3  4</span>
<span class="c1">//    /</span>
<span class="c1">//   5</span>
<span class="c1">//  /</span>
<span class="c1">// 6</span>
<span class="c1">//</span>
<span class="c1">// 路径压缩是指在查询根节点时将起所在路径上的节点变为根节点的直接子节点。即：</span>
<span class="c1">//</span>
<span class="c1">//      1</span>
<span class="c1">//  / / | \ \</span>
<span class="c1">// 2 3  4 5  6</span>
<span class="c1">//</span>
<span class="c1">// 当再次查询节点 6/5/2 所在集合根节点时，只用往上查询一层即可得到根节点 1，降低了时间复杂度</span>
<span class="c1">//</span>
<span class="kt">int</span> <span class="n">find</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o">!=</span> <span class="n">f</span><span class="p">[</span><span class="n">x</span><span class="p">])</span> <span class="n">f</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">find</span><span class="p">(</span><span class="n">f</span><span class="p">[</span><span class="n">x</span><span class="p">]);</span>
    <span class="k">return</span> <span class="n">f</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
<span class="p">}</span>

<span class="c1">// 合并 x 和 y 节点所在的两个集合</span>
<span class="kt">void</span> <span class="n">union_2</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">find</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
    <span class="n">y</span> <span class="o">=</span> <span class="n">find</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o">!=</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 这里选择序号小的节点为合并后的集合根节点，也可以自定义一个估价函数，比如按秩合并</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o">&gt;</span> <span class="n">y</span><span class="p">)</span> <span class="n">f</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">y</span><span class="p">;</span>
        <span class="k">else</span> <span class="n">f</span><span class="p">[</span><span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">judge</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">find</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">==</span> <span class="n">find</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">init</span><span class="p">(</span><span class="mi">6</span><span class="p">);</span>

    <span class="n">union_2</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">union_2</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="n">union_2</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>

    <span class="n">printf</span><span class="p">(</span><span class="s">"%d %d %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">judge</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">judge</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">judge</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">));</span> <span class="c1">// 1 0 0</span>

    <span class="n">union_2</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="n">union_2</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>

    <span class="n">printf</span><span class="p">(</span><span class="s">"%d %d %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">judge</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">judge</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">judge</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">));</span> <span class="c1">// 1 1 1</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="带权">带权</h3>

<h2 id="单调队列-栈">单调队列-栈</h2>
<h3 id="单调队列">单调队列</h3>
<h4 id="介绍">介绍</h4>
<p>单调队列是一种广泛应用的数据结构，它能够动态地维护序列中的最值</p>

<h4 id="实例">实例</h4>
<p>设计一个队列，使得能够处理三种操作：</p>
<ul>
  <li>PUSH 100  将元素100添加到队尾</li>
  <li>MAX  查询当前队列中元素的最大值</li>
  <li>POP  移除队首元素</li>
</ul>

<h4 id="暴力解法">暴力解法</h4>
<p>最简单的做法就是每次查询时遍历当前队列中的所有元素，比较得到最大值，复杂度：O(N*K)，K为每次查询时队列的平均长度<br />
比如：</p>

<table>
  <thead>
    <tr>
      <th>Operation</th>
      <th style="text-align: left">Comment（左边为队首，单调递减队列，队首为最大值）</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>PUSH 300</td>
      <td style="text-align: left">[300]</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">(1) 遍历得到当前最大值为300</td>
    </tr>
    <tr>
      <td>PUSH 200</td>
      <td style="text-align: left">[300,200]</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">(2) 遍历得到当前最大值为300</td>
    </tr>
    <tr>
      <td>PUSH 100</td>
      <td style="text-align: left">[300,200,100]</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">(3) 遍历得到当前最大值为300</td>
    </tr>
    <tr>
      <td>POP</td>
      <td style="text-align: left">[200,100]</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">(4) 遍历得到当前最大值为200</td>
    </tr>
    <tr>
      <td>PUSH 400</td>
      <td style="text-align: left">[200,100,400]</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">(5) 遍历得到当前最大值为400</td>
    </tr>
    <tr>
      <td>POP</td>
      <td style="text-align: left">[100,400]</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">(6) 遍历得到当前最大值为400</td>
    </tr>
  </tbody>
</table>

<p>显然这不是最优解<br />
先看第(1)(2)(3)(4)次查询，其实是可以省略一些比较运算的，因为进队的元素是单调递减的，无需比较直接返回队首元素即可（即使中间有出队操作）<br />
再看第(5)次查询，插入的400破坏了前面的单调关系，是否可以将队列中的已有的200、100直接出队（因为这俩已经没用了，只要400被插入到队列中，最大值就永远不会是200或100，即使400被移除队列，200或100肯定先于400被移除），然后再将400进队，这样最大值就是队首元素了<br />
综合上面两种情况：如果插入的元素满足单调关系，直接将元素插入队尾，否则先将队尾元素出队，再插入新的元素，查询时直接返回队首元素即可</p>

<h4 id="单调队列-1">单调队列</h4>
<p>单调队列相对于普通队列而言，需要维护了一种单调关系，队首始终保存的是当前队列中元素的最值<br />
每个元素仅进队一次，仅出队一次，在元素插入队尾前，需要先和队尾元素进行比较，如果关系符合单调顺序，则直接插入队尾，否则需要先移除队尾元素再进行插入，使得始终保持单调关系<br />
复杂度：O(N)</p>

<table>
  <thead>
    <tr>
      <th>Operation</th>
      <th style="text-align: left">Comment</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>PUSH 300</td>
      <td style="text-align: left">[300]</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">无需遍历，直接返回队首元素300</td>
    </tr>
    <tr>
      <td>PUSH 200</td>
      <td style="text-align: left">[300,200] 200小于300，直接插入队尾</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">无需遍历，直接返回队首元素300</td>
    </tr>
    <tr>
      <td>PUSH 100</td>
      <td style="text-align: left">[300,200,100] 100小于200，直接插入队尾</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">无需遍历，直接返回队首元素300</td>
    </tr>
    <tr>
      <td>POP</td>
      <td style="text-align: left">[200,100] 移除队首元素</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">无需遍历，直接返回队首元素200</td>
    </tr>
    <tr>
      <td>PUSH 400</td>
      <td style="text-align: left">[400]，400不小于100，移除队尾元素100，继续比较，400不小于200，再移除队尾元素200，最后将400插入队尾</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">无需遍历，直接返回队首元素400</td>
    </tr>
    <tr>
      <td>POP</td>
      <td style="text-align: left">[400]，注意这里POP原本出队的是元素200，所以这里不需要真正执行出队操作。实际实现时可以给每个进队元素内置一个in_id，每次出队维护一个out_id++，如果当前out_id和队首元素的id相等，才真正执行出队操作</td>
    </tr>
    <tr>
      <td>MAX</td>
      <td style="text-align: left">无需遍历，直接返回队首元素400</td>
    </tr>
  </tbody>
</table>

<h5 id="代码">代码</h5>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 未经测试，仅供参考</span>
<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstring&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define MAXN 1000010
</span>
<span class="k">struct</span> <span class="nc">item</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="n">val</span><span class="p">;</span>
<span class="p">}</span> <span class="n">q</span><span class="p">[</span><span class="n">MAXN</span><span class="p">],</span> <span class="n">tp</span><span class="p">;</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="n">op</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span>
    <span class="kt">int</span> <span class="n">front</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">rear</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">in</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">out</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// in, out表示进队、出队编号</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">scanf</span><span class="p">(</span><span class="s">"%s"</span><span class="p">,</span> <span class="n">op</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">strcmp</span><span class="p">(</span><span class="n">op</span><span class="p">,</span> <span class="s">"END"</span><span class="p">))</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">strcmp</span><span class="p">(</span><span class="n">op</span><span class="p">,</span> <span class="s">"PUSH"</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 进队，单调递减</span>
            <span class="n">scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">tp</span><span class="p">.</span><span class="n">val</span><span class="p">);</span>
            <span class="n">tp</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">in</span><span class="o">++</span><span class="p">;</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">rear</span> <span class="o">&gt;</span> <span class="n">front</span> <span class="o">&amp;&amp;</span> <span class="n">tp</span><span class="p">.</span><span class="n">val</span> <span class="o">&gt;=</span> <span class="n">q</span><span class="p">[</span><span class="n">rear</span><span class="p">].</span><span class="n">val</span><span class="p">)</span> <span class="n">rear</span><span class="o">--</span><span class="p">;</span>
            <span class="n">q</span><span class="p">[</span><span class="n">rear</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">tp</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">strcmp</span><span class="p">(</span><span class="n">op</span><span class="p">,</span> <span class="s">"MAX"</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 查询</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">front</span> <span class="o">==</span> <span class="n">rear</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="o">-</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">q</span><span class="p">[</span><span class="n">front</span><span class="p">].</span><span class="n">val</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// 出队，如果id在当前队首就出队</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">out</span> <span class="o">==</span> <span class="n">q</span><span class="p">[</span><span class="n">front</span><span class="p">].</span><span class="n">id</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">front</span><span class="o">++</span><span class="p">;</span>
            <span class="p">}</span>
            <span class="n">out</span><span class="o">++</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="题目">题目</h4>
<ul>
  <li>FZU 1894  模板题</li>
  <li>POJ 2823  模板题</li>
  <li>HDU 3415</li>
  <li>HDU 3530</li>
  <li>POJ 3061</li>
</ul>

<h3 id="单调栈">单调栈</h3>

<h4 id="介绍-1">介绍</h4>

<p>和单调队列类似，栈内元素始终保持单调性，不同的是单调栈只能在栈顶操作</p>

<p>将一个元素压入单调栈时，为了维护栈的单调性，需要和栈顶元素进行比较，栈顶始终保存的是当前栈中元素的最值</p>

<p>比如单调递减栈（从栈底到栈顶单调递减），每个元素进栈时，如果栈顶元素比当前元素大则直接进栈，否则需要先不断弹出栈顶元素直到栈顶元素大于当前元素，然后再压入当前元素</p>

<p>利用这一性质，可以利用单调栈：</p>

<ul>
  <li>求每个元素左边第一个比它大（单调递减）/ 小（单调递增）的元素</li>
  <li>求每个元素左边的元素中以当前元素为右边第一个比其大（单调递减）或小（单调递增）的元素列表</li>
</ul>

<h4 id="实例-1">实例</h4>

<table>
  <thead>
    <tr>
      <th>Operation</th>
      <th style="text-align: left">Comment（右边为栈顶，从栈底到栈顶单调递减，栈顶为最小值）</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>6</td>
      <td style="text-align: left">[6]</td>
    </tr>
    <tr>
      <td>10</td>
      <td style="text-align: left">[10] 10大于6，弹出栈顶元素6，压入元素10</td>
    </tr>
    <tr>
      <td>3</td>
      <td style="text-align: left">[10,3] 3小于10，压入元素3，3</td>
    </tr>
    <tr>
      <td>7</td>
      <td style="text-align: left">[10,7] 7大于3，弹出栈顶元素3，压入元素7<br />比如这里可以得出：7左边第一个比7大的元素是栈顶元素10</td>
    </tr>
    <tr>
      <td>4</td>
      <td style="text-align: left">[10,7,4] 4小于7，压入元素4</td>
    </tr>
    <tr>
      <td>12</td>
      <td style="text-align: left">[12] 12大于10,7,4 弹出栈顶元素，压入元素12<br />比如这里可以得出：12左边的元素中，有三个元素10,7,4(递减序列)，他们右边的第一个比其大的元素是12</td>
    </tr>
    <tr>
      <td>2</td>
      <td style="text-align: left">[12,2] 2小于12，压入元素2</td>
    </tr>
  </tbody>
</table>

<table>
  <thead>
    <tr>
      <th>Operation</th>
      <th style="text-align: left">Comment（右边为栈顶，从栈底到栈顶单调递增，栈顶为最大值）</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>6</td>
      <td style="text-align: left">[6]</td>
    </tr>
    <tr>
      <td>10</td>
      <td style="text-align: left">[6,10] 10大于6，压入元素10</td>
    </tr>
    <tr>
      <td>3</td>
      <td style="text-align: left">[3] 3小于6,10，弹出栈顶元素，压入元素3</td>
    </tr>
    <tr>
      <td>7</td>
      <td style="text-align: left">[3,7] 7大于3，压入元素7</td>
    </tr>
    <tr>
      <td>4</td>
      <td style="text-align: left">[3,4] 4小于7，弹出栈顶元素7，压入元素4</td>
    </tr>
    <tr>
      <td>12</td>
      <td style="text-align: left">[3,4,12] 12大于4，压入元素12</td>
    </tr>
    <tr>
      <td>2</td>
      <td style="text-align: left">[2] 2小于3,4,12，弹出栈顶元素，压入元素2</td>
    </tr>
  </tbody>
</table>

<h4 id="代码-1">代码</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 未经测试，仅供参考</span>
<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstring&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stack&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">item</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">id</span><span class="p">,</span> <span class="n">val</span><span class="p">;</span>
<span class="p">}</span> <span class="n">tp</span><span class="p">;</span>

<span class="c1">// 7 6 10 3 7 4 12 2</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span><span class="p">;</span>
    <span class="n">stack</span><span class="o">&lt;</span><span class="n">item</span><span class="o">&gt;</span> <span class="n">s</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">n</span><span class="p">)</span> <span class="o">!=</span> <span class="n">EOF</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">tp</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
            <span class="n">scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">tp</span><span class="p">.</span><span class="n">val</span><span class="p">);</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">tp</span><span class="p">.</span><span class="n">val</span> <span class="o">&gt;=</span> <span class="n">s</span><span class="p">.</span><span class="n">top</span><span class="p">().</span><span class="n">val</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 从栈底到栈顶单调递减</span>
                <span class="n">s</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>
            <span class="p">}</span>
            <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"left first: "</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">s</span><span class="p">.</span><span class="n">top</span><span class="p">().</span><span class="n">val</span> <span class="o">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">", left size: "</span> <span class="o">&lt;&lt;</span> <span class="n">s</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
            <span class="n">s</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">tp</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="题目-1">题目</h4>

<ul>
  <li>POJ 3250 模板题</li>
  <li>POJ 2796</li>
  <li>HDU 1506</li>
  <li>POJ 2559</li>
</ul>

<h2 id="树链剖分">树链剖分</h2>

<h2 id="划分树">划分树</h2>

<h2 id="平衡树">平衡树</h2>

<h3 id="treap">Treap</h3>

<h3 id="splay">Splay</h3>

<h3 id="sbt">SBT</h3>

<h3 id="avl">AVL</h3>

<h3 id="红黑树">红黑树</h3>

<h2 id="主席树">主席树</h2>

<h1 id="图论">图论</h1>

<h2 id="邻接表与邻接矩阵">邻接表与邻接矩阵</h2>

<p>图常用的两种存储方式即：邻接矩阵和邻接表</p>

<h3 id="邻接矩阵">邻接矩阵</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 邻接矩阵，遍历时间复杂度：O(N^2)</span>

<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
#define N 110
</span>
<span class="kt">int</span> <span class="n">n</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">vis</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">mpt</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>

<span class="kt">void</span> <span class="nf">init</span><span class="p">(</span><span class="kt">int</span> <span class="n">nn</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">n</span> <span class="o">=</span> <span class="n">nn</span><span class="p">;</span>
    <span class="n">memset</span><span class="p">(</span><span class="n">mpt</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">mpt</span><span class="p">));</span>
    <span class="n">memset</span><span class="p">(</span><span class="n">vis</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">vis</span><span class="p">));</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">add</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="kt">int</span> <span class="n">v</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">mpt</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">dfs</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">u</span><span class="p">);</span>
    <span class="n">vis</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">v</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">v</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">mpt</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">vis</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="p">{</span>
            <span class="n">dfs</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">init</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">dfs</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="邻接表">邻接表</h3>

<h4 id="数组-1">数组</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 邻接表的数组实现与遍历，遍历时间复杂度：O(E)</span>

<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span>
<span class="cp">#define N 100010
#define M 200010
</span>
<span class="k">struct</span> <span class="nc">Edge</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">w</span><span class="p">;</span>     <span class="c1">// 边的起点、重点、权值</span>
    <span class="kt">int</span> <span class="n">next</span><span class="p">;</span>        <span class="c1">// 与节点相连的边的集合中下一条边的序号</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">tot</span><span class="p">;</span>             <span class="c1">// tot 表示 edge 数组中待分配的边的下标</span>
<span class="kt">int</span> <span class="n">head</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>         <span class="c1">// head[i] 表示与节点 i 相连的的第一条边的下标</span>
<span class="k">struct</span> <span class="nc">Edge</span> <span class="n">edge</span><span class="p">[</span><span class="n">M</span><span class="p">];</span> <span class="c1">// 存储边</span>
<span class="kt">int</span> <span class="n">vis</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>

<span class="c1">// 初始化</span>
<span class="kt">void</span> <span class="n">init</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">tot</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">memset</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">head</span><span class="p">));</span>
    <span class="n">memset</span><span class="p">(</span><span class="n">vis</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">vis</span><span class="p">));</span>
<span class="p">}</span>

<span class="c1">// 新建 u-&gt;v 的边，边的下标为 tot</span>
<span class="c1">// 使用头插法，所以对节点 u 相连的边进行遍历时和添加边时的顺序相反</span>
<span class="kt">void</span> <span class="n">add</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">w</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">edge</span><span class="p">[</span><span class="n">tot</span><span class="p">].</span><span class="n">u</span> <span class="o">=</span> <span class="n">u</span><span class="p">;</span>
    <span class="n">edge</span><span class="p">[</span><span class="n">tot</span><span class="p">].</span><span class="n">v</span> <span class="o">=</span> <span class="n">v</span><span class="p">;</span>
    <span class="n">edge</span><span class="p">[</span><span class="n">tot</span><span class="p">].</span><span class="n">w</span> <span class="o">=</span> <span class="n">w</span><span class="p">;</span>
    <span class="n">edge</span><span class="p">[</span><span class="n">tot</span><span class="p">].</span><span class="n">next</span> <span class="o">=</span> <span class="n">head</span><span class="p">[</span><span class="n">u</span><span class="p">];</span>
    <span class="n">head</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="n">tot</span><span class="o">++</span><span class="p">;</span>          <span class="c1">// 将当前新加的边保存到 head[u]，已有的边接在 edge[head[u]].next</span>
<span class="p">}</span>

<span class="c1">// 如果是树的话，使用 pre 记录父节点防止重复遍历</span>
<span class="kt">void</span> <span class="n">dfs1</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="kt">int</span> <span class="n">pre</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">u</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">head</span><span class="p">[</span><span class="n">u</span><span class="p">];</span> <span class="n">i</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">=</span> <span class="n">edge</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">next</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">edge</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">v</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">v</span> <span class="o">!=</span> <span class="n">pre</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">dfs1</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">u</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 如果是图的话(特指带环图)，就必须使用 vis 标记</span>
<span class="kt">void</span> <span class="n">dfs2</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">u</span><span class="p">);</span>
    <span class="n">vis</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">head</span><span class="p">[</span><span class="n">u</span><span class="p">];</span> <span class="n">i</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">=</span> <span class="n">edge</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">next</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">edge</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">v</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">vis</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="p">{</span>
            <span class="n">dfs2</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">init</span><span class="p">();</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">dfs1</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>

    <span class="n">puts</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

    <span class="n">init</span><span class="p">();</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">dfs2</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="vector">Vector</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 邻接数组写起来稍微有点麻烦</span>
<span class="c1">// 很多时候可以直接使用 STL 中的 vector 实现</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstring&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define N 100010
</span>
<span class="kt">int</span> <span class="n">vis</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">vec</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>

<span class="kt">void</span> <span class="nf">init</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">memset</span><span class="p">(</span><span class="n">vis</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">vis</span><span class="p">));</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">vec</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">clear</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 添加双向边</span>
<span class="kt">void</span> <span class="n">add</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="kt">int</span> <span class="n">v</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">vec</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
    <span class="n">vec</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">u</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// 遍历</span>
<span class="kt">void</span> <span class="n">dfs</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">u</span><span class="p">);</span>
    <span class="n">vis</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">vec</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">vec</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">i</span><span class="p">];</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">vis</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="p">{</span>
            <span class="n">dfs</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">init</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="n">add</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="n">dfs</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="树问题">树问题</h2>

<h3 id="最近公共祖先">最近公共祖先</h3>

<h3 id="树的直径">树的直径</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 树的直径：树中相距最远的两个节点之间的距离
 *
 * 方法1：树上 DP
 * 方法2：从树上任意一节点出发 dfs/bfs 找到最远的节点 u，再从节点 u 出发找到最远的节点 v，路径 uv 即为树的直径
 *       证明：https://www.luogu.com.cn/blog/Loveti/problem-tree
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define MAX 100
</span>
<span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">dp</span><span class="p">[</span><span class="n">MAX</span><span class="p">][</span><span class="mi">2</span><span class="p">];</span> <span class="c1">// dp[u][0/1] 分别表示以节点 u 为根节点的最长、次长路径长度</span>
<span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">edges</span><span class="p">[</span><span class="n">MAX</span><span class="p">];</span>

<span class="kt">void</span> <span class="nf">dfs1</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="kt">int</span> <span class="n">pre</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">edges</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">edges</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">i</span><span class="p">];</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">v</span> <span class="o">!=</span> <span class="n">pre</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">dfs1</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">u</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&gt;=</span> <span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span> <span class="p">{</span> <span class="c1">// 儿子最长 + 1 &gt;= 当前最长，更新最长和次长</span>
                <span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span>
                <span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&gt;</span> <span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">1</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">solve1</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">dfs1</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="kt">int</span> <span class="n">ans</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">ans</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">ans</span><span class="p">,</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">1</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">pos</span><span class="p">;</span> <span class="c1">// 最远的节点下标、距离</span>
<span class="kt">int</span> <span class="n">dis</span><span class="p">;</span>

<span class="kt">void</span> <span class="n">dfs2</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="kt">int</span> <span class="n">pre</span><span class="p">,</span> <span class="kt">int</span> <span class="n">d</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">d</span> <span class="o">&gt;</span> <span class="n">dis</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">pos</span> <span class="o">=</span> <span class="n">u</span><span class="p">;</span>
        <span class="n">dis</span> <span class="o">=</span> <span class="n">d</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">edges</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">edges</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">i</span><span class="p">];</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">v</span> <span class="o">!=</span> <span class="n">pre</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">dfs2</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span> <span class="n">d</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">solve2</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">dis</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">dfs2</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

    <span class="n">dis</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">dfs2</span><span class="p">(</span><span class="n">pos</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">dis</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/*
ans=5
9 8
1 2
1 3
1 4
2 5
2 6
6 7
6 8
4 9
*/</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">n</span> <span class="o">&gt;&gt;</span> <span class="n">m</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">;</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">u</span> <span class="o">&gt;&gt;</span> <span class="n">v</span><span class="p">;</span>
        <span class="n">edges</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
        <span class="n">edges</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">u</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">solve1</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span> <span class="o">&lt;&lt;</span> <span class="n">solve2</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="树的重心">树的重心</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 树的重心
 *
 * 对于树上的每一个点，计算其所有子树中(含父子树)最大的子树节点数，这个值最小的点就是这棵树的重心
 *
 * 性质
 * - 以树的重心为根时，所有子树的大小都不超过整棵树大小的一半
 * - 树中所有点到某个点的距离和中，到重心的距离和是最小的；如果有两个重心，那么到它们的距离和一样
 * - 把两棵树通过一条边相连得到一棵新的树，那么新的树的重心在连接原来两棵树的重心的路径上
 * - 在一棵树上添加或删除一个叶子，那么它的重心最多只移动一条边的距离
 *
 * 用途
 * 在树分治中，每次选择子树的重心作为根节点，可以保证递归层数最少
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;queue&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define MAX 100
</span>
<span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">rt</span><span class="p">;</span>                  <span class="c1">// 重心</span>
<span class="kt">int</span> <span class="n">size</span><span class="p">[</span><span class="n">MAX</span><span class="p">];</span>           <span class="c1">// size[u]： 以 u 为根节点的子树的大小</span>
<span class="kt">int</span> <span class="n">wsize</span><span class="p">[</span><span class="n">MAX</span><span class="p">];</span>          <span class="c1">// wsize[u]：以 u 为根节点的子树的最大子树的大小</span>

<span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">edges</span><span class="p">[</span><span class="n">MAX</span><span class="p">];</span>

<span class="kt">void</span> <span class="nf">dfs</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="kt">int</span> <span class="n">pre</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">size</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">wsize</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">edges</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">edges</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">i</span><span class="p">];</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">v</span> <span class="o">!=</span> <span class="n">pre</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">dfs</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">u</span><span class="p">);</span>
            <span class="n">size</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+=</span> <span class="n">size</span><span class="p">[</span><span class="n">v</span><span class="p">];</span>
            <span class="n">wsize</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">wsize</span><span class="p">[</span><span class="n">u</span><span class="p">],</span> <span class="n">size</span><span class="p">[</span><span class="n">v</span><span class="p">]);</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">wsize</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">wsize</span><span class="p">[</span><span class="n">u</span><span class="p">],</span> <span class="n">n</span> <span class="o">-</span> <span class="n">size</span><span class="p">[</span><span class="n">u</span><span class="p">]);</span> <span class="c1">// 父子树</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">rt</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">wsize</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">wsize</span><span class="p">[</span><span class="n">rt</span><span class="p">])</span> <span class="n">rt</span> <span class="o">=</span> <span class="n">u</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">solve</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">dfs</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">rt</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/*
ans=2
9 8
1 2
1 3
1 4
2 5
2 6
6 7
6 8
4 9
*/</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">n</span> <span class="o">&gt;&gt;</span> <span class="n">m</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">;</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">u</span> <span class="o">&gt;&gt;</span> <span class="n">v</span><span class="p">;</span>
        <span class="n">edges</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
        <span class="n">edges</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">u</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">solve</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="树分治">树分治</h3>

<h3 id="生成树">生成树</h3>

<h4 id="最小生成树">最小生成树</h4>

<p>最小生成树(Minimum Spanning Tree，MST)指在无向连通图中，边权和最小的生成树</p>

<h5 id="prim">Prim</h5>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 最小生成树(Minimum Spanning Tree，MST)指在无向连通图中，边权和最小的生成树
 *
 * Prim 算法，时间复杂度：O(n^2)
 * (1) 将图的节点分为两部分，一部分是已在 mst 的点，一部分是待加入 mst 的点
 * (2) 随机选择一个节点 v1 作为起点 加入 mst，每次迭代选择距离 mst 最近的点 v2，将对应边加入 mst 中，同时更新未在 mst 中的点到 mst 的最小距离，迭代 n - 1 次即可
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstring&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define INF 0x3f3f3f3f
#define N 1010
</span>
<span class="kt">int</span> <span class="n">mpt</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>  <span class="c1">// mpt[i][j] 表示节点 i 到节点 j 的距离，INF 表示不可达</span>
<span class="kt">int</span> <span class="n">dis</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>     <span class="c1">// dis[i] 表示节点 i 离 mst 的最小距离(即距离 mst 中最近的点的距离)，已加入 mst 中的点对应 dis 为 -1</span>

<span class="kt">void</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">memset</span><span class="p">(</span><span class="n">mpt</span><span class="p">,</span> <span class="n">INF</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">mpt</span><span class="p">));</span> <span class="c1">// 初始化邻接矩阵所有边权值为 INF，表示相互都不可达</span>
<span class="p">}</span>

<span class="c1">// 任选一个起点</span>
<span class="kt">int</span> <span class="n">prim</span><span class="p">(</span><span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">ans</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 初始化 dis 为起点到各个点的距离</span>
        <span class="n">dis</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="n">s</span><span class="p">][</span><span class="n">j</span><span class="p">];</span>
    <span class="p">}</span>
    <span class="n">dis</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 迭代 n - 1 次</span>
        <span class="kt">int</span> <span class="n">min_k</span> <span class="o">=</span> <span class="n">INF</span><span class="p">,</span> <span class="n">k</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dis</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">dis</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">min_k</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 每次迭代选择一个距离 mst 最近的点加入 mst</span>
                <span class="n">min_k</span> <span class="o">=</span> <span class="n">dis</span><span class="p">[</span><span class="n">k</span> <span class="o">=</span> <span class="n">j</span><span class="p">];</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">min_k</span> <span class="o">==</span> <span class="n">INF</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 构不成 mst，非无向连通图</span>
            <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">dis</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
        <span class="n">ans</span> <span class="o">+=</span> <span class="n">min_k</span><span class="p">;</span> <span class="c1">// 将对应边加入 mst，更新 mst 权值和</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 更新其他点到 mst 中的最小距离(即 mst 中加入节点 k 后的变化)</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dis</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">mpt</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">dis</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="p">{</span>
                <span class="n">dis</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">j</span><span class="p">];</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">init</span><span class="p">();</span>

    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
    <span class="n">mpt</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
    <span class="n">mpt</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="n">mpt</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
    <span class="n">mpt</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="mi">4</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">mpt</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="mi">6</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="n">mpt</span><span class="p">[</span><span class="mi">4</span><span class="p">][</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="mi">6</span><span class="p">][</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
    <span class="n">mpt</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="mi">6</span><span class="p">][</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
    <span class="n">mpt</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="mi">5</span><span class="p">][</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
    <span class="n">mpt</span><span class="p">[</span><span class="mi">5</span><span class="p">][</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="mi">6</span><span class="p">][</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">prim</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="p">));</span> <span class="c1">// 17</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h5 id="kruskal">Kruskal</h5>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * Kruskal 算法，时间复杂度：O(M * logM)
 *
 * 思想：一开始所有的点都是独立的，将所有边按权值从小到达排列，然后依次判断边的两端是否在不同的集合中(使用并查集维护)，如果是则添加这条边到 mst
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstring&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define N 110
#define M 10010
</span>
<span class="k">struct</span> <span class="nc">Edge</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">st</span><span class="p">,</span> <span class="n">to</span><span class="p">,</span> <span class="n">val</span><span class="p">;</span> <span class="c1">// 这里表示双向边</span>
    <span class="kt">bool</span> <span class="k">operator</span><span class="o">&lt;</span><span class="p">(</span><span class="k">const</span> <span class="n">Edge</span> <span class="o">&amp;</span><span class="n">t</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">val</span> <span class="o">&lt;</span> <span class="n">t</span><span class="p">.</span><span class="n">val</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span> <span class="n">edge</span><span class="p">[</span><span class="n">M</span><span class="p">];</span>

<span class="kt">int</span> <span class="n">f</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>

<span class="kt">void</span> <span class="n">init</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">f</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">find</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o">!=</span> <span class="n">f</span><span class="p">[</span><span class="n">x</span><span class="p">])</span> <span class="n">f</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">find</span><span class="p">(</span><span class="n">f</span><span class="p">[</span><span class="n">x</span><span class="p">]);</span>
    <span class="k">return</span> <span class="n">f</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
<span class="p">}</span>

<span class="kt">bool</span> <span class="n">un</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">find</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
    <span class="n">y</span> <span class="o">=</span> <span class="n">find</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o">!=</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">f</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">y</span><span class="p">;</span>
        <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">kruskal</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">m</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">cnt</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">ans</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">sort</span><span class="p">(</span><span class="n">edge</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">edge</span> <span class="o">+</span> <span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">un</span><span class="p">(</span><span class="n">edge</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">st</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">to</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">ans</span> <span class="o">+=</span> <span class="n">edge</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">val</span><span class="p">;</span>
            <span class="n">cnt</span><span class="o">++</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">cnt</span> <span class="o">!=</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">6</span><span class="p">,</span> <span class="n">m</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
    <span class="n">init</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>

    <span class="n">edge</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">st</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">to</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">val</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
    <span class="n">edge</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">st</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">to</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">val</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="n">edge</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">st</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">to</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">val</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
    <span class="n">edge</span><span class="p">[</span><span class="mi">4</span><span class="p">].</span><span class="n">st</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">4</span><span class="p">].</span><span class="n">to</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">4</span><span class="p">].</span><span class="n">val</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">edge</span><span class="p">[</span><span class="mi">5</span><span class="p">].</span><span class="n">st</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">5</span><span class="p">].</span><span class="n">to</span> <span class="o">=</span> <span class="mi">6</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">5</span><span class="p">].</span><span class="n">val</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="n">edge</span><span class="p">[</span><span class="mi">6</span><span class="p">].</span><span class="n">st</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">6</span><span class="p">].</span><span class="n">to</span> <span class="o">=</span> <span class="mi">6</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">6</span><span class="p">].</span><span class="n">val</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
    <span class="n">edge</span><span class="p">[</span><span class="mi">7</span><span class="p">].</span><span class="n">st</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">7</span><span class="p">].</span><span class="n">to</span> <span class="o">=</span> <span class="mi">6</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">7</span><span class="p">].</span><span class="n">val</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
    <span class="n">edge</span><span class="p">[</span><span class="mi">8</span><span class="p">].</span><span class="n">st</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">8</span><span class="p">].</span><span class="n">to</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">8</span><span class="p">].</span><span class="n">val</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
    <span class="n">edge</span><span class="p">[</span><span class="mi">9</span><span class="p">].</span><span class="n">st</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">9</span><span class="p">].</span><span class="n">to</span> <span class="o">=</span> <span class="mi">6</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">9</span><span class="p">].</span><span class="n">val</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">kruskal</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">));</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="次小生成树">次小生成树</h4>

<h4 id="最小树形图">最小树形图</h4>

<h2 id="最短路">最短路</h2>

<h3 id="dijkstra">Dijkstra</h3>

<h3 id="floyd">Floyd</h3>

<h3 id="k短路">K短路</h3>

<h2 id="连通图">连通图</h2>

<h2 id="匹配">匹配</h2>

<h3 id="二分匹配">二分匹配</h3>

<h2 id="查分约束">查分约束</h2>

<h2 id="2-sat">2-SAT</h2>

<h2 id="网络流">网络流</h2>

<h3 id="最大流">最大流</h3>

<h3 id="费用流">费用流</h3>

<h2 id="其他">其他</h2>

<h3 id="环路">环路</h3>

<h4 id="无向图">无向图</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 无向图判断是否存在环
 *
 * 方法1：如果是连通图，如果边的数量(不含重边)超过 n - 1 条(树)，则必然存在环
 * 方法2：和 kruskal 类似，不断加入边，使用并查集维护，如果两个顶点在同一个集合，则存在环
 * 方法3：直接 dfs 搜索，如果存在环则必然会导致节点被重复访问。所以如果遍历过程中节点被访问过，则存在环
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;queue&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define MAX 100
</span>
<span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">vis</span><span class="p">[</span><span class="n">MAX</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">mpt</span><span class="p">[</span><span class="n">MAX</span><span class="p">][</span><span class="n">MAX</span><span class="p">];</span>

<span class="kt">bool</span> <span class="nf">dfs3</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="kt">int</span> <span class="n">pre</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">vis</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">v</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">v</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">v</span> <span class="o">!=</span> <span class="n">pre</span> <span class="o">&amp;&amp;</span> <span class="n">mpt</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">v</span><span class="p">])</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">vis</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> <span class="c1">// 存在环</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dfs3</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">u</span><span class="p">))</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">bool</span> <span class="n">check3</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">vis</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">dfs3</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">i</span><span class="p">))</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/*
ans=yes
3 3
1 2
2 3
3 1

ans=no
3 2
1 2
2 3

ans=yes
4 4
1 2
2 3
2 4
3 4

     1
    /
   2
  / \
 3 - 4
*/</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">n</span> <span class="o">&gt;&gt;</span> <span class="n">m</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">;</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">u</span> <span class="o">&gt;&gt;</span> <span class="n">v</span><span class="p">;</span>
        <span class="n">mpt</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">mpt</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">check3</span><span class="p">())</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"yes"</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"no"</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="有向图">有向图</h4>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * 有向图判断是否存在环
 * 复杂度：O(N+M)
 *
 * 方法1：拓扑排序
 * 实现：利用队列，不断将入度为 0 的点入队，出队时删除当前点到其相邻点的边(度数-1)，如果能遍历完所有点，则说明不存在环
 * 用途：可以用来检查偏序、依赖关系
 *
 * 方法2：DFS
 * 和无向图不一样的是，并不能简单地通过是否重复遍历判断，比如：A-&gt;B、A-&gt;C-&gt;B，节点 B 虽然被重复遍历了，但并不存在环
 * 这是因为遍历过程中没有区分边的方向，虽然节点 B 被重复访问了，但都是其他节点到节点 B
 *
 * 所以可以这样，将遍历标记数组元素分为 3 种状态：
 *
 * vis[i] = 0  节点未被访问
 * vis[i] = 1  节点正在被访问，从节点 i 出发，正在遍历与其相邻的节点，如果递归过程中发现有节点 vis = 1，则说明该节点在当前递归路径被重复访问了，存在一个"反向环路"，一定存在环
 * vis[i] = 2  节点被访问完成，即从节点 i 出发的相邻节点都被遍历完成，表示从节点 i 出发的子图中不存在环。
 *
 * vis[i] = 2  这其实相当于一个优化，也可以在节点访问完成时将 vis = 0，不过会造成图重复遍历，复杂度较高，大于 O(N^2)。有两个原因：
 *   (1) 我们需要从每个节点开始各遍历一次图，比如 B&lt;-A&lt;-C&lt;-D&lt;-E&lt;-C，如果只从 B 开始遍历，根本走不到环 CDE。而且以某个点为起点遍历时，必须情况 vis 数组，否则 B&lt;-A，先从 B 开始标记 B 已走过，再从 A 开始遍历则会遍历到 A，误判为存在环；而无向图则不用，因为无向图 A-&gt;B，那么一定 B-&gt;A
 *   (2) 在以同一个点为起点的遍历过程中也可能重复遍历，如 A-&gt;B/C-&gt;D-&gt;E-&gt;F&lt;-D，则以 A 为起点，会重复遍历 DEFD，第一次通过 B，第二次通过 C
 *
 * 如果遍历过程中，发现 vis[i] = 1，则存在环
 * 在上述例子中，第二次遍历到节点 B 时(A-&gt;C-&gt;B)，vis[B] = 2，说明从节点 B 出发的子图中不存在环，即使现在又有节点 C 出发访问了节点 B，也不存在环
 *
 * 方法3：DFS
 * 存在环的充要条件是：边被重复访问，是否可以通过判断边重复访问即可？vis[e]？
 *
 * 方法4：Tarjan (TODO)
 * 
 * https://leetcode-cn.com/problems/course-schedule/
 * https://mnunknown.gitbook.io/algorithm-notes/topological_sortff0c_tuo_pu_pai_xu/you_xiang__wu_xiang_tu_de_ji_ben_xing_zhi_he_cao_z
 */</span>

<span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;cstdio&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;queue&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="cp">#define MAX 100
</span>
<span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">in</span><span class="p">[</span><span class="n">MAX</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">vis</span><span class="p">[</span><span class="n">MAX</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">mpt</span><span class="p">[</span><span class="n">MAX</span><span class="p">][</span><span class="n">MAX</span><span class="p">];</span>

<span class="kt">bool</span> <span class="nf">check1</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">q</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">in</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="kt">int</span> <span class="n">cnt</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">q</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span>
        <span class="n">q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>
        <span class="n">cnt</span><span class="o">++</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">v</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">v</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">mpt</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">in</span><span class="p">[</span><span class="n">v</span><span class="p">]</span><span class="o">--</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">in</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">cnt</span> <span class="o">!=</span> <span class="n">n</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">bool</span> <span class="n">dfs2</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">vis</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">v</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">v</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">mpt</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">v</span><span class="p">])</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">vis</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">vis</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">dfs2</span><span class="p">(</span><span class="n">v</span><span class="p">))</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> <span class="c1">// vis[v] = 2 则不用继续搜索</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="n">vis</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">bool</span> <span class="n">check2</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">vis</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">dfs2</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/*
ans=yes
3 3
1 2
2 3
3 1

ans=no
3 2
1 2
2 3

ans=no
4 4
1 2
2 3
2 4
3 4

     1
    /
   2
  / \
 v   v
 3 -&gt; 4

ans=yes
4 4
1 2
2 3
3 4
4 2

     1
    /
   2
  / ^
 v   \
 3 -&gt; 4

*/</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">n</span> <span class="o">&gt;&gt;</span> <span class="n">m</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">;</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">u</span> <span class="o">&gt;&gt;</span> <span class="n">v</span><span class="p">;</span>
        <span class="n">mpt</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// u &gt; v</span>
        <span class="n">in</span><span class="p">[</span><span class="n">v</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">check1</span><span class="p">()</span> <span class="o">?</span> <span class="s">"yes"</span> <span class="o">:</span> <span class="s">"no"</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">check2</span><span class="p">()</span> <span class="o">?</span> <span class="s">"yes"</span> <span class="o">:</span> <span class="s">"no"</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="欧拉图">欧拉图</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// TODO</span>
</code></pre></div></div>

<h1 id="字符串">字符串</h1>

<h2 id="manacher">Manacher</h2>

<h2 id="kmp">KMP</h2>

<h2 id="ac自动机">AC自动机</h2>

<h2 id="后缀数组">后缀数组</h2>

<h1 id="计算几何">计算几何</h1>]]></content><author><name>朱元朝</name><email>452181625@qq.com</email></author><category term="学习" /><summary type="html"><![CDATA[ACM 打酱油选手，简单复习一下已经忘了很久的常用算法]]></summary></entry></feed>