Переглянути джерело

课程:完成主题课程与历年真题

Codex Agent 1 місяць тому
коміт
7c67679b80
100 змінених файлів з 4189 додано та 0 видалено
  1. 2 0
      .gitignore
  2. 122 0
      AGENTS.md
  3. 166 0
      scripts/audit_mhtml.py
  4. 63 0
      scripts/check_course_docs.py
  5. 320 0
      scripts/extract_reference_attachments.py
  6. 78 0
      scripts/verify_markdown_cpp.py
  7. 14 0
      主题.md
  8. 75 0
      参考实现/01-欧拉路径/CodeForces-508D.cpp
  9. 72 0
      参考实现/01-欧拉路径/CodeForces-723E.cpp
  10. 56 0
      参考实现/01-欧拉路径/HDU-1116.cpp
  11. 34 0
      参考实现/01-欧拉路径/POJ-2230.cpp
  12. 80 0
      参考实现/02-强连通与双连通/CodeForces-1000E.cpp
  13. 56 0
      参考实现/02-强连通与双连通/CodeForces-427C.cpp
  14. 91 0
      参考实现/02-强连通与双连通/CodeForces-732F.cpp
  15. 55 0
      参考实现/02-强连通与双连通/CodeForces-962F.cpp
  16. 48 0
      参考实现/02-强连通与双连通/POJ-1144.cpp
  17. 48 0
      参考实现/02-强连通与双连通/POJ-1236.cpp
  18. 42 0
      参考实现/02-强连通与双连通/POJ-2186.cpp
  19. 58 0
      参考实现/02-强连通与双连通/POJ-3177.cpp
  20. 25 0
      参考实现/03-Bitset/AtCoder-abc258_g.cpp
  21. 51 0
      参考实现/03-Bitset/CodeForces-1097F.cpp
  22. 36 0
      参考实现/03-Bitset/CodeForces-914F.cpp
  23. 52 0
      参考实现/04-KMP与Manacher/CodeForces-17E.cpp
  24. 28 0
      参考实现/04-KMP与Manacher/CodeForces-432D.cpp
  25. 32 0
      参考实现/04-KMP与Manacher/CodeForces-471D.cpp
  26. 22 0
      参考实现/04-KMP与Manacher/POJ-2406.cpp
  27. 30 0
      参考实现/04-KMP与Manacher/POJ-3461.cpp
  28. 32 0
      参考实现/04-KMP与Manacher/POJ-3974.cpp
  29. 39 0
      参考实现/05-最短路与类最短路/AtCoder-abc277_e.cpp
  30. 30 0
      参考实现/05-最短路与类最短路/AtCoder-abc340_d.cpp
  31. 42 0
      参考实现/05-最短路与类最短路/CodeForces-229B.cpp
  32. 50 0
      参考实现/05-最短路与类最短路/CodeForces-449B.cpp
  33. 46 0
      参考实现/05-最短路与类最短路/CodeForces-545E.cpp
  34. 49 0
      参考实现/05-最短路与类最短路/CodeForces-59E.cpp
  35. 45 0
      参考实现/05-最短路与类最短路/POJ-3169.cpp
  36. 39 0
      参考实现/05-最短路与类最短路/POJ-3255.cpp
  37. 36 0
      参考实现/06-最小与最大生成树/AtCoder-arc076_b.cpp
  38. 35 0
      参考实现/06-最小与最大生成树/CodeForces-1095F.cpp
  39. 34 0
      参考实现/06-最小与最大生成树/CodeForces-1245D.cpp
  40. 65 0
      参考实现/06-最小与最大生成树/CodeForces-160D.cpp
  41. 74 0
      参考实现/06-最小与最大生成树/CodeForces-1706E.cpp
  42. 66 0
      参考实现/06-最小与最大生成树/CodeForces-609E.cpp
  43. 53 0
      参考实现/06-最小与最大生成树/CodeForces-888G.cpp
  44. 48 0
      参考实现/07-二分图/CodeForces-1139E.cpp
  45. 26 0
      参考实现/07-二分图/CodeForces-1144F.cpp
  46. 51 0
      参考实现/07-二分图/CodeForces-1354E.cpp
  47. 83 0
      参考实现/07-二分图/CodeForces-498C.cpp
  48. 30 0
      参考实现/07-二分图/CodeForces-741C.cpp
  49. 49 0
      参考实现/07-二分图/HDU-2255.cpp
  50. 27 0
      参考实现/07-二分图/POJ-1274.cpp
  51. 23 0
      参考实现/07-二分图/POJ-3041.cpp
  52. 5 0
      参考实现/08-高级线段树与树状数组/CSES-1737.cpp
  53. 6 0
      参考实现/08-高级线段树与树状数组/CodeForces-1042D.cpp
  54. 8 0
      参考实现/08-高级线段树与树状数组/CodeForces-1114F.cpp
  55. 6 0
      参考实现/08-高级线段树与树状数组/CodeForces-438D.cpp
  56. 6 0
      参考实现/08-高级线段树与树状数组/CodeForces-459D.cpp
  57. 7 0
      参考实现/08-高级线段树与树状数组/CodeForces-558E.cpp
  58. 6 0
      参考实现/08-高级线段树与树状数组/CodeForces-61E.cpp
  59. 6 0
      参考实现/08-高级线段树与树状数组/CodeForces-920F.cpp
  60. 7 0
      参考实现/08-高级线段树与树状数组/HDU-5306.cpp
  61. 37 0
      参考实现/08-高级线段树与树状数组/HYSBZ-2212.cpp
  62. 65 0
      参考实现/08-高级线段树与树状数组/HYSBZ-4552.cpp
  63. 8 0
      参考实现/08-高级线段树与树状数组/SPOJ-COT.cpp
  64. 6 0
      参考实现/08-高级线段树与树状数组/SPOJ-MKTHNUM.cpp
  65. 7 0
      参考实现/09-基环树/CodeForces-1027D.cpp
  66. 5 0
      参考实现/09-基环树/CodeForces-1454E.cpp
  67. 5 0
      参考实现/09-基环树/CodeForces-711D.cpp
  68. 4 0
      参考实现/10-高斯消元与CRT/AtCoder-abc186_e.cpp
  69. 3 0
      参考实现/10-高斯消元与CRT/POJ-1006.cpp
  70. 5 0
      参考实现/10-高斯消元与CRT/POJ-1222.cpp
  71. 4 0
      参考实现/10-高斯消元与CRT/POJ-1830.cpp
  72. 3 0
      参考实现/10-高斯消元与CRT/POJ-2891.cpp
  73. 5 0
      参考实现/10-高斯消元与CRT/POJ-2947.cpp
  74. 7 0
      参考实现/11-平衡树/CSES-2072.cpp
  75. 7 0
      参考实现/11-平衡树/CSES-2073.cpp
  76. 4 0
      参考实现/11-平衡树/CSES-2074.cpp
  77. 6 0
      参考实现/11-平衡树/POJ-1442.cpp
  78. 6 0
      参考实现/11-平衡树/POJ-3481.cpp
  79. 4 0
      参考实现/11-平衡树/SPOJ-ORDERSET.cpp
  80. 6 0
      参考实现/12-历年真题/洛谷-P10217.cpp
  81. 6 0
      参考实现/12-历年真题/洛谷-P11232.cpp
  82. 6 0
      参考实现/12-历年真题/洛谷-P11233.cpp
  83. 183 0
      参考实现/12-历年真题/洛谷-P11833.cpp
  84. 266 0
      参考实现/12-历年真题/洛谷-P15653.cpp
  85. 8 0
      参考实现/12-历年真题/洛谷-P1850.cpp
  86. 8 0
      参考实现/12-历年真题/洛谷-P3953.cpp
  87. 7 0
      参考实现/12-历年真题/洛谷-P5022.cpp
  88. 4 0
      参考实现/12-历年真题/洛谷-P5664.cpp
  89. 5 0
      参考实现/12-历年真题/洛谷-P7077.cpp
  90. 5 0
      参考实现/12-历年真题/洛谷-P7914.cpp
  91. 179 0
      参考实现/12-历年真题/洛谷-P8294.cpp
  92. 6 0
      参考实现/12-历年真题/洛谷-P8817.cpp
  93. 8 0
      参考实现/12-历年真题/洛谷-P8818.cpp
  94. 7 0
      参考实现/12-历年真题/洛谷-P9166.cpp
  95. 223 0
      参考实现/12-历年真题/洛谷-P9167.cpp
  96. 12 0
      参考实现/12-历年真题/洛谷-P9169.cpp
  97. 6 0
      参考实现/12-历年真题/洛谷-P9753.cpp
  98. 9 0
      参考实现/12-历年真题/洛谷-P9755.cpp
  99. 60 0
      课程/00-CF2400-2700高阶扩展路线.md
  100. 99 0
      课程/00-课程使用说明.md

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+problems/
+.commandcode/

+ 122 - 0
AGENTS.md

@@ -0,0 +1,122 @@
+# AGENTS.md
+
+## 项目目标
+
+本仓库用于为一名处于“提高+ / 省选-”阶段的中国信息学竞赛学生生成可独立学习的课程资料。目标不是罗列知识点,而是让读者在没有原课程的情况下,也能经历接近课堂的引导、推导、例题分析、编码与复盘过程。
+
+`主题.md` 是课程范围的动态来源。它可能随时增加或调整主题;开始任何课程生成、课程索引更新或习题整理任务前,都必须重新读取它,不能依赖之前记忆的主题列表。
+
+## 默认语言与读者水平
+
+- 正文使用简体中文,术语首次出现时给出常见英文名,方便检索英文资料。
+- 默认读者已掌握 C++ 基础、常见 STL、基础复杂度分析、基础图论与基础动态规划,但仍应在正文开头明确列出本节真正依赖的前置知识。
+- 难度定位高于普及组常规内容,面向提高组高阶到省选入门;避免用大量模板题堆砌篇幅。
+- 数学公式使用 LaTeX。多行展示公式必须用独占行的 `$$` 作为起止定界符,禁止使用当前查看器无法正确渲染的方括号式展示定界符。
+- 正文算法核心使用类 Python 伪代码,突出状态、转移、不变量和数据流,不让 C++ 容器与工程细节淹没推导。完整代码默认使用可提交的 GNU C++17,并作为独立附件保存。
+
+## 内容组织
+
+- 一个大主题应拆成若干边界清晰、可以独立学习的子主题 Markdown 文档,不要把整类算法塞进一个超长文件。
+- 课程文档统一放入 `课程/`。目录与文件名前加两位数字编号,顺序尽量遵循依赖关系;新增主题时不要无故重排已有编号或破坏现有链接。
+- `课程/README.md` 作为总索引,记录主题、子主题、前置依赖、建议顺序和完成状态。只有实际完成并通过质量检查的文档才能标为完成。
+- 同一主题内部应从概念和不变量逐步走到模型辨认、算法推导、实现、变式与综合题。若某个主题跨度很大,先写概览,再拆出独立小节。
+- 不改写或删除用户在 `主题.md` 中的内容,除非用户明确要求。
+
+## 每篇课程文档的最低结构
+
+标题可以按内容微调,但每篇应覆盖以下信息:
+
+1. **本节目标**:学完后能够判断、证明、实现什么。
+2. **前置知识与课前自测**:给出少量能暴露知识缺口的问题;答案放在后文或折叠区,避免立即泄露。
+3. **问题动机**:从一个具体问题或反例出发,说明朴素做法为什么不够。
+4. **步步式引导**:用一连串短问题推进;先让读者观察,再引入定义、性质和算法。关键结论不能凭空给出。
+5. **核心知识**:准确定义、关键不变量、推导或证明、正确性说明、时间与空间复杂度。
+6. **实现指南**:数据结构选择、类 Python 核心伪代码、边界处理、常见错误和调试办法。伪代码必须说明状态与变量含义、适用条件和失效边界;完整 C++17 不在正文中大段铺开。
+7. **扩展与联系**:至少包含有价值的变式、与相邻知识点的联系,或算法失效的边界;不要为了“扩展”堆冷知识。
+8. **精选例题**:按下述统一格式编写。
+9. **总结与自检**:用可回答的问题检查是否真正理解,而不只是背下模板。
+10. **课后训练建议**:给出做题顺序、卡题多久看哪一级 Hint、做完后的复盘点。
+
+## 步步式引导要求
+
+- 采用“问题 -> 尝试 -> 反例/瓶颈 -> 新观察 -> 形式化结论 -> 实现”的节奏。
+- 重要算法至少展示一次从朴素方案到目标复杂度的自然演化。
+- 每引入一个关键技巧,都回答三个问题:它解决了什么瓶颈、为什么正确、在什么条件下不能用。
+- 对容易混淆的概念提供最小反例或对照案例。例如定义相似但适用条件不同的算法,应明确区分。
+- 不要让引导问题变成只有“是/否”的装饰;问题应能促使读者写出状态、画图、构造反例或估算复杂度。
+- 对关键推导设置停顿提示,让读者先独立思考,再展开答案。
+
+## 精选例题规范
+
+例题平台按以下优先级选择:**VJudge 最优先**,其次考虑 Codeforces、AtCoder、黑暗爆炸。应先检索并优先给出可稳定访问、题面与数据范围可核验的 VJudge 条目;若 VJudge 聚合页信息不足,再同时给出原题页用于补全和核验。不要为了满足平台偏好而选择质量较差或重复度高的题。
+
+每道正式例题必须包含:
+
+- **来源信息**:平台、题号、题名、可点击链接,以及大致难度和主要考点。
+- **题目描述**:用中文自包含地转述题意,不要大段复制受版权保护的原题面;保留会影响建模的条件。
+- **输入输出与数据范围**:只写经过来源核验的信息;不确定时明确标注待核验,禁止猜测或编造。
+- **样例解释**:当样例对理解模型有帮助时给出,而不是机械抄录。
+- **分级 Hint**:通常设置 3--5 级,从模型识别、关键性质、算法框架到实现提醒逐层接近答案。相邻两级不能只是换一种说法。
+- **Observations**:按考虑顺序列出数据范围给出的信号、被排除的复杂度、自然但失败的尝试及最小反例、真正改变对象/状态/复杂度的观察。每条观察都要说明它删掉了什么搜索、状态或转移,不能只罗列结论。
+- **Editorial**:详细还原“约束分析 -> 朴素方案 -> 瓶颈 -> 关键转化 -> 形式化模型 -> 目标算法”的考虑链;再分别证明每一步合法、为何不漏解或重复、最优化下界如何达到、终止时为何得到答案,并把复杂度代回本题范围。不能只说“套某模板”。
+- **实现细节**:下标、初始化、图的方向、重复边、自环、溢出、递归深度、常数、特殊数据等与本题有关的事项。
+- **核心伪代码与参考实现附件**:正文只放类 Python 核心伪代码。GNU C++17 完整代码统一保存到仓库根目录 `参考实现/<主题>/OJ-题号.cpp`,正文提供相对链接。附件需与正文算法一致、可独立编译;可以核验时应使用样例或小规模对拍验证。
+- **复盘与变式**:指出本题的识别信号、可迁移技巧,并给出至少一个改变条件后的思考题。
+
+提示与题解应使用 HTML `details` 折叠区或清楚的分隔,确保读者能逐级查看而不会一眼看到完整答案。
+
+## 选题原则
+
+- 每个子主题通常安排 2--4 道核心例题:至少一题用于建立模型,一题需要组合技巧或非直接模板化观察;必要时再加入一题实现或证明导向题。
+- 控制同质题数量。若两题的唯一差别只是换皮或参数,应保留更有代表性的一题。
+- 题目应与当前讲义中已经建立的工具匹配;如必须使用尚未学习的算法,明确标为“选学”并给出依赖跳转。
+- 难度形成梯度,但不能用一道明显过难的题代替必要的中间台阶。
+- 历年真题主题应按知识依赖和思维价值组织,不只按年份堆列表;涉及多个算法时链接回对应子主题。
+
+## 高阶扩展选题与深度
+
+- “每个课程”的高阶扩展默认按 `主题.md` 中的算法大主题计算,不按每篇子文档机械乘题量;历年真题仍保持中国竞赛真题体系。
+- 每个算法大主题通常精选 3 道 Codeforces 2400--2700 或思维强度相当的 AtCoder Grand Contest 题。只有核心转化彼此独立、确有新增学习价值时才增加到 4 道。
+- 转化巧妙优先于评分和模板复杂度。优先选择需要改变研究对象、反向建模、补图/对偶、隐式图、参数化、状态压缩、势能或代数化表达的题。
+- 不用“高级模板 + 常规套用”凑深度。若去掉算法名后只剩普通分层图、直接 CRT、常规矩阵 Lazy 或同一模板换参数,应降为练习或删除,不占高阶扩展名额。
+- 控制套路密度。同一主题的高阶题必须承担不同思维任务;两题若关键考虑链相同,只保留转化更典型、来源更稳定的一题。
+- 可以偶尔加入一题 2800+ 的构造、交互或弱相关灵活性题,但要明确标为“灵活性实验室”、不作为后续硬前置。交互题需提供最小本地模拟器,并明确本地验证不等价于在线通过。
+- 高阶例题即使读者不独立提交,也应提供充分的“不做题收获”:读者仅阅读题面转述、Observations、Editorial、证明和伪代码,也能复述识别信号、核心转化与失效条件。
+
+## 外部资料核验
+
+- 整理例题前应联网核对题号、题名、链接、输入输出、数据范围和特殊限制。技术说明优先使用原题、官方题解或主办方资料;VJudge 可作为统一入口,但不能用聚合页猜测缺失信息。
+- 链接失效或平台当前不可访问时,如实记录核验状态并寻找原始来源或可靠镜像,不能伪造内容。
+- 区分原题事实、官方结论和本文推导;若采用非官方解法,应自行检查正确性。
+
+## 代码与正确性质量门槛
+
+- 所有参考代码至少应通过本地 `g++ -std=c++17 -Wall -Wextra` 编译。
+- 有样例时运行样例;适合暴力校验的算法,优先增加小规模随机对拍。若因外部条件无法执行,要在交付说明中明确未验证项。
+- 复杂度必须结合题目数据范围说明是否可行,不能只孤立地写一个大 O。
+- 正确性证明至少覆盖:算法维护的状态/不变量、每一步为何合法、为何不会漏解或重复计数、终止时为何得到目标答案。
+- 文档中的公式、伪代码、参考实现三者必须使用同一套定义与下标约定。
+- 课程正文不得内嵌带 `main` 的完整 C++ 程序;完整程序必须通过附件链接提供。自动检查应拒绝旧展示公式定界符、缺失附件或正文内嵌完整程序。
+- 禁止编造题目、来源、数据范围、评测结果或“已通过”状态。
+
+## 执行流程
+
+1. 每次先读取最新的 `主题.md`、`课程/README.md`(若存在)和目标章节已有内容。
+2. 明确本次覆盖的子主题、前置知识与预期难度;范围较大时先列可执行计划。
+3. 核验候选题来源,去掉重复、失效或依赖超纲的题。
+4. 先完成知识推导,再写例题 Hint、Observations 与 Editorial;确认考虑链能从题面约束自然导向算法后,再写核心伪代码、实现附件和复盘。
+5. 编译并尽可能运行所有新增附件;检查正文到附件的相对链接、内部链接、题目链接、术语、公式定界符、复杂度和数据范围。
+6. 更新总索引和完成状态,并在交付时列出已验证与尚未验证的部分。
+
+## 写作禁忌
+
+- 不写只有定义、板子和题单的“速查表式课程”,除非用户明确要求速查表。
+- 不把完整题解提前泄露在第一级 Hint 中。
+- 不用“显然”“容易发现”“不难证明”跳过关键推理。
+- 不虚构课堂互动、学生反馈、题目数据或在线评测结果。
+- 不为了显得高级而加入与学习目标无关的艰深内容。
+- 不在未检查全文依赖时批量重命名文件或调整编号。
+
+## 完成标准
+
+一篇文档只有在以下条件同时满足时才视为完成:结构完整;推导可独立理解;例题信息已核验;Hint 确实分层;Editorial、正确性与复杂度齐全;参考实现已经过可执行的编译/测试;索引已同步。否则在索引中标记为草稿或待核验。

+ 166 - 0
scripts/audit_mhtml.py

@@ -0,0 +1,166 @@
+#!/usr/bin/env python3
+"""Audit saved VJudge MHTML files without copying problem statements.
+
+The script reports the metadata needed by the course and verifies that each
+snapshot contains an embedded statement, rather than only the VJudge shell.
+It intentionally stores no statement text.
+"""
+
+from __future__ import annotations
+
+import argparse
+import html
+import json
+import re
+import sys
+from email import policy
+from email.parser import BytesParser
+from html.parser import HTMLParser
+from pathlib import Path
+
+
+class TextExtractor(HTMLParser):
+    def __init__(self) -> None:
+        super().__init__()
+        self.parts: list[str] = []
+
+    def handle_data(self, data: str) -> None:
+        if data.strip():
+            self.parts.append(data.strip())
+
+    def text(self) -> str:
+        return " ".join(self.parts)
+
+
+def plain_text(fragment: str) -> str:
+    parser = TextExtractor()
+    parser.feed(fragment)
+    return html.unescape(parser.text())
+
+
+def decode_part(part) -> str:
+    payload = part.get_payload(decode=True) or b""
+    charset = part.get_content_charset() or "utf-8"
+    return payload.decode(charset, errors="replace")
+
+
+def parse_snapshot(path: Path) -> dict[str, object]:
+    message = BytesParser(policy=policy.default).parsebytes(path.read_bytes())
+    snapshot_url = str(message.get("Snapshot-Content-Location", ""))
+    subject = str(message.get("Subject", path.stem))
+
+    html_parts = [
+        part
+        for part in message.walk()
+        if not part.is_multipart() and part.get_content_type() == "text/html"
+    ]
+    main_part = next(
+        (
+            part
+            for part in html_parts
+            if str(part.get("Content-Location", "")) == snapshot_url
+        ),
+        None,
+    )
+    if main_part is None:
+        raise ValueError("missing VJudge main HTML part")
+
+    main_html = decode_part(main_part)
+    match = re.search(
+        r'<textarea[^>]*name=["\']dataJson["\'][^>]*>(.*?)</textarea>',
+        main_html,
+        flags=re.DOTALL,
+    )
+    if match is None:
+        raise ValueError("missing dataJson metadata")
+    metadata = json.loads(html.unescape(match.group(1)))
+
+    official_keys = {
+        str(item["key"])
+        for item in metadata.get("descBriefs", [])
+        if item.get("mainOfficial") or (item.get("official") and item.get("type") == "main")
+    }
+    statement_candidates: list[tuple[bool, str]] = []
+    for part in html_parts:
+        location = str(part.get("Content-Location", ""))
+        if "/problem/description/" not in location:
+            continue
+        body = decode_part(part)
+        key_match = re.search(r"/problem/description/(\d+)", location)
+        is_official = bool(key_match and key_match.group(1) in official_keys)
+        statement_candidates.append((is_official, body))
+
+    if not statement_candidates:
+        raise ValueError("missing embedded statement HTML")
+    statement_candidates.sort(key=lambda item: (item[0], len(item[1])), reverse=True)
+    statement_html = statement_candidates[0][1]
+    statement_text = plain_text(statement_html)
+
+    properties = {
+        str(item.get("title", "")): plain_text(str(item.get("content", "")))
+        for item in metadata.get("properties", [])
+    }
+    title = re.sub(r"\s+-\s+Virtual Judge$", "", subject)
+    title = re.sub(r"\s+-\s+[^-]+\s+[^-]+$", "", title)
+    has_input = bool(re.search(r"\bInput\b|输入", statement_text, re.IGNORECASE))
+    has_output = bool(re.search(r"\bOutput\b|输出", statement_text, re.IGNORECASE))
+    sample_count = len(re.findall(r'class=["\']vjudge_sample["\']', statement_html))
+
+    return {
+        "file": path.as_posix(),
+        "query": f"{metadata.get('oj', '?')}-{metadata.get('prob', '?')}",
+        "title": title,
+        "source": properties.get("source", ""),
+        "difficulty": properties.get("difficulty", ""),
+        "time_limit": properties.get("time_limit", ""),
+        "memory_limit": properties.get("mem_limit", ""),
+        "statement_chars": len(statement_text),
+        "samples": sample_count,
+        "has_input": has_input,
+        "has_output": has_output,
+        "official_statement": statement_candidates[0][0],
+        "url": snapshot_url,
+    }
+
+
+def main() -> int:
+    parser = argparse.ArgumentParser()
+    parser.add_argument("root", nargs="?", default="problems")
+    parser.add_argument("--json", action="store_true", dest="as_json")
+    args = parser.parse_args()
+
+    paths = sorted(Path(args.root).rglob("*.mhtml"))
+    if not paths:
+        print(f"no .mhtml files found under {args.root}", file=sys.stderr)
+        return 2
+
+    rows: list[dict[str, object]] = []
+    errors: list[str] = []
+    for path in paths:
+        try:
+            rows.append(parse_snapshot(path))
+        except Exception as exc:  # keep auditing the remaining snapshots
+            errors.append(f"{path}: {exc}")
+
+    if args.as_json:
+        print(json.dumps(rows, ensure_ascii=False, indent=2))
+    else:
+        print("query\ttitle\tdifficulty\tsource\tstatement\tsamples\tofficial")
+        for row in rows:
+            statement = "ok" if row["has_input"] and row["has_output"] else "incomplete"
+            official = "yes" if row["official_statement"] else "fallback"
+            print(
+                f"{row['query']}\t{row['title']}\t{row['difficulty'] or '-'}\t"
+                f"{row['source'] or '-'}\t{statement}\t{row['samples']}\t{official}"
+            )
+
+    for error in errors:
+        print(error, file=sys.stderr)
+    incomplete = [
+        row for row in rows if not row["has_input"] or not row["has_output"] or row["statement_chars"] < 200
+    ]
+    return 1 if errors or incomplete else 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())

+ 63 - 0
scripts/check_course_docs.py

@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+"""Check required lesson sections and local Markdown links."""
+
+from __future__ import annotations
+
+import re
+import sys
+from pathlib import Path
+
+
+REQUIRED = (
+    "本节目标",
+    "前置知识",
+    "问题动机",
+    "核心",
+    "实现指南",
+    "扩展与联系",
+    "精选例题",
+    "总结与自检",
+    "课后训练建议",
+)
+
+
+def main() -> int:
+    root = Path(sys.argv[1] if len(sys.argv) > 1 else "课程")
+    errors: list[str] = []
+    lessons = [
+        path
+        for path in sorted(root.rglob("*.md"))
+        if path.name != "README.md" and not path.name.startswith("00-")
+    ]
+    for path in lessons:
+        text = path.read_text(encoding="utf-8")
+        headings = "\n".join(re.findall(r"^#{1,6}\s+(.+)$", text, flags=re.MULTILINE))
+        for required in REQUIRED:
+            if required not in headings:
+                errors.append(f"{path}: missing section containing {required!r}")
+        if "<details>" not in text:
+            errors.append(f"{path}: no folded hints/self-check content")
+        if re.search(r"```(?:cpp|c\+\+)\n.*?\bint\s+main\s*\(", text, flags=re.DOTALL):
+            errors.append(f"{path}: standalone C++ implementation must be an attachment")
+        if re.search(r"^\\\[\s*$|^\\\]\s*$", text, flags=re.MULTILINE):
+            errors.append(f"{path}: display LaTeX must use $$ delimiters, not \\[ or \\]")
+
+    for path in sorted(root.rglob("*.md")):
+        text = path.read_text(encoding="utf-8")
+        prose = re.sub(r"```.*?```", "", text, flags=re.DOTALL)
+        for target in re.findall(r"\[[^]]*\]\(([^)]+)\)", prose):
+            target = target.split("#", 1)[0]
+            if not target or re.match(r"(?:https?|mailto):", target):
+                continue
+            resolved = (path.parent / target).resolve()
+            if not resolved.exists():
+                errors.append(f"{path}: broken local link {target}")
+
+    for error in errors:
+        print(error, file=sys.stderr)
+    print(f"lessons={len(lessons)} errors={len(errors)}")
+    return 1 if errors else 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())

+ 320 - 0
scripts/extract_reference_attachments.py

@@ -0,0 +1,320 @@
+#!/usr/bin/env python3
+"""Move standalone C++ solutions out of lessons and insert core pseudocode.
+
+This is an idempotent course-layout migration. It identifies the nearest
+preceding VJudge problem link for each fenced block containing main(), writes
+the block to 参考实现/<topic>/<OJ-id>.cpp, and replaces it with concise
+Python-like pseudocode plus a relative attachment link.
+"""
+
+from __future__ import annotations
+
+import re
+from pathlib import Path
+
+
+PSEUDOCODE: dict[str, str] = {
+    "POJ-2230": """for each road (u, v):
+    add_arc(u, v); add_arc(v, u)
+stack = [1]; reversed_route = []
+while stack:
+    u = stack[-1]
+    if u still has an unused outgoing arc: stack.append(take_one_arc(u))
+    else: reversed_route.append(stack.pop())
+output reverse(reversed_route)""",
+    "HDU-1116": """for each word:
+    add directed edge first_letter -> last_letter
+    update in_degree, out_degree, and undirected DSU
+connected = all nonzero-degree letters have one DSU root
+degree_ok = all differences are 0, or exactly one +1 and one -1
+answer = connected and degree_ok""",
+    "CodeForces-508D": """encode every length-2 string as a vertex
+for trigram xyz: add edge xy -> yz
+check directed Euler degree conditions and select start
+path = Hierholzer(start)
+if len(path) != edge_count + 1: print NO
+else: print first 2-char vertex, then append each later vertex's last char""",
+    "CodeForces-723E": """answer = number of even-degree original vertices
+add dummy vertex 0 and edge 0-v for every odd-degree vertex v
+for every augmented connected component:
+    follow an Euler circuit and orient each traversed original edge forward
+discard dummy edges and output recorded original orientations""",
+    "CodeForces-427C": """components = Tarjan_SCC(graph)
+total_cost = 0; ways = 1
+for component in components:
+    best = minimum(cost[v] for v in component)
+    total_cost += best
+    ways *= count(v in component where cost[v] == best)  (mod MOD)""",
+    "POJ-1236": """component = Tarjan_SCC(graph)
+if there is only one component: output 1, 0
+build condensation indegree and outdegree
+sources = count(indegree == 0)
+sinks = count(outdegree == 0)
+output sources, max(sources, sinks)""",
+    "POJ-2186": """component = Tarjan_SCC(graph)
+compute every condensation component's size and outdegree
+sink_components = components with outdegree 0
+if len(sink_components) != 1: output 0
+else: output size of the unique sink component""",
+    "CodeForces-1000E": """bridges = find_bridges_with_edge_ids(graph)
+component = flood_fill_while_ignoring(bridges)
+bridge_tree = contract_components_and_keep_bridges()
+a = farthest_vertex(bridge_tree, arbitrary_root)
+b, distance = farthest_vertex(bridge_tree, a)
+output distance""",
+    "POJ-3177": """bridges = find_bridges_with_edge_ids(graph)
+component = flood_fill_while_ignoring(bridges)
+degree = degrees in the contracted bridge tree
+leaves = count(degree == 1)
+output ceil(leaves / 2)""",
+    "CodeForces-732F": """find bridges and edge-biconnected components
+root = component with maximum number of original vertices
+inside each component: orient DFS-tree edges down and back edges up
+build the bridge tree rooted at root
+orient every bridge from child component toward parent component
+output size(root) and all orientations in input order""",
+    "POJ-1144": """DFS(u, parent_edge):
+    dfn[u] = low[u] = next_time()
+    for each edge u-v except parent_edge:
+        if v unvisited:
+            DFS(v); low[u] = min(low[u], low[v])
+            if u is non-root and low[v] >= dfn[u]: mark u as cut
+        else: low[u] = min(low[u], dfn[v])
+    root is cut iff it has at least two DFS children""",
+    "CodeForces-962F": """during undirected Tarjan, push tree/back edge IDs on a stack
+when low[child] >= dfn[parent]:
+    pop through the parent-child edge to obtain one vertex-biconnected block
+    vertices = distinct endpoints of popped edges
+    if number_of_edges == number_of_vertices:
+        add every block edge to answer
+sort and output answer edge IDs""",
+    "AtCoder-abc258_g": """neighbor[i] = bitset of vertices adjacent to i
+sum = 0
+for every edge i-j with i < j:
+    sum += popcount(neighbor[i] AND neighbor[j])
+output sum / 3""",
+    "CodeForces-1097F": """state[x][d] = parity of elements in multiset x divisible by d
+singleton(v): set exactly the divisor bits of v
+union(y, z): state[x] = state[y] XOR state[z]
+gcd_product(y, z): state[x] = state[y] AND state[z]
+query(v): parity = popcount(state[x] AND squarefree_multiple_mask[v]) mod 2""",
+    "CodeForces-914F": """position[c] = bitset of indices currently containing c
+update(i, c): clear i in old character set; set i in c
+query(l, r, pattern):
+    match = all_ones
+    for offset, c in enumerate(pattern):
+        match &= position[c] >> offset
+    discard start positions outside [l, r-len(pattern)+1]
+    return popcount(match)""",
+    "POJ-3461": """pi = prefix_function(pattern)
+matched = answer = 0
+for c in text:
+    while matched > 0 and c != pattern[matched]: matched = pi[matched-1]
+    if c == pattern[matched]: matched += 1
+    if matched == len(pattern):
+        answer += 1; matched = pi[matched-1]""",
+    "POJ-2406": """pi = prefix_function(s)
+period = len(s) - pi[-1]
+if len(s) is divisible by period: output len(s) / period
+else: output 1""",
+    "CodeForces-432D": """pi = prefix_function(s)
+occ[pi[i]] += 1 for every position i
+for length from n down to 1: occ[pi[length-1]] += occ[length]
+occ[length] += 1 for each prefix's occurrence at position 0
+borders = n, pi[n-1], pi[pi[n-1]-1], ...
+output reversed(borders) with occ[length]""",
+    "CodeForces-471D": """if target length == 1: output source length
+text = adjacent_differences(source_heights)
+pattern = adjacent_differences(target_heights)
+output KMP_occurrence_count(pattern, text)""",
+    "POJ-3974": """d1 = odd_palindrome_radii_by_Manacher(s)
+d2 = even_palindrome_radii_by_Manacher(s)
+answer = max(max(2*d1[i]-1), max(2*d2[i]))
+output answer""",
+    "CodeForces-17E": """d1, d2 = Manacher(s)
+P = sum(d1) + sum(d2)
+for each center and radius:
+    range_add all represented start positions
+    range_add all represented end positions
+start, end = prefix_sums(the two difference arrays)
+disjoint = sum(start[i] * number_of_palindromes_ending_before_i)
+output choose(P, 2) - disjoint  (mod MOD)""",
+    "AtCoder-abc340_d": """for each stage i:
+    add edge i -> i+1 with cost A[i]
+    add edge i -> X[i] with cost B[i]
+dist = Dijkstra(graph, source=1)
+output dist[N]""",
+    "AtCoder-abc277_e": """state = (vertex, currently_passable_edge_label)
+for original edge with label a: connect its endpoints in layer a with cost 1
+for each switch vertex: connect its two layers with cost 0
+dist = zero_one_BFS(start=(1, label_1))
+output min(dist[(N,0)], dist[(N,1)])""",
+    "CodeForces-449B": """train[v] = minimum train length to v
+run road-only Dijkstra with seeds (capital,0) and every finite train[v]
+mark v if some road u-v satisfies dist[u] + w == dist[v]
+needed = count(v where train[v] == dist[v] and v has no road predecessor)
+output total_trains - needed""",
+    "CodeForces-59E": """BFS state is (previous_vertex, current_vertex); start = (0, 1)
+for neighbor next of current:
+    skip if (previous, current, next) is forbidden
+    visit state (current, next) and store parent state
+stop at first state whose current vertex is N
+follow parent states to restore the vertex path""",
+    "CodeForces-229B": """run Dijkstra from planet 1
+when finalizing u at time t (unless u is destination):
+    binary-search t in u's sorted blocked times
+    advance depart across the consecutive blocked run t,t+1,...
+    relax every edge using depart + edge_weight
+output destination distance or -1""",
+    "CodeForces-545E": """run Dijkstra from source
+on shorter distance to v: replace distance and parent edge
+on equal distance: replace parent edge only if its own weight is smaller
+because all weights are positive, chosen parents strictly decrease distance
+output sum and IDs of one chosen parent edge for every non-source vertex""",
+    "POJ-3255": """first[source] = 0; second[*] = infinity
+pop a distance label d at u
+for edge u-v:
+    candidate = d + weight
+    if candidate < first[v]: swap(candidate, first[v]); push first[v]
+    if first[v] < candidate < second[v]: set and push second[v]
+output second[destination]""",
+    "POJ-3169": """convert every constraint to x[v] <= x[u] + weight and add edge u->v
+add order edges (i+1)->i with weight 0
+if Bellman-Ford from a super-source finds a negative cycle: output -1
+dist = Bellman-Ford(source=1)
+if N is unreachable: output -2
+else: output dist[N], the tightest upper bound on x[N]-x[1]""",
+    "AtCoder-arc076_b": """candidates = []
+sort towns by x; add every adjacent pair
+sort towns by y; add every adjacent pair
+give each candidate its true min(|dx|, |dy|) cost
+output Kruskal(candidates)""",
+    "CodeForces-1245D": """treat building station i as edge super_source-i with cost c[i]
+initialize Prim key[i] = c[i], parent[i] = super_source
+repeat n times:
+    select unused city v with minimum key
+    record station if parent is source, otherwise record wire
+    update every unused city's key by wire_cost(v, city)
+output total and recorded construction""",
+    "CodeForces-1095F": """hub = vertex with minimum a[hub]
+candidates = all special offers
+for every v != hub: add ordinary edge hub-v with cost a[hub]+a[v]
+output Kruskal(candidates)""",
+    "CodeForces-609E": """T, total = Kruskal_MST(graph)
+preprocess binary lifting for maximum edge on every tree path
+for edge e=(u,v,w):
+    if e belongs to T: answer[e] = total
+    else: answer[e] = total + w - maximum_on_tree_path(u,v)""",
+    "CodeForces-160D": """sort edges into equal-weight groups; DSU contains only lighter edges
+for each group:
+    edges already inside one DSU component are 'none'
+    contract DSU roots and build a temporary multigraph from remaining edges
+    temporary bridges are 'any'; other remaining edges are 'at least one'
+    union all group edges in the global DSU""",
+    "CodeForces-1706E": """process input edges by index; every successful DSU merge creates a new parent node
+new node value = current edge index; its children are the two old component roots
+preprocess LCA on the reconstruction tree
+need[i] = value(LCA(original_vertex_i, original_vertex_i+1))
+answer(l,r) = max(need[l .. r-1]), or 0 when l == r""",
+    "CodeForces-888G": """sort and deduplicate values
+solve(group, bit):
+    split group by current bit
+    answer = solve(zero_side, bit-1) + solve(one_side, bit-1)
+    if both sides exist:
+        build a lower-bit binary trie for the smaller side
+        answer += 2^bit + minimum lower-bit XOR across the split
+    return answer""",
+    "CodeForces-1144F": """two-color the graph
+if an edge has equal-colored endpoints: output NO
+otherwise orient every edge from color 0 to color 1
+translate each orientation back to a 0/1 character in input order""",
+    "CodeForces-1354E": """two-color every connected component and store its two sides
+group-knapsack: from each component choose one side so total chosen size is n2
+recover choices; label chosen side 2
+among all remaining vertices label any n1 as 1 and the rest as 3""",
+    "CodeForces-741C": """make one vertex for each chair
+add an inequality edge for every romantic pair
+add inequality edges (1,2), (3,4), ...
+two-color every resulting even-cycle component
+output the two colors at each romantic pair's chair positions""",
+    "POJ-1274": """match_right[stall] = unmatched
+for each cow u:
+    clear visited stalls
+    DFS through acceptable stalls:
+        take an empty stall, or recursively move its currently matched cow
+    count successful augmentations""",
+    "POJ-3041": """rows are left vertices; columns are right vertices
+each asteroid adds a row-column edge
+maximum_matching = Kuhn(graph)
+output maximum_matching  # equals minimum vertex cover by Konig""",
+    "CodeForces-1139E": """potential values are left vertices; clubs are right vertices
+start with students that never get deleted and maintain a matching
+advance mex while the current potential can be augmented
+process deletions in reverse:
+    record current mex for that day
+    add the deleted student's potential-club edge
+    continue augmenting from current mex""",
+    "HDU-2255": """initialize left label lx[x] = max_y weight[x][y], right label ly = 0
+for every left vertex root:
+    search an augmenting path using only equality edges lx+ly == weight
+    if search fails:
+        delta = minimum slack of every unvisited right vertex
+        subtract delta from visited lx; add it to visited ly; update slack
+    repeat until root is matched
+output weight sum of the perfect matching""",
+    "CodeForces-498C": """factor all array values and iterate over each distinct prime p
+capacity[i] = exponent of p in a[i]
+build flow network: source->odd indices, even indices->sink
+for every allowed pair add infinite-capacity odd->even edge
+answer += maximum_flow(network)
+output answer""",
+}
+
+
+BLOCK = re.compile(r"```(?:cpp|c\+\+)\n(.*?)```", flags=re.DOTALL)
+VJUDGE = re.compile(r"https://vjudge\.net/problem/([A-Za-z0-9_-]+)")
+
+
+def main() -> int:
+    course = Path("课程")
+    attachment_root = Path("参考实现")
+    moved = 0
+    for document in sorted(course.rglob("*.md")):
+        text = document.read_text(encoding="utf-8")
+        output: list[str] = []
+        cursor = 0
+        for match in BLOCK.finditer(text):
+            code = match.group(1)
+            if not re.search(r"\bint\s+main\s*\(", code):
+                continue
+            preceding = text[: match.start()]
+            queries = VJUDGE.findall(preceding)
+            if not queries:
+                raise RuntimeError(f"no preceding VJudge ID for {document}")
+            query = queries[-1]
+            if query not in PSEUDOCODE:
+                raise RuntimeError(f"missing pseudocode for {query} in {document}")
+            topic = document.parent.name
+            attachment = attachment_root / topic / f"{query}.cpp"
+            attachment.parent.mkdir(parents=True, exist_ok=True)
+            attachment.write_text(code.rstrip() + "\n", encoding="utf-8")
+            relative = Path("../..") / attachment
+            replacement = (
+                "```text\n"
+                + PSEUDOCODE[query].rstrip()
+                + "\n```\n\n"
+                + f"完整 GNU C++17 参考实现见附件:[{query}.cpp]({relative.as_posix()})"
+            )
+            output.append(text[cursor : match.start()])
+            output.append(replacement)
+            cursor = match.end()
+            moved += 1
+        if output:
+            output.append(text[cursor:])
+            document.write_text("".join(output), encoding="utf-8")
+    print(f"moved={moved}")
+    return 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())

+ 78 - 0
scripts/verify_markdown_cpp.py

@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+"""Compile every standalone C++ fenced block in course Markdown files."""
+
+from __future__ import annotations
+
+import re
+import subprocess
+import sys
+import tempfile
+from pathlib import Path
+
+
+def main() -> int:
+    root = Path(sys.argv[1] if len(sys.argv) > 1 else "课程")
+    documents = sorted(root.rglob("*.md"))
+    failed = 0
+    compiled = 0
+    snippets = 0
+    with tempfile.TemporaryDirectory(prefix="course-cpp-") as temp:
+        directory = Path(temp)
+        for source in sorted(Path("参考实现").rglob("*.cpp")):
+            compiled += 1
+            output = directory / f"attachment-{compiled}"
+            result = subprocess.run(
+                [
+                    "g++",
+                    "-std=c++17",
+                    "-Wall",
+                    "-Wextra",
+                    "-Wpedantic",
+                    str(source),
+                    "-o",
+                    str(output),
+                ],
+                text=True,
+                capture_output=True,
+                check=False,
+            )
+            if result.returncode != 0:
+                failed += 1
+                print(f"FAIL {source}", file=sys.stderr)
+                print(result.stderr, file=sys.stderr)
+        for document in documents:
+            text = document.read_text(encoding="utf-8")
+            blocks = re.findall(r"```(?:cpp|c\+\+)\n(.*?)```", text, flags=re.DOTALL)
+            for index, code in enumerate(blocks, 1):
+                if not re.search(r"\bint\s+main\s*\(", code):
+                    snippets += 1
+                    continue
+                compiled += 1
+                source = directory / f"block-{compiled}.cpp"
+                output = directory / f"block-{compiled}"
+                source.write_text(code, encoding="utf-8")
+                result = subprocess.run(
+                    [
+                        "g++",
+                        "-std=c++17",
+                        "-Wall",
+                        "-Wextra",
+                        "-Wpedantic",
+                        str(source),
+                        "-o",
+                        str(output),
+                    ],
+                    text=True,
+                    capture_output=True,
+                    check=False,
+                )
+                if result.returncode != 0:
+                    failed += 1
+                    print(f"FAIL {document}:{index}", file=sys.stderr)
+                    print(result.stderr, file=sys.stderr)
+    print(f"compiled={compiled} snippets_skipped={snippets} failed={failed}")
+    return 1 if failed else 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())

+ 14 - 0
主题.md

@@ -0,0 +1,14 @@
+知识点:
+	1. 欧拉路径
+	2. 强连通、双连通
+	3. Bitset
+	4. KMP、Manacher
+	5. 最短路、类最短路
+	6. (类)最小/大生成树
+	7. 二分图
+	8. Segment Tree、Fenwick Tree
+	9. 基环树
+	10. 历年真题
+	11. 高斯消元、CRT
+	12. 平衡树
+

+ 75 - 0
参考实现/01-欧拉路径/CodeForces-508D.cpp

@@ -0,0 +1,75 @@
+#include <algorithm>
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+int code(char c) {
+    if ('a' <= c && c <= 'z') return c - 'a';
+    if ('A' <= c && c <= 'Z') return 26 + c - 'A';
+    return 52 + c - '0';
+}
+
+char decode(int x) {
+    if (x < 26) return static_cast<char>('a' + x);
+    if (x < 52) return static_cast<char>('A' + x - 26);
+    return static_cast<char>('0' + x - 52);
+}
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+
+    int n;
+    cin >> n;
+    constexpr int sigma = 62;
+    constexpr int vertices = sigma * sigma;
+    vector<vector<int>> adj(vertices);
+    vector<int> in(vertices, 0), out(vertices, 0);
+    for (int i = 0; i < n; ++i) {
+        string s;
+        cin >> s;
+        int u = code(s[0]) * sigma + code(s[1]);
+        int v = code(s[1]) * sigma + code(s[2]);
+        adj[u].push_back(v);
+        ++out[u]; ++in[v];
+    }
+
+    int start = -1, plus = 0, minus = 0;
+    bool ok = true;
+    for (int v = 0; v < vertices; ++v) {
+        int diff = out[v] - in[v];
+        if (diff == 1) { ++plus; start = v; }
+        else if (diff == -1) ++minus;
+        else if (diff != 0) ok = false;
+        if (start == -1 && out[v] > 0) start = v;
+    }
+    ok = ok && ((plus == 0 && minus == 0) || (plus == 1 && minus == 1));
+    if (!ok || start == -1) {
+        cout << "NO\n";
+        return 0;
+    }
+
+    vector<size_t> cursor(vertices, 0);
+    vector<int> st{start}, path;
+    path.reserve(n + 1);
+    while (!st.empty()) {
+        int v = st.back();
+        if (cursor[v] == adj[v].size()) {
+            path.push_back(v);
+            st.pop_back();
+        } else {
+            st.push_back(adj[v][cursor[v]++]);
+        }
+    }
+    if (static_cast<int>(path.size()) != n + 1) {
+        cout << "NO\n";
+        return 0;
+    }
+    reverse(path.begin(), path.end());
+
+    cout << "YES\n";
+    cout << decode(path[0] / sigma) << decode(path[0] % sigma);
+    for (int i = 1; i <= n; ++i) cout << decode(path[i] % sigma);
+    cout << '\n';
+}

+ 72 - 0
参考实现/01-欧拉路径/CodeForces-723E.cpp

@@ -0,0 +1,72 @@
+#include <iostream>
+#include <utility>
+#include <vector>
+using namespace std;
+
+struct AdjEdge { int to, id; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+
+    int tests;
+    cin >> tests;
+    while (tests--) {
+        int n, m;
+        cin >> n >> m;
+        vector<vector<AdjEdge>> adj(n + 1);
+        vector<int> degree(n + 1, 0);
+        vector<pair<int, int>> original(m);
+        vector<int> a, b;
+        a.reserve(m + n); b.reserve(m + n);
+
+        auto add_edge = [&](int u, int v) {
+            int id = static_cast<int>(a.size());
+            a.push_back(u); b.push_back(v);
+            adj[u].push_back({v, id});
+            adj[v].push_back({u, id});
+        };
+        for (int id = 0; id < m; ++id) {
+            int u, v;
+            cin >> u >> v;
+            original[id] = {u, v};
+            add_edge(u, v);
+            ++degree[u]; ++degree[v];
+        }
+
+        int best = 0;
+        for (int v = 1; v <= n; ++v) {
+            if (degree[v] % 2 == 0) ++best;
+            else add_edge(0, v);
+        }
+
+        vector<bool> used(a.size(), false);
+        vector<size_t> cursor(n + 1, 0);
+        vector<pair<int, int>> direction(m, {-1, -1});
+        for (int start = 0; start <= n; ++start) {
+            while (cursor[start] < adj[start].size() && used[adj[start][cursor[start]].id]) {
+                ++cursor[start];
+            }
+            if (cursor[start] == adj[start].size()) continue;
+            vector<int> st{start};
+            while (!st.empty()) {
+                int v = st.back();
+                while (cursor[v] < adj[v].size() && used[adj[v][cursor[v]].id]) {
+                    ++cursor[v];
+                }
+                if (cursor[v] == adj[v].size()) {
+                    st.pop_back();
+                    continue;
+                }
+                AdjEdge e = adj[v][cursor[v]++];
+                if (used[e.id]) continue;
+                used[e.id] = true;
+                if (e.id < m) direction[e.id] = {v, e.to};
+                st.push_back(e.to);
+            }
+        }
+
+        cout << best << '\n';
+        for (auto [u, v] : direction) cout << u << ' ' << v << '\n';
+    }
+}

+ 56 - 0
参考实现/01-欧拉路径/HDU-1116.cpp

@@ -0,0 +1,56 @@
+#include <array>
+#include <iostream>
+#include <numeric>
+#include <string>
+using namespace std;
+
+struct DSU {
+    array<int, 26> p{};
+    DSU() { iota(p.begin(), p.end(), 0); }
+    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
+    void unite(int a, int b) {
+        a = find(a); b = find(b);
+        if (a != b) p[a] = b;
+    }
+};
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+
+    int t;
+    cin >> t;
+    while (t--) {
+        int n;
+        cin >> n;
+        array<int, 26> in{}, out{};
+        array<bool, 26> seen{};
+        DSU dsu;
+        for (int i = 0; i < n; ++i) {
+            string s;
+            cin >> s;
+            int u = s.front() - 'a';
+            int v = s.back() - 'a';
+            ++out[u]; ++in[v];
+            seen[u] = seen[v] = true;
+            dsu.unite(u, v);
+        }
+
+        int root = -1;
+        bool ok = true;
+        for (int v = 0; v < 26; ++v) if (seen[v]) {
+            if (root == -1) root = dsu.find(v);
+            else if (dsu.find(v) != root) ok = false;
+        }
+        int plus = 0, minus = 0;
+        for (int v = 0; v < 26; ++v) {
+            int diff = out[v] - in[v];
+            if (diff == 1) ++plus;
+            else if (diff == -1) ++minus;
+            else if (diff != 0) ok = false;
+        }
+        ok = ok && ((plus == 0 && minus == 0) || (plus == 1 && minus == 1));
+        cout << (ok ? "Ordering is possible.\n"
+                    : "The door cannot be opened.\n");
+    }
+}

+ 34 - 0
参考实现/01-欧拉路径/POJ-2230.cpp

@@ -0,0 +1,34 @@
+#include <algorithm>
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+
+    int n, m;
+    cin >> n >> m;
+    vector<vector<int>> adj(n + 1);
+    for (int i = 0; i < m; ++i) {
+        int u, v;
+        cin >> u >> v;
+        adj[u].push_back(v);
+        adj[v].push_back(u);  // 独立的反向弧,不与上一条共享 used 标记
+    }
+
+    vector<size_t> cursor(n + 1, 0);
+    vector<int> st{1}, path;
+    path.reserve(2 * m + 1);
+    while (!st.empty()) {
+        int v = st.back();
+        if (cursor[v] == adj[v].size()) {
+            path.push_back(v);
+            st.pop_back();
+        } else {
+            st.push_back(adj[v][cursor[v]++]);
+        }
+    }
+    reverse(path.begin(), path.end());
+    for (int v : path) cout << v << '\n';
+}

+ 80 - 0
参考实现/02-强连通与双连通/CodeForces-1000E.cpp

@@ -0,0 +1,80 @@
+#include <algorithm>
+#include <iostream>
+#include <queue>
+#include <utility>
+#include <vector>
+using namespace std;
+
+struct Edge { int to, id; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m;
+    cin >> n >> m;
+    vector<pair<int, int>> edges(m);
+    vector<vector<Edge>> g(n);
+    for (int id = 0; id < m; ++id) {
+        int u, v; cin >> u >> v; --u; --v;
+        edges[id] = {u, v};
+        g[u].push_back({v, id}); g[v].push_back({u, id});
+    }
+
+    vector<int> dfn(n), low(n), parent(n, -1), parent_edge(n, -1);
+    vector<size_t> cursor(n);
+    vector<bool> bridge(m, false);
+    int timer = 0;
+    for (int root = 0; root < n; ++root) if (!dfn[root]) {
+        vector<int> st{root}; dfn[root] = low[root] = ++timer;
+        while (!st.empty()) {
+            int u = st.back();
+            if (cursor[u] < g[u].size()) {
+                Edge e = g[u][cursor[u]++];
+                if (e.id == parent_edge[u]) continue;
+                if (!dfn[e.to]) {
+                    parent[e.to] = u; parent_edge[e.to] = e.id;
+                    dfn[e.to] = low[e.to] = ++timer; st.push_back(e.to);
+                } else low[u] = min(low[u], dfn[e.to]);
+            } else {
+                st.pop_back();
+                if (parent[u] != -1) {
+                    int p = parent[u];
+                    if (low[u] > dfn[p]) bridge[parent_edge[u]] = true;
+                    low[p] = min(low[p], low[u]);
+                }
+            }
+        }
+    }
+
+    vector<int> comp(n, -1);
+    int count = 0;
+    for (int s = 0; s < n; ++s) if (comp[s] == -1) {
+        vector<int> st{s}; comp[s] = count;
+        while (!st.empty()) {
+            int u = st.back(); st.pop_back();
+            for (Edge e : g[u]) if (!bridge[e.id] && comp[e.to] == -1) {
+                comp[e.to] = count; st.push_back(e.to);
+            }
+        }
+        ++count;
+    }
+    vector<vector<int>> tree(count);
+    for (int id = 0; id < m; ++id) if (bridge[id]) {
+        auto [u, v] = edges[id];
+        tree[comp[u]].push_back(comp[v]); tree[comp[v]].push_back(comp[u]);
+    }
+    auto farthest = [&](int start) {
+        vector<int> dist(count, -1); queue<int> q;
+        dist[start] = 0; q.push(start); int best = start;
+        while (!q.empty()) {
+            int u = q.front(); q.pop();
+            if (dist[u] > dist[best]) best = u;
+            for (int v : tree[u]) if (dist[v] == -1) {
+                dist[v] = dist[u] + 1; q.push(v);
+            }
+        }
+        return pair<int, int>{best, dist[best]};
+    };
+    int endpoint = farthest(0).first;
+    cout << farthest(endpoint).second << '\n';
+}

+ 56 - 0
参考实现/02-强连通与双连通/CodeForces-427C.cpp

@@ -0,0 +1,56 @@
+#include <algorithm>
+#include <climits>
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n;
+    cin >> n;
+    vector<long long> cost(n);
+    for (auto &x : cost) cin >> x;
+    int m;
+    cin >> m;
+    vector<vector<int>> g(n);
+    while (m--) {
+        int u, v; cin >> u >> v;
+        g[--u].push_back(--v);
+    }
+
+    vector<int> dfn(n), low(n), comp(n, -1), st;
+    vector<bool> in_stack(n, false);
+    int timer = 0, components = 0;
+    auto dfs = [&](auto &&self, int u) -> void {
+        dfn[u] = low[u] = ++timer;
+        st.push_back(u); in_stack[u] = true;
+        for (int v : g[u]) {
+            if (!dfn[v]) { self(self, v); low[u] = min(low[u], low[v]); }
+            else if (in_stack[v]) low[u] = min(low[u], dfn[v]);
+        }
+        if (low[u] == dfn[u]) {
+            while (true) {
+                int v = st.back(); st.pop_back(); in_stack[v] = false;
+                comp[v] = components;
+                if (v == u) break;
+            }
+            ++components;
+        }
+    };
+    for (int v = 0; v < n; ++v) if (!dfn[v]) dfs(dfs, v);
+
+    vector<long long> best(components, LLONG_MAX), ways(components, 0);
+    for (int v = 0; v < n; ++v) {
+        int c = comp[v];
+        if (cost[v] < best[c]) best[c] = cost[v], ways[c] = 1;
+        else if (cost[v] == best[c]) ++ways[c];
+    }
+    constexpr long long mod = 1'000'000'007LL;
+    long long answer_cost = 0, answer_ways = 1;
+    for (int c = 0; c < components; ++c) {
+        answer_cost += best[c];
+        answer_ways = answer_ways * ways[c] % mod;
+    }
+    cout << answer_cost << ' ' << answer_ways << '\n';
+}

+ 91 - 0
参考实现/02-强连通与双连通/CodeForces-732F.cpp

@@ -0,0 +1,91 @@
+#include <algorithm>
+#include <iostream>
+#include <queue>
+#include <utility>
+#include <vector>
+using namespace std;
+struct E { int to, id; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m; cin >> n >> m;
+    vector<pair<int, int>> edge(m), answer(m, {-1, -1});
+    vector<vector<E>> g(n);
+    for (int id = 0; id < m; ++id) {
+        int u, v; cin >> u >> v; --u; --v; edge[id] = {u, v};
+        g[u].push_back({v, id}); g[v].push_back({u, id});
+    }
+
+    vector<int> dfn(n), low(n), par(n, -1), pe(n, -1);
+    vector<size_t> it(n); vector<bool> bridge(m); int timer = 0;
+    vector<int> st{0}; dfn[0] = low[0] = ++timer;
+    while (!st.empty()) {
+        int u = st.back();
+        if (it[u] < g[u].size()) {
+            E e = g[u][it[u]++];
+            if (e.id == pe[u]) continue;
+            if (!dfn[e.to]) {
+                par[e.to] = u; pe[e.to] = e.id;
+                dfn[e.to] = low[e.to] = ++timer; st.push_back(e.to);
+            } else low[u] = min(low[u], dfn[e.to]);
+        } else {
+            st.pop_back();
+            if (par[u] != -1) {
+                if (low[u] > dfn[par[u]]) bridge[pe[u]] = true;
+                low[par[u]] = min(low[par[u]], low[u]);
+            }
+        }
+    }
+
+    vector<int> comp(n, -1), comp_size; int count = 0;
+    for (int s = 0; s < n; ++s) if (comp[s] == -1) {
+        int size = 0; vector<int> work{s}; comp[s] = count;
+        while (!work.empty()) {
+            int u = work.back(); work.pop_back(); ++size;
+            for (E e : g[u]) if (!bridge[e.id] && comp[e.to] == -1) {
+                comp[e.to] = count; work.push_back(e.to);
+            }
+        }
+        comp_size.push_back(size); ++count;
+    }
+    int root = int(max_element(comp_size.begin(), comp_size.end()) - comp_size.begin());
+
+    // 非桥边:在各边双分量中做 DFS,树边向下、返祖边向上。
+    vector<bool> seen_vertex(n), used_edge(m);
+    vector<size_t> orient_it(n);
+    for (int s = 0; s < n; ++s) if (!seen_vertex[s]) {
+        vector<int> dfs{s}; seen_vertex[s] = true;
+        while (!dfs.empty()) {
+            int u = dfs.back();
+            while (orient_it[u] < g[u].size() &&
+                   (bridge[g[u][orient_it[u]].id] || used_edge[g[u][orient_it[u]].id])) {
+                ++orient_it[u];
+            }
+            if (orient_it[u] == g[u].size()) { dfs.pop_back(); continue; }
+            E e = g[u][orient_it[u]++];
+            used_edge[e.id] = true; answer[e.id] = {u, e.to};
+            if (!seen_vertex[e.to]) { seen_vertex[e.to] = true; dfs.push_back(e.to); }
+        }
+    }
+
+    vector<vector<pair<int, int>>> tree(count);
+    for (int id = 0; id < m; ++id) if (bridge[id]) {
+        auto [u, v] = edge[id];
+        tree[comp[u]].push_back({comp[v], id});
+        tree[comp[v]].push_back({comp[u], id});
+    }
+    vector<int> parent(count, -1); queue<int> q; parent[root] = root; q.push(root);
+    while (!q.empty()) {
+        int c = q.front(); q.pop();
+        for (auto [to, id] : tree[c]) if (parent[to] == -1) {
+            parent[to] = c; q.push(to);
+            auto [u, v] = edge[id];
+            // 子分量 -> 父分量
+            answer[id] = (comp[u] == to) ? pair<int, int>{u, v}
+                                         : pair<int, int>{v, u};
+        }
+    }
+    cout << comp_size[root] << '\n';
+    for (auto [u, v] : answer) cout << u + 1 << ' ' << v + 1 << '\n';
+}

+ 55 - 0
参考实现/02-强连通与双连通/CodeForces-962F.cpp

@@ -0,0 +1,55 @@
+#include <algorithm>
+#include <iostream>
+#include <utility>
+#include <vector>
+using namespace std;
+struct E { int to, id; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m; cin >> n >> m;
+    vector<pair<int, int>> edges(m);
+    vector<vector<E>> g(n);
+    for (int id = 0; id < m; ++id) {
+        int u, v; cin >> u >> v; --u; --v; edges[id] = {u, v};
+        g[u].push_back({v, id}); g[v].push_back({u, id});
+    }
+    vector<int> dfn(n), low(n), edge_stack, seen(n, 0), answer;
+    int timer = 0, stamp = 0;
+    auto dfs = [&](auto &&self, int u, int parent_edge) -> void {
+        dfn[u] = low[u] = ++timer;
+        for (E e : g[u]) {
+            if (e.id == parent_edge) continue;
+            if (!dfn[e.to]) {
+                edge_stack.push_back(e.id);
+                self(self, e.to, e.id);
+                low[u] = min(low[u], low[e.to]);
+                if (low[e.to] >= dfn[u]) {
+                    ++stamp;
+                    vector<int> block;
+                    int vertices = 0;
+                    while (true) {
+                        int id = edge_stack.back(); edge_stack.pop_back();
+                        block.push_back(id);
+                        auto [a, b] = edges[id];
+                        if (seen[a] != stamp) seen[a] = stamp, ++vertices;
+                        if (seen[b] != stamp) seen[b] = stamp, ++vertices;
+                        if (id == e.id) break;
+                    }
+                    if (static_cast<int>(block.size()) == vertices) {
+                        answer.insert(answer.end(), block.begin(), block.end());
+                    }
+                }
+            } else if (dfn[e.to] < dfn[u]) {
+                edge_stack.push_back(e.id);
+                low[u] = min(low[u], dfn[e.to]);
+            }
+        }
+    };
+    for (int v = 0; v < n; ++v) if (!dfn[v]) dfs(dfs, v, -1);
+    sort(answer.begin(), answer.end());
+    cout << answer.size() << '\n';
+    for (int id : answer) cout << id + 1 << ' ';
+    cout << '\n';
+}

+ 48 - 0
参考实现/02-强连通与双连通/POJ-1144.cpp

@@ -0,0 +1,48 @@
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+using namespace std;
+
+struct E { int to, id; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n;
+    string line;
+    while (cin >> n && n != 0) {
+        getline(cin, line);
+        vector<vector<E>> g(n);
+        int edge_id = 0;
+        while (getline(cin, line) && line != "0") {
+            istringstream input(line);
+            int u, v; input >> u; --u;
+            while (input >> v) {
+                --v;
+                g[u].push_back({v, edge_id});
+                g[v].push_back({u, edge_id});
+                ++edge_id;
+            }
+        }
+        vector<int> dfn(n), low(n);
+        vector<bool> cut(n, false);
+        int timer = 0;
+        auto dfs = [&](auto &&self, int u, int parent_edge) -> void {
+            dfn[u] = low[u] = ++timer;
+            int children = 0;
+            for (E e : g[u]) {
+                if (e.id == parent_edge) continue;
+                if (!dfn[e.to]) {
+                    ++children; self(self, e.to, e.id);
+                    low[u] = min(low[u], low[e.to]);
+                    if (parent_edge != -1 && low[e.to] >= dfn[u]) cut[u] = true;
+                } else low[u] = min(low[u], dfn[e.to]);
+            }
+            if (parent_edge == -1 && children >= 2) cut[u] = true;
+        };
+        for (int v = 0; v < n; ++v) if (!dfn[v]) dfs(dfs, v, -1);
+        cout << count(cut.begin(), cut.end(), true) << '\n';
+    }
+}

+ 48 - 0
参考实现/02-强连通与双连通/POJ-1236.cpp

@@ -0,0 +1,48 @@
+#include <algorithm>
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n;
+    cin >> n;
+    vector<vector<int>> g(n);
+    for (int u = 0; u < n; ++u) {
+        int v;
+        while (cin >> v && v != 0) g[u].push_back(v - 1);
+    }
+    vector<int> dfn(n), low(n), comp(n, -1), st;
+    vector<bool> in_stack(n);
+    int timer = 0, count = 0;
+    auto dfs = [&](auto &&self, int u) -> void {
+        dfn[u] = low[u] = ++timer; st.push_back(u); in_stack[u] = true;
+        for (int v : g[u]) {
+            if (!dfn[v]) self(self, v), low[u] = min(low[u], low[v]);
+            else if (in_stack[v]) low[u] = min(low[u], dfn[v]);
+        }
+        if (dfn[u] == low[u]) {
+            while (true) {
+                int v = st.back(); st.pop_back(); in_stack[v] = false; comp[v] = count;
+                if (v == u) break;
+            }
+            ++count;
+        }
+    };
+    for (int v = 0; v < n; ++v) if (!dfn[v]) dfs(dfs, v);
+    if (count == 1) {
+        cout << "1\n0\n";
+        return 0;
+    }
+    vector<int> indeg(count), outdeg(count);
+    for (int u = 0; u < n; ++u) for (int v : g[u]) if (comp[u] != comp[v]) {
+        ++outdeg[comp[u]]; ++indeg[comp[v]];
+    }
+    int sources = 0, sinks = 0;
+    for (int c = 0; c < count; ++c) {
+        sources += indeg[c] == 0;
+        sinks += outdeg[c] == 0;
+    }
+    cout << sources << '\n' << max(sources, sinks) << '\n';
+}

+ 42 - 0
参考实现/02-强连通与双连通/POJ-2186.cpp

@@ -0,0 +1,42 @@
+#include <algorithm>
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m;
+    cin >> n >> m;
+    vector<vector<int>> g(n);
+    while (m--) { int u, v; cin >> u >> v; g[--u].push_back(--v); }
+    vector<int> dfn(n), low(n), comp(n, -1), st;
+    vector<bool> in_stack(n);
+    int timer = 0, count = 0;
+    auto dfs = [&](auto &&self, int u) -> void {
+        dfn[u] = low[u] = ++timer; st.push_back(u); in_stack[u] = true;
+        for (int v : g[u]) {
+            if (!dfn[v]) self(self, v), low[u] = min(low[u], low[v]);
+            else if (in_stack[v]) low[u] = min(low[u], dfn[v]);
+        }
+        if (dfn[u] == low[u]) {
+            while (true) {
+                int v = st.back(); st.pop_back(); in_stack[v] = false; comp[v] = count;
+                if (v == u) break;
+            }
+            ++count;
+        }
+    };
+    for (int v = 0; v < n; ++v) if (!dfn[v]) dfs(dfs, v);
+    vector<int> size(count), outdeg(count);
+    for (int v = 0; v < n; ++v) ++size[comp[v]];
+    for (int u = 0; u < n; ++u) for (int v : g[u]) if (comp[u] != comp[v]) {
+        ++outdeg[comp[u]];
+    }
+    int sink = -1;
+    for (int c = 0; c < count; ++c) if (outdeg[c] == 0) {
+        if (sink != -1) { cout << "0\n"; return 0; }
+        sink = c;
+    }
+    cout << size[sink] << '\n';
+}

+ 58 - 0
参考实现/02-强连通与双连通/POJ-3177.cpp

@@ -0,0 +1,58 @@
+#include <algorithm>
+#include <iostream>
+#include <utility>
+#include <vector>
+using namespace std;
+struct E { int to, id; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m; cin >> n >> m;
+    vector<vector<E>> g(n);
+    vector<pair<int, int>> edges(m);
+    for (int id = 0; id < m; ++id) {
+        int u, v; cin >> u >> v; --u; --v; edges[id] = {u, v};
+        g[u].push_back({v, id}); g[v].push_back({u, id});
+    }
+    vector<int> dfn(n), low(n), par(n, -1), pe(n, -1);
+    vector<size_t> it(n); vector<bool> bridge(m); int timer = 0;
+    for (int root = 0; root < n; ++root) if (!dfn[root]) {
+        vector<int> st{root}; dfn[root] = low[root] = ++timer;
+        while (!st.empty()) {
+            int u = st.back();
+            if (it[u] < g[u].size()) {
+                E e = g[u][it[u]++];
+                if (e.id == pe[u]) continue;
+                if (!dfn[e.to]) {
+                    par[e.to] = u; pe[e.to] = e.id;
+                    dfn[e.to] = low[e.to] = ++timer; st.push_back(e.to);
+                } else low[u] = min(low[u], dfn[e.to]);
+            } else {
+                st.pop_back();
+                if (par[u] != -1) {
+                    if (low[u] > dfn[par[u]]) bridge[pe[u]] = true;
+                    low[par[u]] = min(low[par[u]], low[u]);
+                }
+            }
+        }
+    }
+    vector<int> comp(n, -1); int count = 0;
+    for (int s = 0; s < n; ++s) if (comp[s] == -1) {
+        vector<int> st{s}; comp[s] = count;
+        while (!st.empty()) {
+            int u = st.back(); st.pop_back();
+            for (E e : g[u]) if (!bridge[e.id] && comp[e.to] == -1) {
+                comp[e.to] = count; st.push_back(e.to);
+            }
+        }
+        ++count;
+    }
+    vector<int> degree(count);
+    for (int id = 0; id < m; ++id) if (bridge[id]) {
+        auto [u, v] = edges[id]; ++degree[comp[u]]; ++degree[comp[v]];
+    }
+    int leaves = 0;
+    for (int d : degree) leaves += d == 1;
+    cout << (leaves + 1) / 2 << '\n';
+}

+ 25 - 0
参考实现/03-Bitset/AtCoder-abc258_g.cpp

@@ -0,0 +1,25 @@
+#include <bitset>
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n; cin >> n;
+    constexpr int max_n = 3000;
+    vector<bitset<max_n>> neighbor(n);
+    vector<string> matrix(n);
+    for (int i = 0; i < n; ++i) {
+        cin >> matrix[i];
+        for (int j = 0; j < n; ++j) if (matrix[i][j] == '1') neighbor[i].set(j);
+    }
+    long long sum = 0;
+    for (int i = 0; i < n; ++i) {
+        for (int j = i + 1; j < n; ++j) if (matrix[i][j] == '1') {
+            sum += static_cast<long long>((neighbor[i] & neighbor[j]).count());
+        }
+    }
+    cout << sum / 3 << '\n';
+}

+ 51 - 0
参考实现/03-Bitset/CodeForces-1097F.cpp

@@ -0,0 +1,51 @@
+#include <bitset>
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    constexpr int max_value = 7000;
+    int n, q; cin >> n >> q;
+
+    vector<int> mu(max_value + 1), primes;
+    vector<bool> composite(max_value + 1);
+    mu[1] = 1;
+    for (int i = 2; i <= max_value; ++i) {
+        if (!composite[i]) primes.push_back(i), mu[i] = -1;
+        for (int p : primes) {
+            if (i * p > max_value) break;
+            composite[i * p] = true;
+            if (i % p == 0) { mu[i * p] = 0; break; }
+            mu[i * p] = -mu[i];
+        }
+    }
+
+    vector<bitset<max_value + 1>> inverse_mask(max_value + 1);
+    for (int v = 1; v <= max_value; ++v) {
+        for (int k = 1; v * k <= max_value; ++k) {
+            if (mu[k] != 0) inverse_mask[v].set(v * k);
+        }
+    }
+    vector<bitset<max_value + 1>> state(n + 1);
+    string output;
+    while (q--) {
+        int type, x; cin >> type >> x;
+        if (type == 1) {
+            int v; cin >> v; state[x].reset();
+            for (int d = 1; d * d <= v; ++d) if (v % d == 0) {
+                state[x].set(d); state[x].set(v / d);
+            }
+        } else if (type == 2) {
+            int y, z; cin >> y >> z; state[x] = state[y] ^ state[z];
+        } else if (type == 3) {
+            int y, z; cin >> y >> z; state[x] = state[y] & state[z];
+        } else {
+            int v; cin >> v;
+            output.push_back(char('0' + ((state[x] & inverse_mask[v]).count() & 1U)));
+        }
+    }
+    cout << output << '\n';
+}

+ 36 - 0
参考实现/03-Bitset/CodeForces-914F.cpp

@@ -0,0 +1,36 @@
+#include <bitset>
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    constexpr int max_n = 100000;
+    string s; cin >> s;
+    vector<bitset<max_n>> position(26);
+    for (int i = 0; i < static_cast<int>(s.size()); ++i) position[s[i] - 'a'].set(i);
+    int q; cin >> q;
+    while (q--) {
+        int type; cin >> type;
+        if (type == 1) {
+            int i; char c; cin >> i >> c; --i;
+            position[s[i] - 'a'].reset(i);
+            s[i] = c;
+            position[s[i] - 'a'].set(i);
+        } else {
+            int l, r; string y; cin >> l >> r >> y; --l; --r;
+            int valid = r - l - static_cast<int>(y.size()) + 2;
+            if (valid <= 0) { cout << "0\n"; continue; }
+            bitset<max_n> match;
+            match.set();
+            for (int j = 0; j < static_cast<int>(y.size()); ++j) {
+                match &= position[y[j] - 'a'] >> j;
+            }
+            match >>= l;
+            match <<= max_n - valid;  // 只保留移位后下标 [0, valid-1]
+            cout << match.count() << '\n';
+        }
+    }
+}

+ 52 - 0
参考实现/04-KMP与Manacher/CodeForces-17E.cpp

@@ -0,0 +1,52 @@
+#include <algorithm>
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n; string s; cin >> n >> s;
+    vector<int> d1(n), d2(n);
+    for (int i = 0, l = 0, r = -1; i < n; ++i) {
+        int k = i > r ? 1 : min(d1[l + r - i], r - i + 1);
+        while (i - k >= 0 && i + k < n && s[i - k] == s[i + k]) ++k;
+        d1[i] = k;
+        if (i + k - 1 > r) l = i - k + 1, r = i + k - 1;
+    }
+    for (int i = 0, l = 0, r = -1; i < n; ++i) {
+        int k = i > r ? 0 : min(d2[l + r - i + 1], r - i + 1);
+        while (i - k - 1 >= 0 && i + k < n && s[i - k - 1] == s[i + k]) ++k;
+        d2[i] = k;
+        if (i + k - 1 > r) l = i - k, r = i + k - 1;
+    }
+
+    vector<long long> start_diff(n + 1), end_diff(n + 1);
+    auto add = [&](vector<long long> &diff, int l, int r) {
+        if (l > r) return;
+        ++diff[l]; --diff[r + 1];
+    };
+    long long palindromes = 0;
+    for (int i = 0; i < n; ++i) {
+        palindromes += d1[i] + d2[i];
+        add(start_diff, i - d1[i] + 1, i);
+        add(end_diff, i, i + d1[i] - 1);
+        add(start_diff, i - d2[i], i - 1);
+        add(end_diff, i, i + d2[i] - 1);
+    }
+
+    constexpr long long mod = 51123987;
+    long long a = palindromes, b = palindromes - 1;
+    if (a % 2 == 0) a /= 2; else b /= 2;
+    long long all_pairs = (a % mod) * (b % mod) % mod;
+
+    long long starts_here = 0, ends_here = 0, ended_before = 0, disjoint = 0;
+    for (int i = 0; i < n; ++i) {
+        starts_here += start_diff[i];
+        ends_here += end_diff[i];
+        disjoint = (disjoint + (starts_here % mod) * (ended_before % mod)) % mod;
+        ended_before += ends_here;
+    }
+    cout << (all_pairs - disjoint + mod) % mod << '\n';
+}

+ 28 - 0
参考实现/04-KMP与Manacher/CodeForces-432D.cpp

@@ -0,0 +1,28 @@
+#include <algorithm>
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    string s; cin >> s;
+    int n = static_cast<int>(s.size());
+    vector<int> pi(n), occurrences(n + 1);
+    for (int i = 1; i < n; ++i) {
+        int j = pi[i - 1];
+        while (j > 0 && s[i] != s[j]) j = pi[j - 1];
+        if (s[i] == s[j]) ++j;
+        pi[i] = j;
+    }
+    for (int x : pi) ++occurrences[x];
+    for (int len = n; len >= 1; --len) occurrences[pi[len - 1]] += occurrences[len];
+    for (int len = 1; len <= n; ++len) ++occurrences[len];
+
+    vector<int> borders;
+    for (int len = n; len > 0; len = pi[len - 1]) borders.push_back(len);
+    reverse(borders.begin(), borders.end());
+    cout << borders.size() << '\n';
+    for (int len : borders) cout << len << ' ' << occurrences[len] << '\n';
+}

+ 32 - 0
参考实现/04-KMP与Manacher/CodeForces-471D.cpp

@@ -0,0 +1,32 @@
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, w; cin >> n >> w;
+    vector<long long> a(n), b(w);
+    for (auto &x : a) cin >> x;
+    for (auto &x : b) cin >> x;
+    if (w == 1) { cout << n << '\n'; return 0; }
+    vector<long long> text(n - 1), pattern(w - 1);
+    for (int i = 0; i + 1 < n; ++i) text[i] = a[i + 1] - a[i];
+    for (int i = 0; i + 1 < w; ++i) pattern[i] = b[i + 1] - b[i];
+    vector<int> pi(pattern.size());
+    for (int i = 1; i < static_cast<int>(pattern.size()); ++i) {
+        int j = pi[i - 1];
+        while (j > 0 && pattern[i] != pattern[j]) j = pi[j - 1];
+        if (pattern[i] == pattern[j]) ++j;
+        pi[i] = j;
+    }
+    int matched = 0, answer = 0;
+    for (long long x : text) {
+        while (matched > 0 && x != pattern[matched]) matched = pi[matched - 1];
+        if (x == pattern[matched]) ++matched;
+        if (matched == static_cast<int>(pattern.size())) {
+            ++answer; matched = pi[matched - 1];
+        }
+    }
+    cout << answer << '\n';
+}

+ 22 - 0
参考实现/04-KMP与Manacher/POJ-2406.cpp

@@ -0,0 +1,22 @@
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    string s;
+    while (cin >> s && s != ".") {
+        int n = static_cast<int>(s.size());
+        vector<int> pi(n);
+        for (int i = 1; i < n; ++i) {
+            int j = pi[i - 1];
+            while (j > 0 && s[i] != s[j]) j = pi[j - 1];
+            if (s[i] == s[j]) ++j;
+            pi[i] = j;
+        }
+        int period = n - pi[n - 1];
+        cout << (n % period == 0 ? n / period : 1) << '\n';
+    }
+}

+ 30 - 0
参考实现/04-KMP与Manacher/POJ-3461.cpp

@@ -0,0 +1,30 @@
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int tests; cin >> tests;
+    while (tests--) {
+        string pattern, text; cin >> pattern >> text;
+        vector<int> pi(pattern.size());
+        for (int i = 1; i < static_cast<int>(pattern.size()); ++i) {
+            int j = pi[i - 1];
+            while (j > 0 && pattern[i] != pattern[j]) j = pi[j - 1];
+            if (pattern[i] == pattern[j]) ++j;
+            pi[i] = j;
+        }
+        int matched = 0, answer = 0;
+        for (char c : text) {
+            while (matched > 0 && c != pattern[matched]) matched = pi[matched - 1];
+            if (c == pattern[matched]) ++matched;
+            if (matched == static_cast<int>(pattern.size())) {
+                ++answer;
+                matched = pi[matched - 1];
+            }
+        }
+        cout << answer << '\n';
+    }
+}

+ 32 - 0
参考实现/04-KMP与Manacher/POJ-3974.cpp

@@ -0,0 +1,32 @@
+#include <algorithm>
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    string s;
+    int test = 0;
+    while (cin >> s && s != "END") {
+        int n = static_cast<int>(s.size());
+        vector<int> d1(n), d2(n);
+        for (int i = 0, l = 0, r = -1; i < n; ++i) {
+            int k = (i > r) ? 1 : min(d1[l + r - i], r - i + 1);
+            while (i - k >= 0 && i + k < n && s[i - k] == s[i + k]) ++k;
+            d1[i] = k;
+            if (i + k - 1 > r) l = i - k + 1, r = i + k - 1;
+        }
+        for (int i = 0, l = 0, r = -1; i < n; ++i) {
+            int k = (i > r) ? 0 : min(d2[l + r - i + 1], r - i + 1);
+            while (i - k - 1 >= 0 && i + k < n && s[i - k - 1] == s[i + k]) ++k;
+            d2[i] = k;
+            if (i + k - 1 > r) l = i - k, r = i + k - 1;
+        }
+        int answer = 1;
+        for (int x : d1) answer = max(answer, 2 * x - 1);
+        for (int x : d2) answer = max(answer, 2 * x);
+        cout << "Case " << ++test << ": " << answer << '\n';
+    }
+}

+ 39 - 0
参考实现/05-最短路与类最短路/AtCoder-abc277_e.cpp

@@ -0,0 +1,39 @@
+#include <deque>
+#include <iostream>
+#include <limits>
+#include <utility>
+#include <vector>
+using namespace std;
+struct Edge { int to, cost; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m, k; cin >> n >> m >> k;
+    auto id = [n](int v, int mode) { return v + mode * n; };
+    vector<vector<Edge>> g(2 * n);
+    for (int i = 0; i < m; ++i) {
+        int u, v, a; cin >> u >> v >> a; --u; --v;
+        g[id(u, a)].push_back({id(v, a), 1});
+        g[id(v, a)].push_back({id(u, a), 1});
+    }
+    for (int i = 0; i < k; ++i) {
+        int v; cin >> v; --v;
+        g[id(v, 0)].push_back({id(v, 1), 0});
+        g[id(v, 1)].push_back({id(v, 0), 0});
+    }
+    const int inf = numeric_limits<int>::max() / 4;
+    vector<int> dist(2 * n, inf); vector<bool> done(2 * n, false); deque<int> dq;
+    dist[id(0, 1)] = 0; dq.push_front(id(0, 1));
+    while (!dq.empty()) {
+        int u = dq.front(); dq.pop_front();
+        if (done[u]) continue;
+        done[u] = true;
+        for (Edge e : g[u]) if (dist[e.to] > dist[u] + e.cost) {
+            dist[e.to] = dist[u] + e.cost;
+            if (e.cost == 0) dq.push_front(e.to); else dq.push_back(e.to);
+        }
+    }
+    int answer = min(dist[id(n - 1, 0)], dist[id(n - 1, 1)]);
+    cout << (answer == inf ? -1 : answer) << '\n';
+}

+ 30 - 0
参考实现/05-最短路与类最短路/AtCoder-abc340_d.cpp

@@ -0,0 +1,30 @@
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <queue>
+#include <utility>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n; cin >> n;
+    vector<vector<pair<int, long long>>> g(n);
+    for (int i = 0; i + 1 < n; ++i) {
+        long long a, b; int x; cin >> a >> b >> x; --x;
+        g[i].push_back({i + 1, a}); g[i].push_back({x, b});
+    }
+    const long long inf = numeric_limits<long long>::max() / 4;
+    vector<long long> dist(n, inf); dist[0] = 0;
+    priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<>> pq;
+    pq.push({0, 0});
+    while (!pq.empty()) {
+        auto [d, u] = pq.top(); pq.pop();
+        if (d != dist[u]) continue;
+        for (auto [v, w] : g[u]) if (dist[v] > d + w) {
+            dist[v] = d + w; pq.push({dist[v], v});
+        }
+    }
+    cout << dist[n - 1] << '\n';
+}

+ 42 - 0
参考实现/05-最短路与类最短路/CodeForces-229B.cpp

@@ -0,0 +1,42 @@
+#include <algorithm>
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <queue>
+#include <utility>
+#include <vector>
+using namespace std;
+struct Edge { int to; long long weight; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m; cin >> n >> m;
+    vector<vector<Edge>> g(n);
+    while (m--) {
+        int u, v; long long w; cin >> u >> v >> w; --u; --v;
+        g[u].push_back({v, w}); g[v].push_back({u, w});
+    }
+    vector<vector<long long>> blocked(n);
+    for (int i = 0; i < n; ++i) {
+        int k; cin >> k; blocked[i].resize(k);
+        for (auto &x : blocked[i]) cin >> x;
+    }
+    const long long inf = numeric_limits<long long>::max() / 4;
+    vector<long long> dist(n, inf); dist[0] = 0;
+    priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<>> pq;
+    pq.push({0, 0});
+    while (!pq.empty()) {
+        auto [d, u] = pq.top(); pq.pop();
+        if (d != dist[u]) continue;
+        if (u == n - 1) { cout << d << '\n'; return 0; }
+        long long depart = d;
+        auto it = lower_bound(blocked[u].begin(), blocked[u].end(), depart);
+        while (it != blocked[u].end() && *it == depart) ++depart, ++it;
+        for (Edge e : g[u]) if (dist[e.to] > depart + e.weight) {
+            dist[e.to] = depart + e.weight;
+            pq.push({dist[e.to], e.to});
+        }
+    }
+    cout << "-1\n";
+}

+ 50 - 0
参考实现/05-最短路与类最短路/CodeForces-449B.cpp

@@ -0,0 +1,50 @@
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <queue>
+#include <tuple>
+#include <utility>
+#include <vector>
+using namespace std;
+struct Edge { int to; long long weight; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m, k; cin >> n >> m >> k;
+    vector<vector<Edge>> g(n);
+    vector<tuple<int, int, long long>> roads;
+    for (int i = 0; i < m; ++i) {
+        int u, v; long long w; cin >> u >> v >> w; --u; --v;
+        g[u].push_back({v, w}); g[v].push_back({u, w});
+        roads.push_back({u, v, w});
+    }
+    const long long inf = numeric_limits<long long>::max() / 4;
+    vector<long long> train(n, inf), dist(n, inf);
+    for (int i = 0; i < k; ++i) {
+        int v; long long w; cin >> v >> w; --v;
+        train[v] = min(train[v], w);
+    }
+    priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<>> pq;
+    dist[0] = 0; pq.push({0, 0});
+    for (int v = 1; v < n; ++v) if (train[v] < inf) {
+        dist[v] = train[v]; pq.push({dist[v], v});
+    }
+    while (!pq.empty()) {
+        auto [d, u] = pq.top(); pq.pop();
+        if (d != dist[u]) continue;
+        for (Edge e : g[u]) if (dist[e.to] > d + e.weight) {
+            dist[e.to] = d + e.weight; pq.push({dist[e.to], e.to});
+        }
+    }
+    vector<bool> road_predecessor(n, false);
+    for (auto [u, v, w] : roads) {
+        if (dist[u] + w == dist[v]) road_predecessor[v] = true;
+        if (dist[v] + w == dist[u]) road_predecessor[u] = true;
+    }
+    int needed = 0;
+    for (int v = 1; v < n; ++v) {
+        if (train[v] == dist[v] && !road_predecessor[v]) ++needed;
+    }
+    cout << k - needed << '\n';
+}

+ 46 - 0
参考实现/05-最短路与类最短路/CodeForces-545E.cpp

@@ -0,0 +1,46 @@
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <queue>
+#include <utility>
+#include <vector>
+using namespace std;
+struct Edge { int to, id; long long weight; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m; cin >> n >> m;
+    vector<vector<Edge>> g(n);
+    for (int id = 0; id < m; ++id) {
+        int u, v; long long w; cin >> u >> v >> w; --u; --v;
+        g[u].push_back({v, id, w}); g[v].push_back({u, id, w});
+    }
+    int source; cin >> source; --source;
+    const long long inf = numeric_limits<long long>::max() / 4;
+    vector<long long> dist(n, inf), parent_weight(n, inf);
+    vector<int> parent_edge(n, -1);
+    priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<>> pq;
+    dist[source] = 0; pq.push({0, source});
+    while (!pq.empty()) {
+        auto [d, u] = pq.top(); pq.pop();
+        if (d != dist[u]) continue;
+        for (Edge e : g[u]) {
+            long long candidate = d + e.weight;
+            if (candidate < dist[e.to]) {
+                dist[e.to] = candidate;
+                parent_weight[e.to] = e.weight;
+                parent_edge[e.to] = e.id;
+                pq.push({candidate, e.to});
+            } else if (candidate == dist[e.to] && e.weight < parent_weight[e.to]) {
+                parent_weight[e.to] = e.weight;
+                parent_edge[e.to] = e.id;
+            }
+        }
+    }
+    long long total = 0;
+    for (int v = 0; v < n; ++v) if (v != source) total += parent_weight[v];
+    cout << total << '\n';
+    for (int v = 0; v < n; ++v) if (v != source) cout << parent_edge[v] + 1 << ' ';
+    cout << '\n';
+}

+ 49 - 0
参考实现/05-最短路与类最短路/CodeForces-59E.cpp

@@ -0,0 +1,49 @@
+#include <algorithm>
+#include <iostream>
+#include <queue>
+#include <unordered_set>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m, k; cin >> n >> m >> k;
+    vector<vector<int>> g(n + 1);
+    for (int i = 0; i < m; ++i) {
+        int u, v; cin >> u >> v; g[u].push_back(v); g[v].push_back(u);
+    }
+    int width = n + 1;
+    auto state = [width](int previous, int current) { return previous * width + current; };
+    auto triple = [width](int a, int b, int c) {
+        return (static_cast<long long>(a) * width + b) * width + c;
+    };
+    unordered_set<long long> forbidden;
+    forbidden.reserve(static_cast<size_t>(k) * 2 + 1);
+    while (k--) { int a, b, c; cin >> a >> b >> c; forbidden.insert(triple(a, b, c)); }
+
+    int states = width * width;
+    vector<int> dist(states, -1), parent(states, -1);
+    int start = state(0, 1), target = -1;
+    queue<int> q; q.push(start); dist[start] = 0;
+    while (!q.empty() && target == -1) {
+        int id = q.front(); q.pop();
+        int previous = id / width, current = id % width;
+        for (int next : g[current]) {
+            if (forbidden.count(triple(previous, current, next))) continue;
+            int next_state = state(current, next);
+            if (dist[next_state] != -1) continue;
+            dist[next_state] = dist[id] + 1;
+            parent[next_state] = id;
+            if (next == n) { target = next_state; break; }
+            q.push(next_state);
+        }
+    }
+    if (target == -1) { cout << "-1\n"; return 0; }
+    vector<int> path;
+    for (int id = target; id != -1; id = parent[id]) path.push_back(id % width);
+    reverse(path.begin(), path.end());
+    cout << path.size() - 1 << '\n';
+    for (int v : path) cout << v << ' ';
+    cout << '\n';
+}

+ 45 - 0
参考实现/05-最短路与类最短路/POJ-3169.cpp

@@ -0,0 +1,45 @@
+#include <algorithm>
+#include <iostream>
+#include <limits>
+#include <vector>
+using namespace std;
+struct Edge { int from, to; long long weight; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, like_count, dislike_count;
+    cin >> n >> like_count >> dislike_count;
+    vector<Edge> edges;
+    for (int i = 0; i + 1 < n; ++i) edges.push_back({i + 1, i, 0});
+    while (like_count--) {
+        int a, b; long long d; cin >> a >> b >> d; --a; --b;
+        edges.push_back({a, b, d});
+    }
+    while (dislike_count--) {
+        int a, b; long long d; cin >> a >> b >> d; --a; --b;
+        edges.push_back({b, a, -d});
+    }
+
+    vector<long long> all(n, 0);
+    for (int iteration = 0; iteration < n; ++iteration) {
+        bool changed = false;
+        for (Edge e : edges) if (all[e.to] > all[e.from] + e.weight) {
+            all[e.to] = all[e.from] + e.weight; changed = true;
+        }
+        if (!changed) break;
+        if (iteration == n - 1) { cout << "-1\n"; return 0; }
+    }
+
+    const long long inf = numeric_limits<long long>::max() / 4;
+    vector<long long> dist(n, inf); dist[0] = 0;
+    for (int iteration = 0; iteration + 1 < n; ++iteration) {
+        bool changed = false;
+        for (Edge e : edges) if (dist[e.from] != inf &&
+                dist[e.to] > dist[e.from] + e.weight) {
+            dist[e.to] = dist[e.from] + e.weight; changed = true;
+        }
+        if (!changed) break;
+    }
+    cout << (dist[n - 1] == inf ? -2 : dist[n - 1]) << '\n';
+}

+ 39 - 0
参考实现/05-最短路与类最短路/POJ-3255.cpp

@@ -0,0 +1,39 @@
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <queue>
+#include <utility>
+#include <vector>
+using namespace std;
+struct Edge { int to; long long weight; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m; cin >> n >> m;
+    vector<vector<Edge>> g(n);
+    while (m--) {
+        int u, v; long long w; cin >> u >> v >> w; --u; --v;
+        g[u].push_back({v, w}); g[v].push_back({u, w});
+    }
+    const long long inf = numeric_limits<long long>::max() / 4;
+    vector<long long> first(n, inf), second(n, inf);
+    priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<>> pq;
+    first[0] = 0; pq.push({0, 0});
+    while (!pq.empty()) {
+        auto [d, u] = pq.top(); pq.pop();
+        if (d > second[u]) continue;
+        for (Edge e : g[u]) {
+            long long candidate = d + e.weight;
+            if (candidate < first[e.to]) {
+                swap(candidate, first[e.to]);
+                pq.push({first[e.to], e.to});
+            }
+            if (first[e.to] < candidate && candidate < second[e.to]) {
+                second[e.to] = candidate;
+                pq.push({second[e.to], e.to});
+            }
+        }
+    }
+    cout << second[n - 1] << '\n';
+}

+ 36 - 0
参考实现/06-最小与最大生成树/AtCoder-arc076_b.cpp

@@ -0,0 +1,36 @@
+#include <algorithm>
+#include <iostream>
+#include <numeric>
+#include <tuple>
+#include <vector>
+using namespace std;
+struct DSU {
+    vector<int> p, size;
+    explicit DSU(int n) : p(n), size(n, 1) { iota(p.begin(), p.end(), 0); }
+    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
+    bool unite(int a, int b) {
+        a = find(a); b = find(b); if (a == b) return false;
+        if (size[a] < size[b]) swap(a, b); p[b] = a; size[a] += size[b]; return true;
+    }
+};
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n; cin >> n;
+    vector<long long> x(n), y(n); vector<int> order(n);
+    for (int i = 0; i < n; ++i) cin >> x[i] >> y[i], order[i] = i;
+    vector<tuple<long long, int, int>> edges;
+    auto add_neighbors = [&](const vector<long long> &coordinate) {
+        sort(order.begin(), order.end(), [&](int a, int b) { return coordinate[a] < coordinate[b]; });
+        for (int i = 1; i < n; ++i) {
+            int u = order[i - 1], v = order[i];
+            edges.push_back({min(abs(x[u] - x[v]), abs(y[u] - y[v])), u, v});
+        }
+    };
+    add_neighbors(x); add_neighbors(y);
+    sort(edges.begin(), edges.end());
+    DSU dsu(n); long long answer = 0;
+    for (auto [w, u, v] : edges) if (dsu.unite(u, v)) answer += w;
+    cout << answer << '\n';
+}

+ 35 - 0
参考实现/06-最小与最大生成树/CodeForces-1095F.cpp

@@ -0,0 +1,35 @@
+#include <algorithm>
+#include <iostream>
+#include <numeric>
+#include <tuple>
+#include <vector>
+using namespace std;
+struct DSU {
+    vector<int> p, s;
+    explicit DSU(int n) : p(n), s(n, 1) { iota(p.begin(), p.end(), 0); }
+    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
+    bool unite(int a, int b) {
+        a = find(a); b = find(b); if (a == b) return false;
+        if (s[a] < s[b]) swap(a, b); p[b] = a; s[a] += s[b]; return true;
+    }
+};
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m; cin >> n >> m;
+    vector<long long> a(n);
+    for (auto &x : a) cin >> x;
+    vector<tuple<long long, int, int>> edges;
+    edges.reserve(m + n - 1);
+    while (m--) {
+        int u, v; long long w; cin >> u >> v >> w;
+        edges.push_back({w, u - 1, v - 1});
+    }
+    int hub = int(min_element(a.begin(), a.end()) - a.begin());
+    for (int v = 0; v < n; ++v) if (v != hub) edges.push_back({a[hub] + a[v], hub, v});
+    sort(edges.begin(), edges.end());
+    DSU dsu(n); long long answer = 0;
+    for (auto [w, u, v] : edges) if (dsu.unite(u, v)) answer += w;
+    cout << answer << '\n';
+}

+ 34 - 0
参考实现/06-最小与最大生成树/CodeForces-1245D.cpp

@@ -0,0 +1,34 @@
+#include <iostream>
+#include <limits>
+#include <utility>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n; cin >> n;
+    vector<long long> x(n), y(n), c(n), k(n);
+    for (int i = 0; i < n; ++i) cin >> x[i] >> y[i];
+    for (auto &v : c) cin >> v;
+    for (auto &v : k) cin >> v;
+    vector<long long> best = c;
+    vector<int> parent(n, -1); vector<bool> used(n, false);
+    vector<int> stations; vector<pair<int, int>> wires;
+    long long total = 0;
+    for (int step = 0; step < n; ++step) {
+        int v = -1;
+        for (int i = 0; i < n; ++i) if (!used[i] && (v == -1 || best[i] < best[v])) v = i;
+        used[v] = true; total += best[v];
+        if (parent[v] == -1) stations.push_back(v);
+        else wires.push_back({v, parent[v]});
+        for (int to = 0; to < n; ++to) if (!used[to]) {
+            long long cost = (k[v] + k[to]) * (abs(x[v] - x[to]) + abs(y[v] - y[to]));
+            if (cost < best[to]) best[to] = cost, parent[to] = v;
+        }
+    }
+    cout << total << '\n' << stations.size() << '\n';
+    for (int v : stations) cout << v + 1 << ' ';
+    cout << '\n' << wires.size() << '\n';
+    for (auto [u, v] : wires) cout << u + 1 << ' ' << v + 1 << '\n';
+}

+ 65 - 0
参考实现/06-最小与最大生成树/CodeForces-160D.cpp

@@ -0,0 +1,65 @@
+#include <algorithm>
+#include <functional>
+#include <iostream>
+#include <numeric>
+#include <string>
+#include <utility>
+#include <vector>
+using namespace std;
+struct DSU {
+    vector<int> p, s;
+    explicit DSU(int n) : p(n), s(n, 1) { iota(p.begin(), p.end(), 0); }
+    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
+    void unite(int a, int b) {
+        a = find(a); b = find(b); if (a == b) return;
+        if (s[a] < s[b]) swap(a, b); p[b] = a; s[a] += s[b];
+    }
+};
+struct Edge { int u, v, w, id; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m; cin >> n >> m;
+    vector<Edge> edges(m);
+    for (int i = 0; i < m; ++i) {
+        cin >> edges[i].u >> edges[i].v >> edges[i].w;
+        --edges[i].u; --edges[i].v; edges[i].id = i;
+    }
+    sort(edges.begin(), edges.end(), [](const Edge &a, const Edge &b) { return a.w < b.w; });
+    vector<string> answer(m, "none"); DSU dsu(n);
+    for (int left = 0; left < m; ) {
+        int right = left;
+        while (right < m && edges[right].w == edges[left].w) ++right;
+        vector<int> candidate, roots;
+        for (int i = left; i < right; ++i) {
+            int a = dsu.find(edges[i].u), b = dsu.find(edges[i].v);
+            if (a != b) {
+                candidate.push_back(i); roots.push_back(a); roots.push_back(b);
+                answer[edges[i].id] = "at least one";
+            }
+        }
+        sort(roots.begin(), roots.end()); roots.erase(unique(roots.begin(), roots.end()), roots.end());
+        vector<vector<pair<int, int>>> graph(roots.size());
+        for (int index : candidate) {
+            int a = int(lower_bound(roots.begin(), roots.end(), dsu.find(edges[index].u)) - roots.begin());
+            int b = int(lower_bound(roots.begin(), roots.end(), dsu.find(edges[index].v)) - roots.begin());
+            graph[a].push_back({b, edges[index].id}); graph[b].push_back({a, edges[index].id});
+        }
+        vector<int> tin(roots.size(), -1), low(roots.size()); int timer = 0;
+        function<void(int, int)> dfs = [&](int u, int parent_edge) {
+            tin[u] = low[u] = timer++;
+            for (auto [v, id] : graph[u]) {
+                if (id == parent_edge) continue;
+                if (tin[v] == -1) {
+                    dfs(v, id); low[u] = min(low[u], low[v]);
+                    if (low[v] > tin[u]) answer[id] = "any";
+                } else low[u] = min(low[u], tin[v]);
+            }
+        };
+        for (int v = 0; v < static_cast<int>(roots.size()); ++v) if (tin[v] == -1) dfs(v, -1);
+        for (int i = left; i < right; ++i) dsu.unite(edges[i].u, edges[i].v);
+        left = right;
+    }
+    for (const string &s : answer) cout << s << '\n';
+}

+ 74 - 0
参考实现/06-最小与最大生成树/CodeForces-1706E.cpp

@@ -0,0 +1,74 @@
+#include <algorithm>
+#include <iostream>
+#include <numeric>
+#include <utility>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int tests; cin >> tests;
+    while (tests--) {
+        int n, m, queries; cin >> n >> m >> queries;
+        vector<int> dsu(2 * n), value(2 * n, 0);
+        iota(dsu.begin(), dsu.end(), 0);
+        vector<vector<int>> child(2 * n);
+        auto find = [&](auto &&self, int x) -> int {
+            return dsu[x] == x ? x : dsu[x] = self(self, dsu[x]);
+        };
+        int nodes = n;
+        for (int index = 1; index <= m; ++index) {
+            int u, v; cin >> u >> v; --u; --v;
+            int a = find(find, u), b = find(find, v);
+            if (a == b) continue;
+            value[nodes] = index;
+            child[nodes] = {a, b};
+            dsu[a] = dsu[b] = nodes;
+            dsu[nodes] = nodes;
+            ++nodes;
+        }
+        int root = find(find, 0), log = 1;
+        while ((1 << log) <= nodes) ++log;
+        vector<vector<int>> up(log, vector<int>(nodes, root));
+        vector<int> depth(nodes, 0), stack{root};
+        while (!stack.empty()) {
+            int u = stack.back(); stack.pop_back();
+            for (int v : child[u]) {
+                up[0][v] = u; depth[v] = depth[u] + 1; stack.push_back(v);
+            }
+        }
+        up[0][root] = root;
+        for (int j = 1; j < log; ++j) for (int v = 0; v < nodes; ++v) {
+            up[j][v] = up[j - 1][up[j - 1][v]];
+        }
+        auto lca = [&](int u, int v) {
+            if (depth[u] < depth[v]) swap(u, v);
+            for (int j = log - 1; j >= 0; --j) if (depth[u] - (1 << j) >= depth[v]) u = up[j][u];
+            if (u == v) return u;
+            for (int j = log - 1; j >= 0; --j) if (up[j][u] != up[j][v]) {
+                u = up[j][u]; v = up[j][v];
+            }
+            return up[0][u];
+        };
+
+        int size = 1;
+        while (size < max(1, n - 1)) size <<= 1;
+        vector<int> segment(2 * size, 0);
+        for (int i = 0; i + 1 < n; ++i) segment[size + i] = value[lca(i, i + 1)];
+        for (int i = size - 1; i > 0; --i) segment[i] = max(segment[2 * i], segment[2 * i + 1]);
+        auto range_max = [&](int left, int right) {
+            int answer = 0;
+            for (left += size, right += size; left < right; left >>= 1, right >>= 1) {
+                if (left & 1) answer = max(answer, segment[left++]);
+                if (right & 1) answer = max(answer, segment[--right]);
+            }
+            return answer;
+        };
+        while (queries--) {
+            int l, r; cin >> l >> r; --l;
+            cout << (l + 1 == r ? 0 : range_max(l, r - 1)) << ' ';
+        }
+        cout << '\n';
+    }
+}

+ 66 - 0
参考实现/06-最小与最大生成树/CodeForces-609E.cpp

@@ -0,0 +1,66 @@
+#include <algorithm>
+#include <iostream>
+#include <numeric>
+#include <queue>
+#include <tuple>
+#include <vector>
+using namespace std;
+struct DSU {
+    vector<int> p, s;
+    explicit DSU(int n) : p(n), s(n, 1) { iota(p.begin(), p.end(), 0); }
+    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
+    bool unite(int a, int b) {
+        a = find(a); b = find(b); if (a == b) return false;
+        if (s[a] < s[b]) swap(a, b); p[b] = a; s[a] += s[b]; return true;
+    }
+};
+struct Edge { int u, v; long long w; bool tree = false; };
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m; cin >> n >> m;
+    vector<Edge> edges(m); vector<int> order(m);
+    for (int i = 0; i < m; ++i) {
+        cin >> edges[i].u >> edges[i].v >> edges[i].w;
+        --edges[i].u; --edges[i].v; order[i] = i;
+    }
+    sort(order.begin(), order.end(), [&](int a, int b) { return edges[a].w < edges[b].w; });
+    vector<vector<pair<int, long long>>> tree(n);
+    DSU dsu(n); long long total = 0;
+    for (int id : order) if (dsu.unite(edges[id].u, edges[id].v)) {
+        edges[id].tree = true; total += edges[id].w;
+        tree[edges[id].u].push_back({edges[id].v, edges[id].w});
+        tree[edges[id].v].push_back({edges[id].u, edges[id].w});
+    }
+    constexpr int log = 20;
+    vector<vector<int>> up(log, vector<int>(n));
+    vector<vector<long long>> maximum(log, vector<long long>(n));
+    vector<int> depth(n, -1); queue<int> q; depth[0] = 0; up[0][0] = 0; q.push(0);
+    while (!q.empty()) {
+        int u = q.front(); q.pop();
+        for (auto [v, w] : tree[u]) if (depth[v] == -1) {
+            depth[v] = depth[u] + 1; up[0][v] = u; maximum[0][v] = w; q.push(v);
+        }
+    }
+    for (int j = 1; j < log; ++j) for (int v = 0; v < n; ++v) {
+        up[j][v] = up[j - 1][up[j - 1][v]];
+        maximum[j][v] = max(maximum[j - 1][v], maximum[j - 1][up[j - 1][v]]);
+    }
+    auto path_max = [&](int u, int v) {
+        long long answer = 0;
+        if (depth[u] < depth[v]) swap(u, v);
+        for (int j = log - 1; j >= 0; --j) if (depth[u] - (1 << j) >= depth[v]) {
+            answer = max(answer, maximum[j][u]); u = up[j][u];
+        }
+        if (u == v) return answer;
+        for (int j = log - 1; j >= 0; --j) if (up[j][u] != up[j][v]) {
+            answer = max({answer, maximum[j][u], maximum[j][v]});
+            u = up[j][u]; v = up[j][v];
+        }
+        return max({answer, maximum[0][u], maximum[0][v]});
+    };
+    for (const Edge &e : edges) {
+        cout << (e.tree ? total : total + e.w - path_max(e.u, e.v)) << '\n';
+    }
+}

+ 53 - 0
参考实现/06-最小与最大生成树/CodeForces-888G.cpp

@@ -0,0 +1,53 @@
+#include <algorithm>
+#include <array>
+#include <iostream>
+#include <limits>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n; cin >> n;
+    vector<int> a(n);
+    for (int &x : a) cin >> x;
+    sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end());
+
+    auto solve = [&](auto &&self, int left, int right, int bit) -> long long {
+        if (right - left <= 1 || bit < 0) return 0;
+        int middle = left;
+        while (middle < right && ((a[middle] >> bit) & 1) == 0) ++middle;
+        long long answer = self(self, left, middle, bit - 1) + self(self, middle, right, bit - 1);
+        if (middle == left || middle == right) return answer;
+
+        int build_l = left, build_r = middle, query_l = middle, query_r = right;
+        if (build_r - build_l > query_r - query_l) {
+            swap(build_l, query_l); swap(build_r, query_r);
+        }
+        vector<array<int, 2>> trie(1, array<int, 2>{-1, -1});
+        trie.reserve(static_cast<size_t>(build_r - build_l) * (bit + 1) + 1);
+        for (int i = build_l; i < build_r; ++i) {
+            int node = 0;
+            for (int b = bit - 1; b >= 0; --b) {
+                int digit = (a[i] >> b) & 1;
+                if (trie[node][digit] == -1) {
+                    trie[node][digit] = static_cast<int>(trie.size());
+                    trie.push_back({-1, -1});
+                }
+                node = trie[node][digit];
+            }
+        }
+        int best = numeric_limits<int>::max();
+        for (int i = query_l; i < query_r; ++i) {
+            int node = 0, cost = 0;
+            for (int b = bit - 1; b >= 0; --b) {
+                int digit = (a[i] >> b) & 1;
+                if (trie[node][digit] != -1) node = trie[node][digit];
+                else cost |= 1 << b, node = trie[node][digit ^ 1];
+            }
+            best = min(best, cost);
+        }
+        return answer + (1LL << bit) + best;
+    };
+    cout << solve(solve, 0, static_cast<int>(a.size()), 29) << '\n';
+}

+ 48 - 0
参考实现/07-二分图/CodeForces-1139E.cpp

@@ -0,0 +1,48 @@
+#include <functional>
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, clubs; cin >> n >> clubs;
+    vector<int> potential(n), club(n);
+    for (int &x : potential) cin >> x;
+    for (int &x : club) cin >> x, --x;
+    int days; cin >> days;
+    vector<int> removed(days); vector<bool> will_remove(n, false);
+    for (int &x : removed) { cin >> x; --x; will_remove[x] = true; }
+
+    constexpr int max_potential = 5000;
+    vector<vector<int>> graph(max_potential + 1);
+    for (int i = 0; i < n; ++i) if (!will_remove[i]) graph[potential[i]].push_back(club[i]);
+    vector<int> match_club(clubs, -1), seen(clubs, 0);
+    int token = 0;
+    function<bool(int)> augment = [&](int p) {
+        for (int c : graph[p]) if (seen[c] != token) {
+            seen[c] = token;
+            if (match_club[c] == -1 || augment(match_club[c])) {
+                match_club[c] = p; return true;
+            }
+        }
+        return false;
+    };
+    int mex = 0;
+    auto advance = [&] {
+        while (mex <= clubs) {
+            ++token;
+            if (!augment(mex)) break;
+            ++mex;
+        }
+    };
+    advance();
+    vector<int> answer(days);
+    for (int day = days - 1; day >= 0; --day) {
+        answer[day] = mex;
+        int student = removed[day];
+        graph[potential[student]].push_back(club[student]);
+        advance();
+    }
+    for (int x : answer) cout << x << '\n';
+}

+ 26 - 0
参考实现/07-二分图/CodeForces-1144F.cpp

@@ -0,0 +1,26 @@
+#include <iostream>
+#include <queue>
+#include <utility>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m; cin >> n >> m;
+    vector<pair<int, int>> edges(m); vector<vector<int>> g(n);
+    for (auto &[u, v] : edges) {
+        cin >> u >> v; --u; --v; g[u].push_back(v); g[v].push_back(u);
+    }
+    vector<int> color(n, -1); queue<int> q; color[0] = 0; q.push(0);
+    while (!q.empty()) {
+        int u = q.front(); q.pop();
+        for (int v : g[u]) {
+            if (color[v] == -1) color[v] = color[u] ^ 1, q.push(v);
+            else if (color[v] == color[u]) { cout << "NO\n"; return 0; }
+        }
+    }
+    cout << "YES\n";
+    for (auto [u, v] : edges) cout << (color[u] == 0 ? '0' : '1');
+    cout << '\n';
+}

+ 51 - 0
参考实现/07-二分图/CodeForces-1354E.cpp

@@ -0,0 +1,51 @@
+#include <iostream>
+#include <queue>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m, need1, need2, need3;
+    cin >> n >> m >> need1 >> need2 >> need3;
+    vector<vector<int>> g(n);
+    while (m--) { int u, v; cin >> u >> v; --u; --v; g[u].push_back(v); g[v].push_back(u); }
+    vector<int> color(n, -1), component(n, -1);
+    vector<vector<int>> side0, side1;
+    for (int start = 0; start < n; ++start) if (color[start] == -1) {
+        int id = side0.size(); side0.push_back({}); side1.push_back({});
+        queue<int> q; q.push(start); color[start] = 0; component[start] = id;
+        while (!q.empty()) {
+            int u = q.front(); q.pop();
+            (color[u] == 0 ? side0[id] : side1[id]).push_back(u);
+            for (int v : g[u]) {
+                if (color[v] == -1) color[v] = color[u] ^ 1, component[v] = id, q.push(v);
+                else if (color[v] == color[u]) { cout << "NO\n"; return 0; }
+            }
+        }
+    }
+    int count = side0.size();
+    vector<vector<signed char>> choice(count + 1, vector<signed char>(need2 + 1, -1));
+    choice[0][0] = 0;
+    for (int i = 0; i < count; ++i) for (int sum = 0; sum <= need2; ++sum) if (choice[i][sum] != -1) {
+        if (sum + static_cast<int>(side0[i].size()) <= need2)
+            choice[i + 1][sum + side0[i].size()] = 0;
+        if (sum + static_cast<int>(side1[i].size()) <= need2)
+            choice[i + 1][sum + side1[i].size()] = 1;
+    }
+    if (choice[count][need2] == -1) { cout << "NO\n"; return 0; }
+    vector<int> selected(count); int sum = need2;
+    for (int i = count; i > 0; --i) {
+        selected[i - 1] = choice[i][sum];
+        sum -= selected[i - 1] == 0 ? side0[i - 1].size() : side1[i - 1].size();
+    }
+    vector<char> answer(n, '3');
+    for (int i = 0; i < count; ++i) {
+        const vector<int> &middle = selected[i] == 0 ? side0[i] : side1[i];
+        for (int v : middle) answer[v] = '2';
+    }
+    for (int v = 0; v < n && need1 > 0; ++v) if (answer[v] != '2') answer[v] = '1', --need1;
+    cout << "YES\n";
+    for (char c : answer) cout << c;
+    cout << '\n';
+}

+ 83 - 0
参考实现/07-二分图/CodeForces-498C.cpp

@@ -0,0 +1,83 @@
+#include <algorithm>
+#include <iostream>
+#include <limits>
+#include <queue>
+#include <utility>
+#include <vector>
+using namespace std;
+
+struct Dinic {
+    struct Edge { int to, reverse, capacity; };
+    vector<vector<Edge>> g;
+    vector<int> level, cursor;
+    explicit Dinic(int n) : g(n), level(n), cursor(n) {}
+    void add_edge(int u, int v, int capacity) {
+        Edge a{v, static_cast<int>(g[v].size()), capacity};
+        Edge b{u, static_cast<int>(g[u].size()), 0};
+        g[u].push_back(a); g[v].push_back(b);
+    }
+    bool bfs(int source, int sink) {
+        fill(level.begin(), level.end(), -1); queue<int> q;
+        level[source] = 0; q.push(source);
+        while (!q.empty()) {
+            int u = q.front(); q.pop();
+            for (const Edge &e : g[u]) if (e.capacity > 0 && level[e.to] == -1) {
+                level[e.to] = level[u] + 1; q.push(e.to);
+            }
+        }
+        return level[sink] != -1;
+    }
+    int dfs(int u, int sink, int pushed) {
+        if (u == sink) return pushed;
+        for (int &i = cursor[u]; i < static_cast<int>(g[u].size()); ++i) {
+            Edge &e = g[u][i];
+            if (e.capacity > 0 && level[e.to] == level[u] + 1) {
+                int flow = dfs(e.to, sink, min(pushed, e.capacity));
+                if (flow) {
+                    e.capacity -= flow; g[e.to][e.reverse].capacity += flow; return flow;
+                }
+            }
+        }
+        return 0;
+    }
+    int max_flow(int source, int sink) {
+        int answer = 0, flow;
+        while (bfs(source, sink)) {
+            fill(cursor.begin(), cursor.end(), 0);
+            while ((flow = dfs(source, sink, numeric_limits<int>::max() / 4)) > 0) answer += flow;
+        }
+        return answer;
+    }
+};
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, m; cin >> n >> m;
+    vector<int> a(n), original(n), primes;
+    for (int &x : a) cin >> x;
+    original = a;
+    for (int x : a) {
+        for (int p = 2; 1LL * p * p <= x; ++p) if (x % p == 0) {
+            primes.push_back(p); while (x % p == 0) x /= p;
+        }
+        if (x > 1) primes.push_back(x);
+    }
+    sort(primes.begin(), primes.end()); primes.erase(unique(primes.begin(), primes.end()), primes.end());
+    vector<pair<int, int>> pairs(m);
+    for (auto &[u, v] : pairs) { cin >> u >> v; --u; --v; if (u % 2 == 1) swap(u, v); }
+
+    int answer = 0, source = n, sink = n + 1;
+    for (int prime : primes) {
+        Dinic flow(n + 2); vector<int> exponent(n);
+        for (int i = 0; i < n; ++i) {
+            int x = original[i];
+            while (x % prime == 0) ++exponent[i], x /= prime;
+            if (i % 2 == 0) flow.add_edge(source, i, exponent[i]);
+            else flow.add_edge(i, sink, exponent[i]);
+        }
+        for (auto [u, v] : pairs) flow.add_edge(u, v, 1'000'000);
+        answer += flow.max_flow(source, sink);
+    }
+    cout << answer << '\n';
+}

+ 30 - 0
参考实现/07-二分图/CodeForces-741C.cpp

@@ -0,0 +1,30 @@
+#include <iostream>
+#include <queue>
+#include <utility>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n; cin >> n;
+    vector<pair<int, int>> couple(n); vector<vector<int>> g(2 * n);
+    for (auto &[a, b] : couple) {
+        cin >> a >> b; --a; --b; g[a].push_back(b); g[b].push_back(a);
+    }
+    for (int i = 0; i < 2 * n; i += 2) {
+        g[i].push_back(i + 1); g[i + 1].push_back(i);
+    }
+    vector<int> color(2 * n, -1);
+    for (int s = 0; s < 2 * n; ++s) if (color[s] == -1) {
+        queue<int> q; q.push(s); color[s] = 0;
+        while (!q.empty()) {
+            int u = q.front(); q.pop();
+            for (int v : g[u]) {
+                if (color[v] == -1) color[v] = color[u] ^ 1, q.push(v);
+                else if (color[v] == color[u]) { cout << "-1\n"; return 0; }
+            }
+        }
+    }
+    for (auto [a, b] : couple) cout << color[a] + 1 << ' ' << color[b] + 1 << '\n';
+}

+ 49 - 0
参考实现/07-二分图/HDU-2255.cpp

@@ -0,0 +1,49 @@
+#include <algorithm>
+#include <iostream>
+#include <limits>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n;
+    while (cin >> n) {
+        vector<vector<long long>> weight(n, vector<long long>(n));
+        for (auto &row : weight) for (auto &x : row) cin >> x;
+        vector<long long> lx(n), ly(n, 0), slack(n);
+        vector<int> match_y(n, -1);
+        for (int x = 0; x < n; ++x) lx[x] = *max_element(weight[x].begin(), weight[x].end());
+
+        for (int root = 0; root < n; ++root) {
+            fill(slack.begin(), slack.end(), numeric_limits<long long>::max() / 4);
+            while (true) {
+                vector<bool> seen_x(n, false), seen_y(n, false);
+                auto augment = [&](auto &&self, int x) -> bool {
+                    seen_x[x] = true;
+                    for (int y = 0; y < n; ++y) if (!seen_y[y]) {
+                        long long gap = lx[x] + ly[y] - weight[x][y];
+                        if (gap == 0) {
+                            seen_y[y] = true;
+                            if (match_y[y] == -1 || self(self, match_y[y])) {
+                                match_y[y] = x; return true;
+                            }
+                        } else slack[y] = min(slack[y], gap);
+                    }
+                    return false;
+                };
+                if (augment(augment, root)) break;
+                long long delta = numeric_limits<long long>::max() / 4;
+                for (int y = 0; y < n; ++y) if (!seen_y[y]) delta = min(delta, slack[y]);
+                for (int x = 0; x < n; ++x) if (seen_x[x]) lx[x] -= delta;
+                for (int y = 0; y < n; ++y) {
+                    if (seen_y[y]) ly[y] += delta;
+                    else slack[y] -= delta;
+                }
+            }
+        }
+        long long answer = 0;
+        for (int y = 0; y < n; ++y) answer += weight[match_y[y]][y];
+        cout << answer << '\n';
+    }
+}

+ 27 - 0
参考实现/07-二分图/POJ-1274.cpp

@@ -0,0 +1,27 @@
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int cows, stalls;
+    while (cin >> cows >> stalls) {
+        vector<vector<int>> g(cows);
+        for (int u = 0; u < cows; ++u) {
+            int count; cin >> count;
+            while (count--) { int v; cin >> v; g[u].push_back(v - 1); }
+        }
+        vector<int> match(stalls, -1), seen(stalls);
+        int token = 0, answer = 0;
+        auto augment = [&](auto &&self, int u) -> bool {
+            for (int v : g[u]) if (seen[v] != token) {
+                seen[v] = token;
+                if (match[v] == -1 || self(self, match[v])) { match[v] = u; return true; }
+            }
+            return false;
+        };
+        for (int u = 0; u < cows; ++u) { ++token; answer += augment(augment, u); }
+        cout << answer << '\n';
+    }
+}

+ 23 - 0
参考实现/07-二分图/POJ-3041.cpp

@@ -0,0 +1,23 @@
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int main() {
+    ios::sync_with_stdio(false);
+    cin.tie(nullptr);
+    int n, k; cin >> n >> k;
+    vector<vector<int>> g(n);
+    while (k--) { int row, column; cin >> row >> column; g[row - 1].push_back(column - 1); }
+    vector<int> match(n, -1), seen(n); int token = 0, answer = 0;
+    auto augment = [&](auto &&self, int row) -> bool {
+        for (int column : g[row]) if (seen[column] != token) {
+            seen[column] = token;
+            if (match[column] == -1 || self(self, match[column])) {
+                match[column] = row; return true;
+            }
+        }
+        return false;
+    };
+    for (int row = 0; row < n; ++row) { ++token; answer += augment(augment, row); }
+    cout << answer << '\n';
+}

+ 5 - 0
参考实现/08-高级线段树与树状数组/CSES-1737.cpp

@@ -0,0 +1,5 @@
+#include <iostream>
+#include <vector>
+using namespace std;
+struct Node{int l=0,r=0;long long sum=0;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,q;cin>>n>>q;vector<long long>a(n);for(auto&x:a)cin>>x;vector<Node>tr(1);tr.reserve(4*n+q*20);auto build=[&](auto&&self,int l,int r)->int{int u=tr.size();tr.push_back({});if(l==r){tr[u].sum=a[l];return u;}int m=(l+r)/2;tr[u].l=self(self,l,m);tr[u].r=self(self,m+1,r);tr[u].sum=tr[tr[u].l].sum+tr[tr[u].r].sum;return u;};auto upd=[&](auto&&self,int old,int l,int r,int p,long long x)->int{int u=tr.size();tr.push_back(tr[old]);if(l==r){tr[u].sum=x;return u;}int m=(l+r)/2;if(p<=m)tr[u].l=self(self,tr[old].l,l,m,p,x);else tr[u].r=self(self,tr[old].r,m+1,r,p,x);tr[u].sum=tr[tr[u].l].sum+tr[tr[u].r].sum;return u;};auto ask=[&](auto&&self,int u,int l,int r,int ql,int qr)->long long{if(ql<=l&&r<=qr)return tr[u].sum;int m=(l+r)/2;long long s=0;if(ql<=m)s+=self(self,tr[u].l,l,m,ql,qr);if(qr>m)s+=self(self,tr[u].r,m+1,r,ql,qr);return s;};vector<int>root{build(build,0,n-1)};while(q--){int type,k;cin>>type>>k;--k;if(type==1){int p;long long x;cin>>p>>x;root[k]=upd(upd,root[k],0,n-1,p-1,x);}else if(type==2){int l,r;cin>>l>>r;cout<<ask(ask,root[k],0,n-1,l-1,r-1)<<'\n';}else root.push_back(root[k]);}}

+ 6 - 0
参考实现/08-高级线段树与树状数组/CodeForces-1042D.cpp

@@ -0,0 +1,6 @@
+#include <algorithm>
+#include <iostream>
+#include <vector>
+using namespace std;
+struct BIT{vector<int>t;explicit BIT(int n):t(n+1){}void add(int x){for(;x<(int)t.size();x+=x&-x)++t[x];}int sum(int x){int s=0;for(;x;x-=x&-x)s+=t[x];return s;}};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;long long limit;cin>>n>>limit;vector<long long>p(n+1),v;for(int i=1;i<=n;++i){long long x;cin>>x;p[i]=p[i-1]+x;}v=p;sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());BIT bit(v.size());long long ans=0,inserted=0;bit.add(lower_bound(v.begin(),v.end(),p[0])-v.begin()+1);++inserted;for(int i=1;i<=n;++i){int le=upper_bound(v.begin(),v.end(),p[i]-limit)-v.begin();ans+=inserted-bit.sum(le);bit.add(lower_bound(v.begin(),v.end(),p[i])-v.begin()+1);++inserted;}cout<<ans<<'\n';}

Різницю між файлами не показано, бо вона завелика
+ 8 - 0
参考实现/08-高级线段树与树状数组/CodeForces-1114F.cpp


+ 6 - 0
参考实现/08-高级线段树与树状数组/CodeForces-438D.cpp

@@ -0,0 +1,6 @@
+#include <algorithm>
+#include <iostream>
+#include <vector>
+using namespace std;
+struct Node{long long sum=0,mx=0;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,q;cin>>n>>q;vector<long long>a(n);for(auto&x:a)cin>>x;vector<Node>tr(4*n);auto pull=[&](int u){tr[u]={tr[u*2].sum+tr[u*2+1].sum,max(tr[u*2].mx,tr[u*2+1].mx)};};auto build=[&](auto&&self,int u,int l,int r)->void{if(l==r){tr[u]={a[l],a[l]};return;}int m=(l+r)/2;self(self,u*2,l,m);self(self,u*2+1,m+1,r);pull(u);};auto mod=[&](auto&&self,int u,int l,int r,int ql,int qr,long long x)->void{if(qr<l||r<ql||tr[u].mx<x)return;if(l==r){tr[u].sum%=x;tr[u].mx=tr[u].sum;return;}int m=(l+r)/2;self(self,u*2,l,m,ql,qr,x);self(self,u*2+1,m+1,r,ql,qr,x);pull(u);};auto setv=[&](auto&&self,int u,int l,int r,int p,long long x)->void{if(l==r){tr[u]={x,x};return;}int m=(l+r)/2;if(p<=m)self(self,u*2,l,m,p,x);else self(self,u*2+1,m+1,r,p,x);pull(u);};auto sum=[&](auto&&self,int u,int l,int r,int ql,int qr)->long long{if(ql<=l&&r<=qr)return tr[u].sum;int m=(l+r)/2;long long s=0;if(ql<=m)s+=self(self,u*2,l,m,ql,qr);if(qr>m)s+=self(self,u*2+1,m+1,r,ql,qr);return s;};build(build,1,0,n-1);while(q--){int op;cin>>op;if(op==1){int l,r;cin>>l>>r;cout<<sum(sum,1,0,n-1,l-1,r-1)<<'\n';}else if(op==2){int l,r;long long x;cin>>l>>r>>x;mod(mod,1,0,n-1,l-1,r-1,x);}else{int p;long long x;cin>>p>>x;setv(setv,1,0,n-1,p-1,x);}}}

+ 6 - 0
参考实现/08-高级线段树与树状数组/CodeForces-459D.cpp

@@ -0,0 +1,6 @@
+#include <iostream>
+#include <unordered_map>
+#include <vector>
+using namespace std;
+struct BIT{vector<int>t;explicit BIT(int n):t(n+1){}void add(int x,int v){for(;x<(int)t.size();x+=x&-x)t[x]+=v;}int sum(int x){int s=0;for(;x;x-=x&-x)s+=t[x];return s;}};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;vector<long long>a(n);for(auto&x:a)cin>>x;vector<int>L(n),R(n);unordered_map<long long,int>c;for(int i=0;i<n;++i)L[i]=++c[a[i]];c.clear();for(int i=n-1;i>=0;--i)R[i]=++c[a[i]];BIT bit(n);for(int x:R)bit.add(x,1);long long ans=0;for(int i=0;i<n;++i){bit.add(R[i],-1);ans+=bit.sum(L[i]-1);}cout<<ans<<'\n';}

+ 7 - 0
参考实现/08-高级线段树与树状数组/CodeForces-558E.cpp

@@ -0,0 +1,7 @@
+#include <array>
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+struct Node{array<int,26> count{};int lazy=-1;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,q;string s;cin>>n>>q>>s;vector<Node>tr(4*n);auto pull=[&](int u){for(int c=0;c<26;++c)tr[u].count[c]=tr[u*2].count[c]+tr[u*2+1].count[c];};auto apply=[&](int u,int l,int r,int c){tr[u].count.fill(0);tr[u].count[c]=r-l+1;tr[u].lazy=c;};auto push=[&](int u,int l,int r){if(tr[u].lazy<0||l==r)return;int m=(l+r)/2;apply(u*2,l,m,tr[u].lazy);apply(u*2+1,m+1,r,tr[u].lazy);tr[u].lazy=-1;};auto build=[&](auto&&self,int u,int l,int r)->void{if(l==r){tr[u].count[s[l]-'a']=1;return;}int m=(l+r)/2;self(self,u*2,l,m);self(self,u*2+1,m+1,r);pull(u);};auto assign=[&](auto&&self,int u,int l,int r,int ql,int qr,int c)->void{if(qr<l||r<ql)return;if(ql<=l&&r<=qr){apply(u,l,r,c);return;}push(u,l,r);int m=(l+r)/2;self(self,u*2,l,m,ql,qr,c);self(self,u*2+1,m+1,r,ql,qr,c);pull(u);};auto ask=[&](auto&&self,int u,int l,int r,int ql,int qr)->array<int,26>{if(ql<=l&&r<=qr)return tr[u].count;push(u,l,r);int m=(l+r)/2;array<int,26>z{};if(ql<=m){auto a=self(self,u*2,l,m,ql,qr);for(int c=0;c<26;++c)z[c]+=a[c];}if(qr>m){auto a=self(self,u*2+1,m+1,r,ql,qr);for(int c=0;c<26;++c)z[c]+=a[c];}return z;};build(build,1,0,n-1);while(q--){int l,r,k;cin>>l>>r>>k;--l;--r;auto cnt=ask(ask,1,0,n-1,l,r);int pos=l;if(k==1){for(int c=0;c<26;++c)if(cnt[c])assign(assign,1,0,n-1,pos,pos+cnt[c]-1,c),pos+=cnt[c];}else{for(int c=25;c>=0;--c)if(cnt[c])assign(assign,1,0,n-1,pos,pos+cnt[c]-1,c),pos+=cnt[c];}}for(int i=0;i<n;++i){auto x=ask(ask,1,0,n-1,i,i);for(int c=0;c<26;++c)if(x[c])cout<<char('a'+c);}cout<<'\n';}

+ 6 - 0
参考实现/08-高级线段树与树状数组/CodeForces-61E.cpp

@@ -0,0 +1,6 @@
+#include <algorithm>
+#include <iostream>
+#include <vector>
+using namespace std;
+struct BIT { vector<int> t; explicit BIT(int n):t(n+1){} void add(int x,int v){for(;x<(int)t.size();x+=x&-x)t[x]+=v;} int sum(int x){int s=0;for(;x;x-=x&-x)s+=t[x];return s;} };
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;vector<long long>a(n),v;for(auto&x:a)cin>>x;v=a;sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());vector<int>l(n),r(n);BIT bit(v.size());for(int i=0;i<n;++i){int x=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;l[i]=i-bit.sum(x);bit.add(x,1);}bit=BIT(v.size());for(int i=n-1;i>=0;--i){int x=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;r[i]=bit.sum(x-1);bit.add(x,1);}long long ans=0;for(int i=0;i<n;++i)ans+=1LL*l[i]*r[i];cout<<ans<<'\n';}

+ 6 - 0
参考实现/08-高级线段树与树状数组/CodeForces-920F.cpp

@@ -0,0 +1,6 @@
+#include <algorithm>
+#include <iostream>
+#include <vector>
+using namespace std;
+struct Node{long long sum=0;int mx=0;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);constexpr int V=1000000;vector<int>d(V+1);for(int x=1;x<=V;++x)for(int y=x;y<=V;y+=x)++d[y];int n,q;cin>>n>>q;vector<int>a(n);for(int&x:a)cin>>x;vector<Node>tr(4*n);auto pull=[&](int u){tr[u]={tr[u*2].sum+tr[u*2+1].sum,max(tr[u*2].mx,tr[u*2+1].mx)};};auto build=[&](auto&&self,int u,int l,int r)->void{if(l==r){tr[u]={a[l],a[l]};return;}int m=(l+r)/2;self(self,u*2,l,m);self(self,u*2+1,m+1,r);pull(u);};auto replace=[&](auto&&self,int u,int l,int r,int ql,int qr)->void{if(qr<l||r<ql||tr[u].mx<=2)return;if(l==r){tr[u].mx=d[tr[u].mx];tr[u].sum=tr[u].mx;return;}int m=(l+r)/2;self(self,u*2,l,m,ql,qr);self(self,u*2+1,m+1,r,ql,qr);pull(u);};auto sum=[&](auto&&self,int u,int l,int r,int ql,int qr)->long long{if(ql<=l&&r<=qr)return tr[u].sum;int m=(l+r)/2;long long s=0;if(ql<=m)s+=self(self,u*2,l,m,ql,qr);if(qr>m)s+=self(self,u*2+1,m+1,r,ql,qr);return s;};build(build,1,0,n-1);while(q--){int type,l,r;cin>>type>>l>>r;--l;--r;if(type==1)replace(replace,1,0,n-1,l,r);else cout<<sum(sum,1,0,n-1,l,r)<<'\n';}}

+ 7 - 0
参考实现/08-高级线段树与树状数组/HDU-5306.cpp

@@ -0,0 +1,7 @@
+#include <algorithm>
+#include <iostream>
+#include <limits>
+#include <vector>
+using namespace std;
+struct Node{long long sum=0,mx=0,se=-1;int cnt=0;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin>>T;while(T--){int n,q;cin>>n>>q;vector<long long>a(n);for(auto&x:a)cin>>x;vector<Node>tr(4*n);auto pull=[&](int u){auto&A=tr[u*2];auto&B=tr[u*2+1];tr[u].sum=A.sum+B.sum;if(A.mx==B.mx){tr[u].mx=A.mx;tr[u].cnt=A.cnt+B.cnt;tr[u].se=max(A.se,B.se);}else if(A.mx>B.mx){tr[u].mx=A.mx;tr[u].cnt=A.cnt;tr[u].se=max(A.se,B.mx);}else{tr[u].mx=B.mx;tr[u].cnt=B.cnt;tr[u].se=max(A.mx,B.se);}};auto build=[&](auto&&self,int u,int l,int r)->void{if(l==r){tr[u]={a[l],a[l],-1,1};return;}int m=(l+r)/2;self(self,u*2,l,m);self(self,u*2+1,m+1,r);pull(u);};auto apply=[&](int u,long long x){tr[u].sum-=(tr[u].mx-x)*tr[u].cnt;tr[u].mx=x;};auto push=[&](int u){if(tr[u*2].mx>tr[u].mx)apply(u*2,tr[u].mx);if(tr[u*2+1].mx>tr[u].mx)apply(u*2+1,tr[u].mx);};auto chmin=[&](auto&&self,int u,int l,int r,int ql,int qr,long long x)->void{if(qr<l||r<ql||tr[u].mx<=x)return;if(ql<=l&&r<=qr&&tr[u].se<x){apply(u,x);return;}push(u);int m=(l+r)/2;self(self,u*2,l,m,ql,qr,x);self(self,u*2+1,m+1,r,ql,qr,x);pull(u);};auto sum=[&](auto&&self,int u,int l,int r,int ql,int qr)->long long{if(ql<=l&&r<=qr)return tr[u].sum;push(u);int m=(l+r)/2;long long s=0;if(ql<=m)s+=self(self,u*2,l,m,ql,qr);if(qr>m)s+=self(self,u*2+1,m+1,r,ql,qr);return s;};auto mx=[&](auto&&self,int u,int l,int r,int ql,int qr)->long long{if(ql<=l&&r<=qr)return tr[u].mx;push(u);int m=(l+r)/2;long long z=0;if(ql<=m)z=max(z,self(self,u*2,l,m,ql,qr));if(qr>m)z=max(z,self(self,u*2+1,m+1,r,ql,qr));return z;};build(build,1,0,n-1);while(q--){int op,l,r;cin>>op>>l>>r;--l;--r;if(op==0){long long x;cin>>x;chmin(chmin,1,0,n-1,l,r,x);}else if(op==1)cout<<mx(mx,1,0,n-1,l,r)<<'\n';else cout<<sum(sum,1,0,n-1,l,r)<<'\n';}}}

+ 37 - 0
参考实现/08-高级线段树与树状数组/HYSBZ-2212.cpp

@@ -0,0 +1,37 @@
+#include <iostream>
+#include <vector>
+using namespace std;
+struct Node { int left = 0, right = 0, count = 0; };
+int main() {
+    ios::sync_with_stdio(false); cin.tie(nullptr);
+    int n; cin >> n;
+    vector<int> token(2 * n - 1); for (int &x : token) cin >> x;
+    vector<Node> tree(1); tree.reserve(static_cast<size_t>(n) * 20);
+    auto insert = [&](auto &&self, int l, int r, int position) -> int {
+        int u = tree.size(); tree.push_back({}); tree[u].count = 1;
+        if (l < r) { int mid = (l + r) / 2; if (position <= mid) tree[u].left = self(self, l, mid, position); else tree[u].right = self(self, mid + 1, r, position); }
+        return u;
+    };
+    auto merge = [&](auto &&self, int a, int b, int l, int r, long long &normal, long long &swapped) -> int {
+        if (!a) return b; if (!b) return a;
+        if (l < r) {
+            normal += 1LL * tree[tree[a].right].count * tree[tree[b].left].count;
+            swapped += 1LL * tree[tree[b].right].count * tree[tree[a].left].count;
+            int mid = (l + r) / 2;
+            tree[a].left = self(self, tree[a].left, tree[b].left, l, mid, normal, swapped);
+            tree[a].right = self(self, tree[a].right, tree[b].right, mid + 1, r, normal, swapped);
+        }
+        tree[a].count += tree[b].count; return a;
+    };
+    vector<int> stack; long long answer = 0;
+    for (int i = static_cast<int>(token.size()) - 1; i >= 0; --i) {
+        if (token[i] != 0) stack.push_back(insert(insert, 1, n, token[i]));
+        else {
+            int left = stack.back(); stack.pop_back(); int right = stack.back(); stack.pop_back();
+            long long normal = 0, swapped = 0;
+            stack.push_back(merge(merge, left, right, 1, n, normal, swapped));
+            answer += min(normal, swapped);
+        }
+    }
+    cout << answer << '\n';
+}

+ 65 - 0
参考实现/08-高级线段树与树状数组/HYSBZ-4552.cpp

@@ -0,0 +1,65 @@
+#include <iostream>
+#include <map>
+#include <vector>
+using namespace std;
+struct Node { int left = 0, right = 0, count = 0; };
+struct Block { int right, root; bool descending; };
+int main() {
+    ios::sync_with_stdio(false); cin.tie(nullptr);
+    int n, operations; cin >> n >> operations;
+    vector<Node> tree(1); tree.reserve(static_cast<size_t>(n + 2 * operations) * 22);
+    auto new_node = [&] { tree.push_back({}); return static_cast<int>(tree.size()) - 1; };
+    auto insert = [&](auto &&self, int u, int l, int r, int p) -> int {
+        if (!u) u = new_node(); ++tree[u].count;
+        if (l < r) { int mid = (l + r) / 2; if (p <= mid) tree[u].left = self(self, tree[u].left, l, mid, p); else tree[u].right = self(self, tree[u].right, mid + 1, r, p); }
+        return u;
+    };
+    auto pull = [&](int u) { tree[u].count = tree[tree[u].left].count + tree[tree[u].right].count; };
+    auto split_small = [&](auto &&self, int u, int k, int l, int r) -> pair<int,int> {
+        if (!u) return {0, 0};
+        if (k == 0) return {0, u};
+        if (k == tree[u].count) return {u, 0};
+        int a = new_node(), b = new_node(), mid = (l + r) / 2;
+        int left_count = tree[tree[u].left].count;
+        if (k <= left_count) {
+            auto [x, y] = self(self, tree[u].left, k, l, mid);
+            tree[a].left = x; tree[b].left = y; tree[b].right = tree[u].right;
+        } else {
+            auto [x, y] = self(self, tree[u].right, k - left_count, mid + 1, r);
+            tree[a].left = tree[u].left; tree[a].right = x; tree[b].right = y;
+        }
+        pull(a); pull(b); return {a, b};
+    };
+    auto merge = [&](auto &&self, int a, int b, int l, int r) -> int {
+        if (!a) return b; if (!b) return a;
+        if (l < r) { int mid = (l + r) / 2; tree[a].left = self(self, tree[a].left, tree[b].left, l, mid); tree[a].right = self(self, tree[a].right, tree[b].right, mid + 1, r); }
+        tree[a].count += tree[b].count; return a;
+    };
+    auto kth = [&](auto &&self, int u, int l, int r, int k) -> int {
+        if (l == r) return l; int mid = (l + r) / 2, left_count = tree[tree[u].left].count;
+        return k <= left_count ? self(self, tree[u].left, l, mid, k) : self(self, tree[u].right, mid + 1, r, k - left_count);
+    };
+    map<int, Block> blocks;
+    for (int i = 1, value; i <= n; ++i) { cin >> value; blocks[i] = {i, insert(insert, 0, 1, n, value), false}; }
+    auto split_position = [&](int position) {
+        if (position > n) return blocks.end();
+        auto it = prev(blocks.upper_bound(position));
+        if (it->first == position) return it;
+        int l = it->first, r = it->second.right, take = position - l, total = r - l + 1;
+        int first, second;
+        if (!it->second.descending) tie(first, second) = split_small(split_small, it->second.root, take, 1, n);
+        else tie(second, first) = split_small(split_small, it->second.root, total - take, 1, n);
+        bool direction = it->second.descending; it->second = {position - 1, first, direction};
+        return blocks.emplace(position, Block{r, second, direction}).first;
+    };
+    while (operations--) {
+        int op, l, r; cin >> op >> l >> r;
+        auto finish = split_position(r + 1), begin = split_position(l);
+        int root = 0;
+        for (auto it = begin; it != finish; ++it) root = merge(merge, root, it->second.root, 1, n);
+        blocks.erase(begin, finish); blocks[l] = {r, root, op == 1};
+    }
+    int q; cin >> q; auto it = prev(blocks.upper_bound(q));
+    int offset = q - it->first, size = it->second.right - it->first + 1;
+    cout << kth(kth, it->second.root, 1, n, it->second.descending ? size - offset : offset + 1) << '\n';
+}

+ 8 - 0
参考实现/08-高级线段树与树状数组/SPOJ-COT.cpp

@@ -0,0 +1,8 @@
+#include <algorithm>
+#include <array>
+#include <iostream>
+#include <queue>
+#include <vector>
+using namespace std;
+struct Node{int l=0,r=0,sum=0;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,q;cin>>n>>q;vector<int>w(n),vals;for(int&x:w)cin>>x;vals=w;sort(vals.begin(),vals.end());vals.erase(unique(vals.begin(),vals.end()),vals.end());vector<vector<int>>g(n);for(int i=1,u,v;i<n;++i){cin>>u>>v;--u;--v;g[u].push_back(v);g[v].push_back(u);}constexpr int LOG=17;vector<array<int,LOG+1>>up(n);vector<int>dep(n,-1),order;queue<int>que;dep[0]=0;que.push(0);while(!que.empty()){int u=que.front();que.pop();order.push_back(u);for(int v:g[u])if(dep[v]<0){dep[v]=dep[u]+1;up[v][0]=u;for(int j=1;j<=LOG;++j)up[v][j]=up[up[v][j-1]][j-1];que.push(v);}}vector<Node>tr(1);tr.reserve((n+1)*20);auto upd=[&](auto&&self,int old,int l,int r,int p)->int{int cur=tr.size();tr.push_back(tr[old]);++tr[cur].sum;if(l<r){int m=(l+r)/2;if(p<=m)tr[cur].l=self(self,tr[old].l,l,m,p);else tr[cur].r=self(self,tr[old].r,m+1,r,p);}return cur;};vector<int>root(n);for(int u:order){int pr=u==0?0:root[up[u][0]];root[u]=upd(upd,pr,0,vals.size()-1,lower_bound(vals.begin(),vals.end(),w[u])-vals.begin());}auto lca=[&](int a,int b){if(dep[a]<dep[b])swap(a,b);for(int j=LOG;j>=0;--j)if(dep[a]-(1<<j)>=dep[b])a=up[a][j];if(a==b)return a;for(int j=LOG;j>=0;--j)if(up[a][j]!=up[b][j])a=up[a][j],b=up[b][j];return up[a][0];};auto kth=[&](auto&&self,int A,int B,int C,int D,int l,int r,int k)->int{if(l==r)return l;int cnt=tr[tr[A].l].sum+tr[tr[B].l].sum-tr[tr[C].l].sum-tr[tr[D].l].sum,m=(l+r)/2;return k<=cnt?self(self,tr[A].l,tr[B].l,tr[C].l,tr[D].l,l,m,k):self(self,tr[A].r,tr[B].r,tr[C].r,tr[D].r,m+1,r,k-cnt);};while(q--){int a,b,k;cin>>a>>b>>k;--a;--b;int c=lca(a,b),d=c==0?0:root[up[c][0]];cout<<vals[kth(kth,root[a],root[b],root[c],d,0,vals.size()-1,k)]<<'\n';}}

+ 6 - 0
参考实现/08-高级线段树与树状数组/SPOJ-MKTHNUM.cpp

@@ -0,0 +1,6 @@
+#include <algorithm>
+#include <iostream>
+#include <vector>
+using namespace std;
+struct Node{int l=0,r=0,sum=0;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,q;cin>>n>>q;vector<int>a(n),v;for(int&x:a)cin>>x;v=a;sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());vector<Node>tr(1);tr.reserve((n+1)*20);auto upd=[&](auto&&self,int old,int l,int r,int p)->int{int cur=tr.size();tr.push_back(tr[old]);++tr[cur].sum;if(l<r){int m=(l+r)/2;if(p<=m)tr[cur].l=self(self,tr[old].l,l,m,p);else tr[cur].r=self(self,tr[old].r,m+1,r,p);}return cur;};vector<int>root(n+1);for(int i=1;i<=n;++i)root[i]=upd(upd,root[i-1],0,v.size()-1,lower_bound(v.begin(),v.end(),a[i-1])-v.begin());auto kth=[&](auto&&self,int L,int R,int l,int r,int k)->int{if(l==r)return l;int cnt=tr[tr[R].l].sum-tr[tr[L].l].sum,m=(l+r)/2;return k<=cnt?self(self,tr[L].l,tr[R].l,l,m,k):self(self,tr[L].r,tr[R].r,m+1,r,k-cnt);};while(q--){int l,r,k;cin>>l>>r>>k;cout<<v[kth(kth,root[l-1],root[r],0,v.size()-1,k)]<<'\n';}}

+ 7 - 0
参考实现/09-基环树/CodeForces-1027D.cpp

@@ -0,0 +1,7 @@
+#include <algorithm>
+#include <iostream>
+#include <limits>
+#include <queue>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;vector<int>cost(n),to(n),in(n);for(int&x:cost)cin>>x;for(int&i:to){cin>>i;--i;++in[i];}queue<int>q;vector<bool>removed(n),seen(n);for(int i=0;i<n;++i)if(in[i]==0)q.push(i);while(!q.empty()){int u=q.front();q.pop();removed[u]=true;if(--in[to[u]]==0)q.push(to[u]);}long long ans=0;for(int s=0;s<n;++s)if(!removed[s]&&!seen[s]){int u=s,best=numeric_limits<int>::max();do{seen[u]=true;best=min(best,cost[u]);u=to[u];}while(u!=s);ans+=best;}cout<<ans<<'\n';}

+ 5 - 0
参考实现/09-基环树/CodeForces-1454E.cpp

@@ -0,0 +1,5 @@
+#include <iostream>
+#include <queue>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin>>T;while(T--){int n;cin>>n;vector<vector<int>>g(n);vector<int>deg(n),size(n,1);for(int i=0,u,v;i<n;++i){cin>>u>>v;--u;--v;g[u].push_back(v);g[v].push_back(u);++deg[u];++deg[v];}queue<int>q;for(int i=0;i<n;++i)if(deg[i]==1)q.push(i);while(!q.empty()){int u=q.front();q.pop();deg[u]=0;for(int v:g[u])if(deg[v]>0){size[v]+=size[u];if(--deg[v]==1)q.push(v);}}long long ans=1LL*n*(n-1);for(int i=0;i<n;++i)if(deg[i]>0)ans-=1LL*size[i]*(size[i]-1)/2;cout<<ans<<'\n';}}

+ 5 - 0
参考实现/09-基环树/CodeForces-711D.cpp

@@ -0,0 +1,5 @@
+#include <iostream>
+#include <queue>
+#include <vector>
+using namespace std;constexpr long long MOD=1000000007;long long pw(long long a,int b){long long r=1;for(;b;b>>=1,a=a*a%MOD)if(b&1)r=r*a%MOD;return r;}
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;vector<int>to(n),in(n);for(int&i:to){cin>>i;--i;++in[i];}queue<int>q;vector<bool>removed(n),seen(n);for(int i=0;i<n;++i)if(in[i]==0)q.push(i);int peeled=0;while(!q.empty()){int u=q.front();q.pop();removed[u]=true;++peeled;if(--in[to[u]]==0)q.push(to[u]);}long long ans=pw(2,peeled);for(int s=0;s<n;++s)if(!removed[s]&&!seen[s]){int len=0,u=s;do{seen[u]=true;++len;u=to[u];}while(u!=s);ans=ans*((pw(2,len)-2+MOD)%MOD)%MOD;}cout<<ans<<'\n';}

+ 4 - 0
参考实现/10-高斯消元与CRT/AtCoder-abc186_e.cpp

@@ -0,0 +1,4 @@
+#include <iostream>
+#include <numeric>
+using namespace std;long long exgcd(long long a,long long b,long long&x,long long&y){if(!b){x=1;y=0;return a;}long long g=exgcd(b,a%b,y,x);y-=a/b*x;return g;}
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin>>T;while(T--){long long n,s,k;cin>>n>>s>>k;long long g=gcd(n,k);if(s%g){cout<<-1<<'\n';continue;}n/=g;s/=g;k/=g;long long x,y;exgcd(k,n,x,y);x%=n;if(x<0)x+=n;cout<<((n-s%n)%n*x%n)<<'\n';}}

+ 3 - 0
参考实现/10-高斯消元与CRT/POJ-1006.cpp

@@ -0,0 +1,3 @@
+#include <iostream>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);long long p,e,i,d;int tc=0;while(cin>>p>>e>>i>>d&&p!=-1){long long r=(p*5544+e*14421+i*1288-d)%21252;if(r<=0)r+=21252;cout<<"Case "<<++tc<<": the next triple peak occurs in "<<r<<" days.\n";}}

+ 5 - 0
参考实现/10-高斯消元与CRT/POJ-1222.cpp

@@ -0,0 +1,5 @@
+#include <bitset>
+#include <iostream>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin>>T;for(int tc=1;tc<=T;++tc){vector<bitset<31>>a(30);for(int r=0;r<5;++r)for(int c=0;c<6;++c){int b;cin>>b;int row=r*6+c;a[row][30]=b;for(auto [dr,dc]:vector<pair<int,int>>{{0,0},{1,0},{-1,0},{0,1},{0,-1}}){int x=r+dr,y=c+dc;if(0<=x&&x<5&&0<=y&&y<6)a[row].flip(x*6+y);}}int row=0;for(int col=0;col<30;++col){int p=row;while(p<30&&!a[p][col])++p;if(p==30)continue;swap(a[p],a[row]);for(int i=0;i<30;++i)if(i!=row&&a[i][col])a[i]^=a[row];++row;}cout<<"PUZZLE #"<<tc<<'\n';for(int r=0;r<5;++r){for(int c=0;c<6;++c)cout<<a[r*6+c][30]<<(c==5?'\n':' ');}}}

+ 4 - 0
参考实现/10-高斯消元与CRT/POJ-1830.cpp

@@ -0,0 +1,4 @@
+#include <iostream>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin>>T;while(T--){int n;cin>>n;vector<int>from(n),to(n);for(int&x:from)cin>>x;for(int&x:to)cin>>x;vector<vector<int>>a(n,vector<int>(n+1));for(int i=0;i<n;++i)a[i][i]=1,a[i][n]=from[i]^to[i];int u,v;while(cin>>u>>v&&u+v){a[v-1][u-1]^=1;}int row=0;for(int col=0;col<n&&row<n;++col){int p=row;while(p<n&&!a[p][col])++p;if(p==n)continue;swap(a[p],a[row]);for(int i=0;i<n;++i)if(i!=row&&a[i][col])for(int j=col;j<=n;++j)a[i][j]^=a[row][j];++row;}bool bad=false;for(int i=row;i<n;++i)if(a[i][n])bad=true;if(bad)cout<<"Oh,it's impossible~!!\n";else cout<<(1LL<<(n-row))<<'\n';}}

+ 3 - 0
参考实现/10-高斯消元与CRT/POJ-2891.cpp

@@ -0,0 +1,3 @@
+#include <iostream>
+using namespace std;using i128=__int128_t;long long exgcd(long long a,long long b,long long&x,long long&y){if(!b){x=1;y=0;return a;}long long g=exgcd(b,a%b,y,x);y-=a/b*x;return g;}
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;while(cin>>n){long long r=0,M=1;bool ok=true;while(n--){long long m,b;cin>>m>>b;if(!ok)continue;long long x,y,g=exgcd(M,m,x,y),diff=b-r;if(diff%g){ok=false;continue;}long long mod=m/g,t=(i128)(diff/g)*x%mod;if(t<0)t+=mod;i128 nr=(i128)r+(i128)M*t;i128 nm=(i128)M/g*m;if(nm>(i128)9e18){ok=false;continue;}M=(long long)nm;r=(long long)(nr%M);if(r<0)r+=M;}cout<<(ok?r:-1)<<'\n';}}

+ 5 - 0
参考实现/10-高斯消元与CRT/POJ-2947.cpp

@@ -0,0 +1,5 @@
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;int day(const string&s){static const string d[7]={"MON","TUE","WED","THU","FRI","SAT","SUN"};for(int i=0;i<7;++i)if(s==d[i])return i;return 0;}int inv7(int x){for(int y=1;y<7;++y)if(x*y%7==1)return y;return 0;}
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,m;while(cin>>n>>m&&n+m){vector<vector<int>>a(m,vector<int>(n+1));for(int i=0;i<m;++i){int k;string s,t;cin>>k>>s>>t;a[i][n]=(day(t)-day(s)+1+7)%7;while(k--){int x;cin>>x;a[i][x-1]=(a[i][x-1]+1)%7;}}int row=0;vector<int>where(n,-1);for(int col=0;col<n&&row<m;++col){int p=row;while(p<m&&a[p][col]==0)++p;if(p==m)continue;swap(a[p],a[row]);int z=inv7(a[row][col]);for(int j=col;j<=n;++j)a[row][j]=a[row][j]*z%7;for(int i=0;i<m;++i)if(i!=row&&a[i][col]){int f=a[i][col];for(int j=col;j<=n;++j)a[i][j]=(a[i][j]-f*a[row][j]%7+7)%7;}where[col]=row++;}bool bad=false;for(int i=row;i<m;++i)if(a[i][n])bad=true;if(bad)cout<<"Inconsistent data.\n";else if(row<n)cout<<"Multiple solutions.\n";else{for(int i=0;i<n;++i){int x=a[where[i]][n];if(x<3)x+=7;cout<<x<<(i+1==n?'\n':' ');}}}}

+ 7 - 0
参考实现/11-平衡树/CSES-2072.cpp

@@ -0,0 +1,7 @@
+#include <cstdint>
+#include <iostream>
+#include <random>
+#include <string>
+#include <vector>
+using namespace std;struct Node{int l=0,r=0,size=1;char value=0;uint32_t priority=0;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,q;string s;cin>>n>>q>>s;mt19937 rng(998244353);vector<Node>tr(1);auto size=[&](int x){return x?tr[x].size:0;};auto pull=[&](int x){tr[x].size=size(tr[x].l)+size(tr[x].r)+1;};auto split=[&](auto&&self,int root,int k)->pair<int,int>{if(!root)return{0,0};if(size(tr[root].l)>=k){auto[a,b]=self(self,tr[root].l,k);tr[root].l=b;pull(root);return{a,root};}auto[a,b]=self(self,tr[root].r,k-size(tr[root].l)-1);tr[root].r=a;pull(root);return{root,b};};auto merge=[&](auto&&self,int a,int b)->int{if(!a||!b)return a?a:b;if(tr[a].priority<tr[b].priority){tr[a].r=self(self,tr[a].r,b);pull(a);return a;}tr[b].l=self(self,a,tr[b].l);pull(b);return b;};int root=0;for(char c:s){int z=tr.size();tr.push_back({0,0,1,c,static_cast<uint32_t>(rng())});root=merge(merge,root,z);}while(q--){int l,r;cin>>l>>r;auto[ab,c]=split(split,root,r);auto[a,b]=split(split,ab,l-1);root=merge(merge,merge(merge,a,c),b);}auto output=[&](auto&&self,int u)->void{if(!u)return;self(self,tr[u].l);cout<<tr[u].value;self(self,tr[u].r);};output(output,root);cout<<'\n';}

+ 7 - 0
参考实现/11-平衡树/CSES-2073.cpp

@@ -0,0 +1,7 @@
+#include <cstdint>
+#include <iostream>
+#include <random>
+#include <string>
+#include <vector>
+using namespace std;struct Node{int l=0,r=0,size=1;char value=0;uint32_t priority=0;bool rev=false;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,q;string s;cin>>n>>q>>s;mt19937 rng(19260817);vector<Node>tr(1);auto size=[&](int x){return x?tr[x].size:0;};auto pull=[&](int x){tr[x].size=size(tr[x].l)+size(tr[x].r)+1;};auto apply=[&](int x){if(x){swap(tr[x].l,tr[x].r);tr[x].rev^=1;}};auto push=[&](int x){if(x&&tr[x].rev){apply(tr[x].l);apply(tr[x].r);tr[x].rev=false;}};auto split=[&](auto&&self,int root,int k)->pair<int,int>{if(!root)return{0,0};push(root);if(size(tr[root].l)>=k){auto[a,b]=self(self,tr[root].l,k);tr[root].l=b;pull(root);return{a,root};}auto[a,b]=self(self,tr[root].r,k-size(tr[root].l)-1);tr[root].r=a;pull(root);return{root,b};};auto merge=[&](auto&&self,int a,int b)->int{if(!a||!b)return a?a:b;if(tr[a].priority<tr[b].priority){push(a);tr[a].r=self(self,tr[a].r,b);pull(a);return a;}push(b);tr[b].l=self(self,a,tr[b].l);pull(b);return b;};int root=0;for(char c:s){int z=tr.size();tr.push_back({0,0,1,c,static_cast<uint32_t>(rng()),false});root=merge(merge,root,z);}while(q--){int l,r;cin>>l>>r;auto[ab,c]=split(split,root,r);auto[a,b]=split(split,ab,l-1);apply(b);root=merge(merge,merge(merge,a,b),c);}auto output=[&](auto&&self,int u)->void{if(!u)return;push(u);self(self,tr[u].l);cout<<tr[u].value;self(self,tr[u].r);};output(output,root);cout<<'\n';}

+ 4 - 0
参考实现/11-平衡树/CSES-2074.cpp

@@ -0,0 +1,4 @@
+#include <iostream>
+#include <vector>
+using namespace std;struct Node{int ch[2]{},parent=0,size=1;long long value=0,sum=0;bool rev=false;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,q;cin>>n>>q;vector<long long>a(n+2);for(int i=1;i<=n;++i)cin>>a[i];vector<Node>tr(n+3);int nodes=0,root=0;auto size=[&](int x){return x?tr[x].size:0;};auto sum=[&](int x){return x?tr[x].sum:0LL;};auto pull=[&](int x){tr[x].size=size(tr[x].ch[0])+size(tr[x].ch[1])+1;tr[x].sum=sum(tr[x].ch[0])+sum(tr[x].ch[1])+tr[x].value;};auto apply=[&](int x){if(x){swap(tr[x].ch[0],tr[x].ch[1]);tr[x].rev^=1;}};auto push=[&](int x){if(x&&tr[x].rev){apply(tr[x].ch[0]);apply(tr[x].ch[1]);tr[x].rev=false;}};auto build=[&](auto&&self,int l,int r,int parent)->int{if(l>r)return 0;int m=(l+r)/2,x=++nodes;tr[x].parent=parent;tr[x].value=a[m];tr[x].ch[0]=self(self,l,m-1,x);tr[x].ch[1]=self(self,m+1,r,x);pull(x);return x;};root=build(build,0,n+1,0);auto rotate=[&](int x){int y=tr[x].parent,z=tr[y].parent,d=tr[y].ch[1]==x,b=tr[x].ch[d^1];if(z)tr[z].ch[tr[z].ch[1]==y]=x;else root=x;tr[x].parent=z;tr[x].ch[d^1]=y;tr[y].parent=x;tr[y].ch[d]=b;if(b)tr[b].parent=y;pull(y);pull(x);};auto splay=[&](int x,int goal=0){vector<int>path;for(int u=x;u!=goal;u=tr[u].parent)path.push_back(u);for(auto it=path.rbegin();it!=path.rend();++it)push(*it);while(tr[x].parent!=goal){int y=tr[x].parent,z=tr[y].parent;if(z!=goal)((tr[y].ch[1]==x)==(tr[z].ch[1]==y)?rotate(y):rotate(x));rotate(x);}if(!goal)root=x;};auto kth=[&](int k){int u=root;while(true){push(u);int left=size(tr[u].ch[0]);if(k==left+1)return u;if(k<=left)u=tr[u].ch[0];else k-=left+1,u=tr[u].ch[1];}};auto expose=[&](int l,int r){int x=kth(l);splay(x);int y=kth(r+2);splay(y,x);return tr[y].ch[0];};while(q--){int type,l,r;cin>>type>>l>>r;int segment=expose(l,r);if(type==1){apply(segment);int y=tr[segment].parent;pull(y);pull(tr[y].parent);}else cout<<tr[segment].sum<<'\n';}}

+ 6 - 0
参考实现/11-平衡树/POJ-1442.cpp

@@ -0,0 +1,6 @@
+#include <cstdint>
+#include <iostream>
+#include <random>
+#include <vector>
+using namespace std;struct Node{int l=0,r=0,size=0,key=0;uint32_t priority=0;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int m,n;cin>>m>>n;vector<int>a(m),u(n);for(int&x:a)cin>>x;for(int&x:u)cin>>x;mt19937 rng(712367);vector<Node>tr(1);auto pull=[&](int x){tr[x].size=tr[tr[x].l].size+tr[tr[x].r].size+1;};auto split=[&](auto&&self,int root,int key)->pair<int,int>{if(!root)return{0,0};if(tr[root].key<=key){auto [a,b]=self(self,tr[root].r,key);tr[root].r=a;pull(root);return{root,b};}auto [a,b]=self(self,tr[root].l,key);tr[root].l=b;pull(root);return{a,root};};auto merge=[&](auto&&self,int a,int b)->int{if(!a||!b)return a?a:b;if(tr[a].priority<tr[b].priority){tr[a].r=self(self,tr[a].r,b);pull(a);return a;}tr[b].l=self(self,a,tr[b].l);pull(b);return b;};auto insert=[&](int root,int key){int z=tr.size();tr.push_back({0,0,1,key,static_cast<uint32_t>(rng())});auto [a,b]=split(split,root,key);return merge(merge,merge(merge,a,z),b);};auto kth=[&](int root,int k){while(root){int left=tr[tr[root].l].size;if(k==left+1)return tr[root].key;if(k<=left)root=tr[root].l;else k-=left+1,root=tr[root].r;}return 0;};int root=0,inserted=0;for(int i=1;i<=n;++i){while(inserted<u[i-1])root=insert(root,a[inserted++]);cout<<kth(root,i)<<'\n';}}

+ 6 - 0
参考实现/11-平衡树/POJ-3481.cpp

@@ -0,0 +1,6 @@
+#include <cstdint>
+#include <iostream>
+#include <random>
+#include <vector>
+using namespace std;struct Node{int l=0,r=0,size=0,key=0,id=0;uint32_t priority=0;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);mt19937 rng(923847);vector<Node>tr(1);auto pull=[&](int x){tr[x].size=tr[tr[x].l].size+tr[tr[x].r].size+1;};auto split=[&](auto&&self,int root,int key)->pair<int,int>{if(!root)return{0,0};if(tr[root].key<=key){auto[a,b]=self(self,tr[root].r,key);tr[root].r=a;pull(root);return{root,b};}auto[a,b]=self(self,tr[root].l,key);tr[root].l=b;pull(root);return{a,root};};auto merge=[&](auto&&self,int a,int b)->int{if(!a||!b)return a?a:b;if(tr[a].priority<tr[b].priority){tr[a].r=self(self,tr[a].r,b);pull(a);return a;}tr[b].l=self(self,a,tr[b].l);pull(b);return b;};int root=0,op;while(cin>>op&&op){if(op==1){int id,key;cin>>id>>key;int z=tr.size();tr.push_back({0,0,1,key,id,static_cast<uint32_t>(rng())});auto[a,b]=split(split,root,key);root=merge(merge,merge(merge,a,z),b);}else{if(!root){cout<<0<<'\n';continue;}int z=root;if(op==2)while(tr[z].r)z=tr[z].r;else while(tr[z].l)z=tr[z].l;cout<<tr[z].id<<'\n';auto[a,b]=split(split,root,tr[z].key-1);auto[c,d]=split(split,b,tr[z].key);root=merge(merge,a,merge(merge,merge(merge,tr[c].l,tr[c].r),d));}}}

+ 4 - 0
参考实现/11-平衡树/SPOJ-ORDERSET.cpp

@@ -0,0 +1,4 @@
+#include <iostream>
+#include <vector>
+using namespace std;struct Node{int ch[2]{},parent=0,size=1,key=0;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int q;cin>>q;vector<Node>tr(q+1);int root=0,nodes=0;auto size=[&](int x){return x?tr[x].size:0;};auto pull=[&](int x){tr[x].size=size(tr[x].ch[0])+size(tr[x].ch[1])+1;};auto rotate=[&](int x){int y=tr[x].parent,z=tr[y].parent,d=tr[y].ch[1]==x,b=tr[x].ch[d^1];if(z)tr[z].ch[tr[z].ch[1]==y]=x;else root=x;tr[x].parent=z;tr[x].ch[d^1]=y;tr[y].parent=x;tr[y].ch[d]=b;if(b)tr[b].parent=y;pull(y);pull(x);};auto splay=[&](int x,int goal=0){while(tr[x].parent!=goal){int y=tr[x].parent,z=tr[y].parent;if(z!=goal)((tr[y].ch[1]==x)==(tr[z].ch[1]==y)?rotate(y):rotate(x));rotate(x);}if(!goal)root=x;};auto find=[&](int key){int u=root,last=0;while(u&&tr[u].key!=key){last=u;u=tr[u].ch[key>tr[u].key];}if(u)splay(u);else if(last)splay(last);return u;};auto insert=[&](int key){if(!root){root=++nodes;tr[root].key=key;return;}int u=root,p=0;while(u){p=u;if(tr[u].key==key){splay(u);return;}u=tr[u].ch[key>tr[u].key];}int x=++nodes;tr[x].key=key;tr[x].parent=p;tr[p].ch[key>tr[p].key]=x;splay(x);};auto erase=[&](int key){int x=find(key);if(!x||tr[x].key!=key)return;int L=tr[x].ch[0],R=tr[x].ch[1];if(L)tr[L].parent=0;if(R)tr[R].parent=0;if(!L){root=R;return;}root=L;int u=L;while(tr[u].ch[1])u=tr[u].ch[1];splay(u);tr[u].ch[1]=R;if(R)tr[R].parent=u;pull(u);};auto kth=[&](int k){if(k<1||k>size(root))return -1;int u=root;while(true){int left=size(tr[u].ch[0]);if(k==left+1){splay(u);return tr[u].key;}if(k<=left)u=tr[u].ch[0];else k-=left+1,u=tr[u].ch[1];}};auto less=[&](int key){int u=root,ans=0,last=0;while(u){last=u;if(tr[u].key<key)ans+=size(tr[u].ch[0])+1,u=tr[u].ch[1];else u=tr[u].ch[0];}if(last)splay(last);return ans;};while(q--){char op;int x;cin>>op>>x;if(op=='I')insert(x);else if(op=='D')erase(x);else if(op=='K'){int ans=kth(x);if(ans==-1)cout<<"invalid\n";else cout<<ans<<'\n';}else cout<<less(x)<<'\n';}}

+ 6 - 0
参考实现/12-历年真题/洛谷-P10217.cpp

@@ -0,0 +1,6 @@
+#include <algorithm>
+#include <iostream>
+#include <limits>
+#include <vector>
+using namespace std;using i128=__int128_t;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin>>T;while(T--){long long n,k,x,y;cin>>n>>k>>x>>y;vector<long long>px(n+1),py(n+1);for(int i=0;i<n;++i){long long a,b;cin>>a>>b;px[i+1]=px[i]+a;py[i+1]=py[i]+b;}const i128 INF=(i128(1)<<120);i128 best=INF;for(int r=0;r<n;++r){i128 low=0,high=INF;for(int sx:{-1,1})for(int sy:{-1,1}){i128 A=i128(sx)*(x-px[r])+i128(sy)*(y-py[r]);i128 B=-i128(sx)*px[n]-i128(sy)*py[n];i128 C=B-i128(k)*n,R=i128(k)*r-A;if(C==0){if(R<0)low=1,high=0;}else if(C>0){if(R<0)low=1,high=0;else high=min(high,R/C);}else if(R<0){i128 need=(-R+(-C)-1)/(-C);low=max(low,need);}}if(low<=high)best=min(best,low*n+r);}if(best==INF)cout<<-1<<'\n';else cout<<(long long)best<<'\n';}}

+ 6 - 0
参考实现/12-历年真题/洛谷-P11232.cpp

@@ -0,0 +1,6 @@
+#include <algorithm>
+#include <iostream>
+#include <utility>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin>>T;while(T--){int n,m;long long L,V;cin>>n>>m>>L>>V;struct Car{long long d,v,a;};vector<Car>cars(n);for(auto&x:cars)cin>>x.d>>x.v>>x.a;vector<long long>p(m);for(auto&x:p)cin>>x;vector<pair<int,int>>intervals;long long limit=V*V;for(auto car:cars){int first=lower_bound(p.begin(),p.end(),car.d)-p.begin();if(first==m)continue;auto fast=[&](int idx){return car.v*car.v+2*car.a*(p[idx]-car.d)>limit;};int l=-1,r=-1;if(car.a>=0){if(car.a==0){if(car.v>V)l=first,r=m-1;}else{int lo=first,hi=m-1;while(lo<hi){int mid=(lo+hi)/2;if(fast(mid))hi=mid;else lo=mid+1;}if(fast(lo))l=lo,r=m-1;}}else if(car.v>V){int lo=first,hi=m-1;while(lo<hi){int mid=(lo+hi+1)/2;if(fast(mid))lo=mid;else hi=mid-1;}if(fast(lo))l=first,r=lo;}if(l!=-1)intervals.push_back({r,l});}sort(intervals.begin(),intervals.end());int kept=0,last=-1;for(auto[r,l]:intervals)if(last<l)last=r,++kept;cout<<intervals.size()<<' '<<m-kept<<'\n';}}

+ 6 - 0
参考实现/12-历年真题/洛谷-P11233.cpp

@@ -0,0 +1,6 @@
+#include <algorithm>
+#include <iostream>
+#include <limits>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin>>T;while(T--){int n;cin>>n;vector<int>a(n);int maximum=0;for(int&x:a)cin>>x,maximum=max(maximum,x);const long long NEG=numeric_limits<long long>::min()/4;vector<long long>base(maximum+1,NEG);base[0]=0;long long add=0,best_base=0;int current=a[0];for(int i=1;i<n;++i){int y=a[i];long long switch_value=best_base+add;if(base[y]!=NEG)switch_value=max(switch_value,base[y]+add+y);if(y==current)add+=y;long long new_base=switch_value-add;if(new_base>base[current]){base[current]=new_base;best_base=max(best_base,new_base);}current=y;}cout<<best_base+add<<'\n';}}

+ 183 - 0
参考实现/12-历年真题/洛谷-P11833.cpp

@@ -0,0 +1,183 @@
+#include <algorithm>
+#include <cstdint>
+#include <iostream>
+#include <vector>
+
+using int64 = std::int64_t;
+
+class SegmentTree {
+public:
+    explicit SegmentTree(const std::vector<int64>& values)
+        : n_(static_cast<int>(values.size()) - 1),
+          sum_(4 * n_ + 4), lazy_(4 * n_ + 4), has_lazy_(4 * n_ + 4, false) {
+        minimum_.resize(4 * n_ + 4);
+        maximum_.resize(4 * n_ + 4);
+        build(1, 1, n_, values);
+    }
+
+    int64 range_sum(int left, int right) {
+        if (left > right) return 0;
+        return range_sum(1, 1, n_, left, right);
+    }
+
+    void range_assign(int left, int right, int64 value) {
+        if (left <= right) range_assign(1, 1, n_, left, right, value);
+    }
+
+    int64 point_value(int position) {
+        return range_sum(position, position);
+    }
+
+    // The maintained array is nondecreasing. Return n+1 if no value >= target.
+    int first_at_least(int left, int64 target) {
+        return first_at_least(1, 1, n_, left, target);
+    }
+
+    // Return 0 if no value <= target in [1, right].
+    int last_at_most(int right, int64 target) {
+        return last_at_most(1, 1, n_, right, target);
+    }
+
+private:
+    int n_;
+    std::vector<int64> sum_;
+    std::vector<int64> minimum_;
+    std::vector<int64> maximum_;
+    std::vector<int64> lazy_;
+    std::vector<bool> has_lazy_;
+
+    void apply(int node, int left, int right, int64 value) {
+        sum_[node] = value * (right - left + 1);
+        minimum_[node] = maximum_[node] = value;
+        lazy_[node] = value;
+        has_lazy_[node] = true;
+    }
+
+    void push(int node, int left, int right) {
+        if (!has_lazy_[node] || left == right) return;
+        int middle = (left + right) / 2;
+        apply(node * 2, left, middle, lazy_[node]);
+        apply(node * 2 + 1, middle + 1, right, lazy_[node]);
+        has_lazy_[node] = false;
+    }
+
+    void build(int node, int left, int right, const std::vector<int64>& values) {
+        if (left == right) {
+            sum_[node] = values[left];
+            minimum_[node] = maximum_[node] = values[left];
+            return;
+        }
+        int middle = (left + right) / 2;
+        build(node * 2, left, middle, values);
+        build(node * 2 + 1, middle + 1, right, values);
+        sum_[node] = sum_[node * 2] + sum_[node * 2 + 1];
+        minimum_[node] = minimum_[node * 2];
+        maximum_[node] = maximum_[node * 2 + 1];
+    }
+
+    int64 range_sum(int node, int left, int right, int query_left, int query_right) {
+        if (query_left <= left && right <= query_right) return sum_[node];
+        push(node, left, right);
+        int middle = (left + right) / 2;
+        int64 result = 0;
+        if (query_left <= middle)
+            result += range_sum(node * 2, left, middle, query_left, query_right);
+        if (query_right > middle)
+            result += range_sum(node * 2 + 1, middle + 1, right, query_left, query_right);
+        return result;
+    }
+
+    void range_assign(int node, int left, int right, int query_left, int query_right,
+                      int64 value) {
+        if (query_left <= left && right <= query_right) {
+            apply(node, left, right, value);
+            return;
+        }
+        push(node, left, right);
+        int middle = (left + right) / 2;
+        if (query_left <= middle)
+            range_assign(node * 2, left, middle, query_left, query_right, value);
+        if (query_right > middle)
+            range_assign(node * 2 + 1, middle + 1, right, query_left, query_right, value);
+        sum_[node] = sum_[node * 2] + sum_[node * 2 + 1];
+        minimum_[node] = minimum_[node * 2];
+        maximum_[node] = maximum_[node * 2 + 1];
+    }
+
+    int first_at_least(int node, int left, int right, int query_left, int64 target) {
+        if (right < query_left || maximum_[node] < target) return n_ + 1;
+        if (left == right) return sum_[node] >= target ? left : n_ + 1;
+        push(node, left, right);
+        int middle = (left + right) / 2;
+        int result = first_at_least(node * 2, left, middle, query_left, target);
+        if (result != n_ + 1) return result;
+        return first_at_least(node * 2 + 1, middle + 1, right, query_left, target);
+    }
+
+    int last_at_most(int node, int left, int right, int query_right, int64 target) {
+        if (left > query_right || minimum_[node] > target) return 0;
+        if (left == right) return sum_[node] <= target ? left : 0;
+        push(node, left, right);
+        int middle = (left + right) / 2;
+        int result = last_at_most(node * 2 + 1, middle + 1, right, query_right, target);
+        if (result != 0) return result;
+        return last_at_most(node * 2, left, middle, query_right, target);
+    }
+};
+
+struct Box {
+    int index;
+    int64 deadline;
+    int64 target_normalized;
+};
+
+int main() {
+    std::ios::sync_with_stdio(false);
+    std::cin.tie(nullptr);
+
+    int test_point, test_cases;
+    std::cin >> test_point >> test_cases;
+    (void)test_point;
+    while (test_cases--) {
+        int n;
+        std::cin >> n;
+        std::vector<int64> normalized(n + 1);
+        std::vector<Box> boxes(n);
+        for (int i = 1; i <= n; ++i) {
+            int64 initial, target, deadline;
+            std::cin >> initial >> target >> deadline;
+            normalized[i] = initial - i;
+            boxes[i - 1] = {i, deadline, target - i};
+        }
+
+        std::sort(boxes.begin(), boxes.end(), [](const Box& lhs, const Box& rhs) {
+            if (lhs.deadline != rhs.deadline) return lhs.deadline < rhs.deadline;
+            return lhs.index < rhs.index;
+        });
+
+        SegmentTree tree(normalized);
+        int64 elapsed = 0;
+        bool possible = true;
+        for (const Box& box : boxes) {
+            int i = box.index;
+            int64 current = tree.point_value(i);
+            int64 target = box.target_normalized;
+            if (current < target) {
+                int first = tree.first_at_least(i, target);
+                int right = first - 1;
+                int64 old_sum = tree.range_sum(i, right);
+                elapsed += target * (right - i + 1) - old_sum;
+                tree.range_assign(i, right, target);
+            } else if (current > target) {
+                int last = tree.last_at_most(i, target);
+                int left = last + 1;
+                int64 old_sum = tree.range_sum(left, i);
+                elapsed += old_sum - target * (i - left + 1);
+                tree.range_assign(left, i, target);
+            }
+            if (elapsed > box.deadline) possible = false;
+        }
+        std::cout << (possible ? "Yes\n" : "No\n");
+    }
+    return 0;
+}

+ 266 - 0
参考实现/12-历年真题/洛谷-P15653.cpp

@@ -0,0 +1,266 @@
+#include <algorithm>
+#include <cstdint>
+#include <iostream>
+#include <numeric>
+#include <utility>
+#include <vector>
+
+// Standalone local-protocol version.  The official submission keeps solve_case
+// and replaces the final verifier by calls to report() and invert().
+
+struct Result {
+    int maximum_edges = 0;
+    std::vector<std::vector<int>> operations;
+};
+
+namespace {
+using Matrix = std::vector<std::vector<unsigned char>>;
+
+void toggle_clique(Matrix& difference, const std::vector<int>& vertices) {
+    for (std::size_t i = 0; i < vertices.size(); ++i) {
+        for (std::size_t j = i + 1; j < vertices.size(); ++j) {
+            int u = vertices[i];
+            int v = vertices[j];
+            difference[u][v] ^= 1;
+            difference[v][u] ^= 1;
+        }
+    }
+}
+
+void add_operation(Matrix& difference, std::vector<std::vector<int>>& operations,
+                   std::vector<int> vertices) {
+    toggle_clique(difference, vertices);
+    for (int& vertex : vertices) ++vertex;  // local matrix is zero-indexed
+    operations.push_back(std::move(vertices));
+}
+
+Matrix make_best_target(const Matrix& initial, int k, int& maximum_edges) {
+    int n = static_cast<int>(initial.size());
+    int complete_edges = n * (n - 1) / 2;
+    int edge_count = 0;
+    std::vector<int> degree_parity(n, 0);
+    for (int u = 0; u < n; ++u) {
+        for (int v = u + 1; v < n; ++v) {
+            if (initial[u][v]) {
+                ++edge_count;
+                degree_parity[u] ^= 1;
+                degree_parity[v] ^= 1;
+            }
+        }
+    }
+
+    Matrix missing(n, std::vector<unsigned char>(n, 0));
+    auto add_missing = [&](int u, int v) {
+        missing[u][v] = missing[v][u] = 1;
+    };
+
+    int residue = k % 4;
+    if (residue == 0) {
+        if (((complete_edges - edge_count) & 1) != 0) add_missing(0, 1);
+    } else if (residue == 1 || residue == 3) {
+        std::vector<int> odd;
+        for (int vertex = 0; vertex < n; ++vertex) {
+            int required_missing_parity = ((n - 1) & 1) ^ degree_parity[vertex];
+            if (required_missing_parity) odd.push_back(vertex);
+        }
+        for (std::size_t i = 0; i < odd.size(); i += 2)
+            add_missing(odd[i], odd[i + 1]);
+
+        if (residue == 1) {
+            int required_edge_parity = (complete_edges - edge_count) & 1;
+            int current_missing = static_cast<int>(odd.size() / 2);
+            if ((current_missing & 1) != required_edge_parity) {
+                if (odd.empty()) {
+                    add_missing(0, 1);
+                    add_missing(1, 2);
+                    add_missing(2, 0);
+                } else {
+                    int first = odd[0];
+                    int second = odd[1];
+                    int middle = 0;
+                    while (middle == first || middle == second) ++middle;
+                    missing[first][second] = missing[second][first] = 0;
+                    add_missing(first, middle);
+                    add_missing(middle, second);
+                }
+            }
+        }
+    }
+
+    Matrix target(n, std::vector<unsigned char>(n, 0));
+    int missing_count = 0;
+    for (int u = 0; u < n; ++u) {
+        for (int v = u + 1; v < n; ++v) {
+            target[u][v] = target[v][u] = missing[u][v] ^ 1;
+            missing_count += missing[u][v];
+        }
+    }
+    maximum_edges = complete_edges - missing_count;
+    return target;
+}
+
+bool finish_k_plus_two(Matrix& difference, const std::vector<int>& remaining,
+                       std::vector<std::vector<int>>& operations) {
+    int h = static_cast<int>(remaining.size());
+    std::vector<int> degree(h, 0);
+    for (int i = 0; i < h; ++i)
+        for (int j = i + 1; j < h; ++j)
+            if (difference[remaining[i]][remaining[j]]) degree[i] ^= 1, degree[j] ^= 1;
+
+    for (int total_parity = 0; total_parity < 2; ++total_parity) {
+        std::vector<int> incident_parity(h, 0);
+        bool possible = true;
+        if ((h & 1) == 0) {
+            for (int i = 0; i < h; ++i)
+                incident_parity[i] = degree[i] ^ total_parity;
+        } else {
+            for (int value : degree) possible = possible && value == 0;
+        }
+        if (!possible) continue;
+
+        std::vector<std::pair<int, int>> selected;
+        int actual_total = 0;
+        for (int i = 0; i < h; ++i) {
+            for (int j = i + 1; j < h; ++j) {
+                int use = difference[remaining[i]][remaining[j]] ^ total_parity ^
+                          incident_parity[i] ^ incident_parity[j];
+                if (use) selected.push_back({i, j}), actual_total ^= 1;
+            }
+        }
+        if (actual_total != total_parity) continue;
+
+        Matrix trial = difference;
+        for (auto [left_out, right_out] : selected) {
+            std::vector<int> clique;
+            for (int i = 0; i < h; ++i)
+                if (i != left_out && i != right_out) clique.push_back(remaining[i]);
+            toggle_clique(trial, clique);
+        }
+        bool zero = true;
+        for (int i = 0; i < h; ++i)
+            for (int j = i + 1; j < h; ++j)
+                zero = zero && trial[remaining[i]][remaining[j]] == 0;
+        if (!zero) continue;
+
+        for (auto [left_out, right_out] : selected) {
+            std::vector<int> clique;
+            for (int i = 0; i < h; ++i)
+                if (i != left_out && i != right_out) clique.push_back(remaining[i]);
+            add_operation(difference, operations, std::move(clique));
+        }
+        return true;
+    }
+    return false;
+}
+
+Result solve_case(const Matrix& initial, int k) {
+    int n = static_cast<int>(initial.size());
+    Result result;
+    Matrix target = make_best_target(initial, k, result.maximum_edges);
+    Matrix difference = initial;
+    for (int u = 0; u < n; ++u)
+        for (int v = u + 1; v < n; ++v)
+            difference[u][v] = difference[v][u] = initial[u][v] ^ target[u][v];
+
+    std::vector<int> remaining(n);
+    std::iota(remaining.begin(), remaining.end(), 0);
+    const int subset_size = k - 1;
+    while (static_cast<int>(remaining.size()) > k + 2) {
+        int vertex = remaining.back();
+        remaining.pop_back();
+        std::vector<int> universe = remaining;
+        std::vector<int> base(universe.begin(), universe.begin() + subset_size);
+        std::vector<int> outside(universe.begin() + subset_size, universe.end());
+        int base_zero = base[0];
+        int outside_zero = outside[0];
+
+        int outside_other_xor = 0;
+        for (std::size_t i = 1; i < outside.size(); ++i)
+            outside_other_xor ^= difference[vertex][outside[i]];
+        int base_rest_xor = 0;
+        for (int i = 1; i < subset_size; ++i)
+            base_rest_xor ^= difference[vertex][base[i]];
+
+        int total_coefficient = 0;
+        if (subset_size & 1) {
+            int a_zero = difference[vertex][outside_zero] ^ base_rest_xor;
+            int all_a = a_zero ^ outside_other_xor;
+            total_coefficient = difference[vertex][base_zero] ^ all_a;
+        }
+
+        std::vector<int> a(outside.size(), 0);
+        std::vector<int> c(subset_size, 0);
+        for (std::size_t i = 1; i < outside.size(); ++i)
+            a[i] = difference[vertex][outside[i]];
+        int all_c = ((subset_size - 1) & 1) * total_coefficient ^ base_rest_xor;
+        a[0] = difference[vertex][outside_zero] ^ all_c;
+        for (int i = 1; i < subset_size; ++i)
+            c[i] = total_coefficient ^ difference[vertex][base[i]];
+        int all_a = 0;
+        for (int value : a) all_a ^= value;
+        int base_coefficient = total_coefficient ^ all_a ^ all_c;
+
+        if (base_coefficient) {
+            std::vector<int> clique = base;
+            clique.push_back(vertex);
+            add_operation(difference, result.operations, std::move(clique));
+        }
+        for (std::size_t i = 0; i < outside.size(); ++i) {
+            if (!a[i]) continue;
+            std::vector<int> clique = base;
+            clique[0] = outside[i];
+            clique.push_back(vertex);
+            add_operation(difference, result.operations, std::move(clique));
+        }
+        for (int i = 1; i < subset_size; ++i) {
+            if (!c[i]) continue;
+            std::vector<int> clique = base;
+            clique[i] = outside_zero;
+            clique.push_back(vertex);
+            add_operation(difference, result.operations, std::move(clique));
+        }
+    }
+
+    if (!finish_k_plus_two(difference, remaining, result.operations)) {
+        result.maximum_edges = -1;  // This can only indicate a construction bug.
+    }
+    return result;
+}
+}  // namespace
+
+int main() {
+    std::ios::sync_with_stdio(false);
+    std::cin.tie(nullptr);
+
+    int test_point, test_cases;
+    std::cin >> test_point >> test_cases;
+    (void)test_point;
+    while (test_cases--) {
+        int n, m, k, operation_limit;
+        std::cin >> n >> m >> k >> operation_limit;
+        Matrix graph(n, std::vector<unsigned char>(n, 0));
+        for (int i = 0; i < m; ++i) {
+            int u, v;
+            std::cin >> u >> v;
+            --u;
+            --v;
+            graph[u][v] = graph[v][u] = 1;
+        }
+
+        Result result = solve_case(graph, k);
+        bool valid = result.maximum_edges >= 0 &&
+                     static_cast<int>(result.operations.size()) <= operation_limit;
+        for (const auto& operation : result.operations) {
+            valid = valid && static_cast<int>(operation.size()) == k;
+            std::vector<int> zero_indexed = operation;
+            for (int& vertex : zero_indexed) --vertex;
+            toggle_clique(graph, zero_indexed);
+        }
+        int final_edges = 0;
+        for (int u = 0; u < n; ++u)
+            for (int v = u + 1; v < n; ++v) final_edges += graph[u][v];
+        valid = valid && final_edges == result.maximum_edges;
+        std::cout << result.maximum_edges << ' ' << (valid ? 1 : 0) << '\n';
+    }
+    return 0;
+}

+ 8 - 0
参考实现/12-历年真题/洛谷-P1850.cpp

@@ -0,0 +1,8 @@
+#include <algorithm>
+#include <array>
+#include <iomanip>
+#include <iostream>
+#include <limits>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,m,v,e;cin>>n>>m>>v>>e;vector<int>c(n),d(n);vector<double>p(n);for(int&x:c)cin>>x,--x;for(int&x:d)cin>>x,--x;for(double&x:p)cin>>x;const int INF=1e9;vector<vector<int>>dis(v,vector<int>(v,INF));for(int i=0;i<v;++i)dis[i][i]=0;while(e--){int a,b,w;cin>>a>>b>>w;--a;--b;dis[a][b]=dis[b][a]=min(dis[a][b],w);}for(int k=0;k<v;++k)for(int i=0;i<v;++i)for(int j=0;j<v;++j)dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);const double BIG=numeric_limits<double>::infinity();vector<vector<array<double,2>>>dp(n,vector<array<double,2>>(m+1,{BIG,BIG}));dp[0][0][0]=0;if(m)dp[0][1][1]=0;for(int i=1;i<n;++i)for(int j=0;j<=min(m,i+1);++j){if(j<=i){dp[i][j][0]=min(dp[i][j][0],dp[i-1][j][0]+dis[c[i-1]][c[i]]);dp[i][j][0]=min(dp[i][j][0],dp[i-1][j][1]+(1-p[i-1])*dis[c[i-1]][c[i]]+p[i-1]*dis[d[i-1]][c[i]]);}if(j){dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][0]+(1-p[i])*dis[c[i-1]][c[i]]+p[i]*dis[c[i-1]][d[i]]);dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][1]+(1-p[i-1])*(1-p[i])*dis[c[i-1]][c[i]]+(1-p[i-1])*p[i]*dis[c[i-1]][d[i]]+p[i-1]*(1-p[i])*dis[d[i-1]][c[i]]+p[i-1]*p[i]*dis[d[i-1]][d[i]]);}}double ans=BIG;for(int j=0;j<=m;++j)ans=min({ans,dp[n-1][j][0],dp[n-1][j][1]});cout<<fixed<<setprecision(2)<<ans<<'\n';}

+ 8 - 0
参考实现/12-历年真题/洛谷-P3953.cpp

@@ -0,0 +1,8 @@
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <queue>
+#include <utility>
+#include <vector>
+using namespace std;struct Edge{int to,w;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin>>T;while(T--){int n,m,K,mod;cin>>n>>m>>K>>mod;vector<vector<Edge>>g(n),rev(n);while(m--){int u,v,w;cin>>u>>v>>w;--u;--v;g[u].push_back({v,w});rev[v].push_back({u,w});}const long long INF=numeric_limits<long long>::max()/4;vector<long long>dist(n,INF);priority_queue<pair<long long,int>,vector<pair<long long,int>>,greater<>>pq;dist[n-1]=0;pq.push({0,n-1});while(!pq.empty()){auto[d,u]=pq.top();pq.pop();if(d!=dist[u])continue;for(auto e:rev[u])if(dist[e.to]>d+e.w)dist[e.to]=d+e.w,pq.push({dist[e.to],e.to});}vector<vector<int>>dp(n,vector<int>(K+1)),state(n,vector<int>(K+1));bool infinite=false;function<int(int,int)>solve=[&](int u,int extra){if(state[u][extra]==1){infinite=true;return 0;}if(state[u][extra]==2)return dp[u][extra];state[u][extra]=1;long long ans=u==n-1;for(auto e:g[u])if(dist[e.to]!=INF){long long delta=dist[e.to]+e.w-dist[u];if(delta<=extra)ans+=solve(e.to,extra-(int)delta);}state[u][extra]=2;return dp[u][extra]=ans%mod;};int ans=solve(0,K);cout<<(infinite?-1:ans)<<'\n';}}

+ 7 - 0
参考实现/12-历年真题/洛谷-P5022.cpp

@@ -0,0 +1,7 @@
+#include <algorithm>
+#include <functional>
+#include <iostream>
+#include <utility>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,m;cin>>n>>m;vector<pair<int,int>>edges(m);vector<vector<pair<int,int>>>g(n);for(int i=0;i<m;++i){int u,v;cin>>u>>v;--u;--v;edges[i]={u,v};g[u].push_back({v,i});g[v].push_back({u,i});}for(auto&adj:g)sort(adj.begin(),adj.end());vector<int>best;auto run=[&](int banned){vector<int>order;vector<bool>seen(n);function<void(int)>dfs=[&](int u){seen[u]=true;order.push_back(u+1);for(auto[v,id]:g[u])if(id!=banned&&!seen[v])dfs(v);};dfs(0);return order;};if(m==n-1)best=run(-1);else for(int id=0;id<m;++id){auto cur=run(id);if((int)cur.size()==n&&(best.empty()||cur<best))best=move(cur);}for(int x:best)cout<<x<<' ';cout<<'\n';}

+ 4 - 0
参考实现/12-历年真题/洛谷-P5664.cpp

@@ -0,0 +1,4 @@
+#include <iostream>
+#include <vector>
+using namespace std;constexpr long long MOD=998244353;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,m;cin>>n>>m;vector<vector<long long>>a(n,vector<long long>(m));vector<long long>row(n);for(int i=0;i<n;++i)for(int j=0;j<m;++j){cin>>a[i][j];row[i]=(row[i]+a[i][j])%MOD;}long long total=1;for(int i=0;i<n;++i)total=total*(row[i]+1)%MOD;total=(total-1+MOD)%MOD;long long bad=0;int off=n;for(int col=0;col<m;++col){vector<long long>dp(2*n+1),next(2*n+1);dp[off]=1;for(int i=0;i<n;++i){fill(next.begin(),next.end(),0);for(int d=-i;d<=i;++d){long long cur=dp[off+d];next[off+d]=(next[off+d]+cur)%MOD;next[off+d+1]=(next[off+d+1]+cur*a[i][col])%MOD;next[off+d-1]=(next[off+d-1]+cur*((row[i]-a[i][col]+MOD)%MOD))%MOD;}dp.swap(next);}for(int d=1;d<=n;++d)bad=(bad+dp[off+d])%MOD;}cout<<(total-bad+MOD)%MOD<<'\n';}

+ 5 - 0
参考实现/12-历年真题/洛谷-P7077.cpp

@@ -0,0 +1,5 @@
+#include <iostream>
+#include <queue>
+#include <vector>
+using namespace std;constexpr long long MOD=998244353;struct Function{int type=3,pos=0;long long value=1;vector<int>calls;};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;vector<long long>a(n);for(auto&x:a)cin>>x;int m;cin>>m;vector<Function>f(m+1);vector<int>indegree(m+1);for(int i=0;i<m;++i){cin>>f[i].type;if(f[i].type==1){cin>>f[i].pos>>f[i].value;--f[i].pos;}else if(f[i].type==2)cin>>f[i].value;else{int c;cin>>c;f[i].calls.resize(c);for(int&x:f[i].calls){cin>>x;--x;++indegree[x];}}}int q;cin>>q;f[m].calls.resize(q);for(int&x:f[m].calls){cin>>x;--x;++indegree[x];}queue<int>que;for(int i=0;i<=m;++i)if(indegree[i]==0)que.push(i);vector<int>topo;while(!que.empty()){int u=que.front();que.pop();topo.push_back(u);for(int v:f[u].calls)if(--indegree[v]==0)que.push(v);}vector<long long>mul(m+1,1);for(auto it=topo.rbegin();it!=topo.rend();++it){int u=*it;if(f[u].type==2)mul[u]=f[u].value%MOD;else if(f[u].type==3)for(int v:f[u].calls)mul[u]=mul[u]*mul[v]%MOD;}vector<long long>coef(m+1);coef[m]=1;for(int u:topo)if(f[u].type==3){long long suffix=1;for(auto it=f[u].calls.rbegin();it!=f[u].calls.rend();++it){int v=*it;coef[v]=(coef[v]+coef[u]*suffix)%MOD;suffix=suffix*mul[v]%MOD;}}for(auto&x:a)x=x*mul[m]%MOD;for(int i=0;i<m;++i)if(f[i].type==1)a[f[i].pos]=(a[f[i].pos]+coef[i]*f[i].value)%MOD;for(long long x:a)cout<<x<<' ';cout<<'\n';}

+ 5 - 0
参考实现/12-历年真题/洛谷-P7914.cpp

@@ -0,0 +1,5 @@
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;constexpr long long MOD=1000000007;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,K;string s;cin>>n>>K>>s;vector<vector<char>>star(n,vector<char>(n));for(int l=0;l<n;++l){bool ok=true;for(int r=l;r<n&&r-l+1<=K;++r){ok&=s[r]=='*'||s[r]=='?';star[l][r]=ok;}}vector<vector<long long>>valid(n,vector<long long>(n)),primitive(n,vector<long long>(n)),after(n,vector<long long>(n));auto left_ok=[&](int i){return s[i]=='('||s[i]=='?';};auto right_ok=[&](int i){return s[i]==')'||s[i]=='?';};for(int len=2;len<=n;++len)for(int l=0;l+len<=n;++l){int r=l+len-1;if(left_ok(l)&&right_ok(r)){long long ways=len==2;if(len>2){int a=l+1,b=r-1;ways=(valid[a][b]+star[a][b])%MOD;for(int mid=a;mid<b;++mid){if(star[mid+1][b])ways=(ways+valid[a][mid])%MOD;if(star[a][mid])ways=(ways+valid[mid+1][b])%MOD;}}primitive[l][r]=ways;}long long ways=primitive[l][r];for(int mid=l;mid<r;++mid)ways=(ways+primitive[l][mid]*after[mid+1][r])%MOD;valid[l][r]=ways;ways=valid[l][r];for(int mid=l;mid<r&&mid-l+1<=K;++mid)if(star[l][mid])ways=(ways+valid[mid+1][r])%MOD;after[l][r]=ways;}cout<<valid[0][n-1]<<'\n';}

+ 179 - 0
参考实现/12-历年真题/洛谷-P8294.cpp

@@ -0,0 +1,179 @@
+#include <algorithm>
+#include <cstdint>
+#include <iostream>
+#include <limits>
+#include <utility>
+#include <vector>
+
+using int64 = std::int64_t;
+
+namespace {
+constexpr int64 INF = std::numeric_limits<int64>::max() / 4;
+
+int n;
+std::vector<int64> weight;
+std::vector<int> depth;
+std::vector<std::vector<int>> children;
+std::vector<std::vector<int>> subtree;
+std::vector<std::vector<std::pair<int, int>>> states;
+std::vector<int64> dp;
+std::vector<int64> minimum_one;
+std::vector<int64> minimum_two;
+
+int64& value(int first, int second) {
+    return dp[static_cast<std::size_t>(first) * (n + 1) + second];
+}
+
+void relax(int64& target, int64 candidate) {
+    if (candidate < target) target = candidate;
+}
+
+void prepare(int vertex) {
+    subtree[vertex].push_back(vertex);
+    for (int child : children[vertex]) {
+        depth[child] = depth[vertex] + 1;
+        prepare(child);
+        subtree[vertex].insert(subtree[vertex].end(), subtree[child].begin(),
+                               subtree[child].end());
+    }
+    for (int other : subtree[vertex]) {
+        states[vertex].push_back({vertex, other});
+        if (other != vertex) states[vertex].push_back({other, vertex});
+    }
+    if (children[vertex].size() == 2) {
+        int left = children[vertex][0];
+        int right = children[vertex][1];
+        for (int u : subtree[left]) {
+            for (int v : subtree[right]) {
+                states[vertex].push_back({u, v});
+                states[vertex].push_back({v, u});
+            }
+        }
+    }
+}
+
+void solve_subtree(int vertex) {
+    if (children[vertex].empty()) {
+        value(vertex, vertex) = weight[vertex];
+        return;
+    }
+    for (int child : children[vertex]) solve_subtree(child);
+
+    if (children[vertex].size() == 1) {
+        int child = children[vertex][0];
+        for (auto [v, i] : states[child]) {
+            relax(value(vertex, v), value(i, v) + weight[vertex]);
+            int u = v;
+            relax(value(u, vertex), value(u, i) + weight[vertex] *
+                  (depth[i] - depth[vertex]) + weight[u]);
+        }
+        return;
+    }
+
+    int left = children[vertex][0];
+    int right = children[vertex][1];
+    for (int x : subtree[vertex]) minimum_one[x] = minimum_two[x] = INF;
+
+    // The outgoing original weight is in one child, and the incoming weight
+    // finishes in the other child.
+    for (auto [j, k] : states[left]) relax(minimum_one[k], value(j, k));
+    for (auto [j, k] : states[right]) relax(minimum_one[k], value(j, k));
+    for (auto [i, k] : states[vertex]) {
+        if (i != vertex && k != vertex && minimum_one[k] < INF)
+            relax(minimum_two[i], weight[i] * (depth[k] - depth[vertex]) +
+                  minimum_one[k]);
+    }
+    for (auto [v, i] : states[left])
+        relax(value(vertex, v), weight[vertex] + value(i, v) + minimum_two[i]);
+    for (auto [v, i] : states[right])
+        relax(value(vertex, v), weight[vertex] + value(i, v) + minimum_two[i]);
+
+    for (int x : subtree[vertex]) minimum_one[x] = minimum_two[x] = INF;
+    for (auto [j, k] : states[left])
+        relax(minimum_one[j], value(j, k) + weight[vertex] *
+              (depth[k] - depth[vertex]));
+    for (auto [j, k] : states[right])
+        relax(minimum_one[j], value(j, k) + weight[vertex] *
+              (depth[k] - depth[vertex]));
+    for (auto [i, j] : states[vertex]) {
+        if (i != vertex && j != vertex && minimum_one[j] < INF)
+            relax(minimum_two[i], weight[j] * (depth[i] - depth[vertex]) +
+                  minimum_one[j]);
+    }
+    for (auto [u, i] : states[left])
+        relax(value(u, vertex), weight[u] + value(u, i) + minimum_two[i]);
+    for (auto [u, i] : states[right])
+        relax(value(u, vertex), weight[u] + value(u, i) + minimum_two[i]);
+
+    for (int x : subtree[vertex]) minimum_one[x] = minimum_two[x] = INF;
+    for (auto [u, i] : states[left]) {
+        relax(minimum_one[u], value(u, i) + weight[vertex] *
+              (depth[i] - depth[vertex]) + weight[u]);
+        relax(minimum_two[i], value(u, i));
+    }
+    for (auto [u, i] : states[right]) {
+        relax(minimum_one[u], value(u, i) + weight[vertex] *
+              (depth[i] - depth[vertex]) + weight[u]);
+        relax(minimum_two[i], value(u, i));
+    }
+    for (auto [u, v] : states[vertex]) {
+        if (u != vertex && v != vertex)
+            relax(value(u, v), minimum_one[u] + minimum_two[v]);
+    }
+}
+}  // namespace
+
+int main() {
+    std::ios::sync_with_stdio(false);
+    std::cin.tie(nullptr);
+
+    std::cin >> n;
+    weight.assign(n + 1, 0);
+    depth.assign(n + 1, 0);
+    children.assign(n + 1, {});
+    subtree.assign(n + 1, {});
+    states.assign(n + 1, {});
+    minimum_one.assign(n + 1, INF);
+    minimum_two.assign(n + 1, INF);
+    dp.assign(static_cast<std::size_t>(n + 1) * (n + 1), INF);
+    for (int i = 1; i <= n; ++i) std::cin >> weight[i];
+    for (int i = 2; i <= n; ++i) {
+        int parent;
+        std::cin >> parent;
+        children[parent].push_back(i);
+    }
+    if (n == 1) {
+        std::cout << 0 << '\n';
+        return 0;
+    }
+
+    prepare(1);
+    for (int child : children[1]) solve_subtree(child);
+
+    int64 answer = INF;
+    if (children[1].size() == 1) {
+        int child = children[1][0];
+        for (auto [u, v] : states[child])
+            relax(answer, value(u, v) + weight[1] * (depth[v] - depth[1]));
+    } else {
+        int first_child = children[1][0];
+        int second_child = children[1][1];
+        for (int direction = 0; direction < 2; ++direction) {
+            std::fill(minimum_one.begin(), minimum_one.end(), INF);
+            std::fill(minimum_two.begin(), minimum_two.end(), INF);
+            for (auto [i, j] : states[first_child])
+                relax(minimum_one[i], value(i, j) + weight[1] *
+                      (depth[j] - depth[1]));
+            for (auto [k, l] : states[second_child])
+                relax(minimum_two[l], value(k, l));
+            for (auto [i, l] : states[1]) {
+                if (i != 1 && l != 1)
+                    relax(answer, minimum_one[i] + minimum_two[l] +
+                          weight[i] * (depth[l] - depth[1]));
+            }
+            std::swap(first_child, second_child);
+        }
+    }
+    std::cout << answer << '\n';
+    return 0;
+}

+ 6 - 0
参考实现/12-历年真题/洛谷-P8817.cpp

@@ -0,0 +1,6 @@
+#include <algorithm>
+#include <iostream>
+#include <queue>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,m,k;cin>>n>>m>>k;++k;vector<long long>score(n);for(int i=1;i<n;++i)cin>>score[i];vector<vector<int>>g(n);while(m--){int u,v;cin>>u>>v;--u;--v;g[u].push_back(v);g[v].push_back(u);}vector<vector<char>>reach(n,vector<char>(n));for(int s=0;s<n;++s){vector<int>d(n,-1);queue<int>q;d[s]=0;q.push(s);while(!q.empty()){int u=q.front();q.pop();reach[s][u]=1;if(d[u]==k)continue;for(int v:g[u])if(d[v]<0)d[v]=d[u]+1,q.push(v);}}vector<vector<int>>best(n);for(int b=1;b<n;++b){for(int a=1;a<n;++a)if(a!=b&&reach[0][a]&&reach[a][b])best[b].push_back(a);sort(best[b].begin(),best[b].end(),[&](int x,int y){return score[x]>score[y];});if(best[b].size()>3)best[b].resize(3);}long long ans=0;for(int b=1;b<n;++b)for(int c=1;c<n;++c)if(b!=c&&reach[b][c])for(int a:best[b])for(int d:best[c])if(a!=c&&a!=d&&b!=d)ans=max(ans,score[a]+score[b]+score[c]+score[d]);cout<<ans<<'\n';}

+ 8 - 0
参考实现/12-历年真题/洛谷-P8818.cpp

@@ -0,0 +1,8 @@
+#include <algorithm>
+#include <array>
+#include <iostream>
+#include <limits>
+#include <vector>
+using namespace std;const long long INF=(1LL<<62);
+struct Table{int n,lg;vector<vector<long long>>mn,mx,pos,neg;Table(const vector<long long>&a){n=a.size();lg=1;while((1<<lg)<=n)++lg;mn.assign(lg,vector<long long>(n));mx=pos=neg=mn;for(int i=0;i<n;++i){mn[0][i]=mx[0][i]=a[i];pos[0][i]=a[i]>=0?a[i]:INF;neg[0][i]=a[i]<=0?a[i]:-INF;}for(int j=1;j<lg;++j)for(int i=0;i+(1<<j)<=n;++i){int h=1<<(j-1);mn[j][i]=min(mn[j-1][i],mn[j-1][i+h]);mx[j][i]=max(mx[j-1][i],mx[j-1][i+h]);pos[j][i]=min(pos[j-1][i],pos[j-1][i+h]);neg[j][i]=max(neg[j-1][i],neg[j-1][i+h]);}}array<long long,4>query(int l,int r){int j=31-__builtin_clz(r-l+1),p=r-(1<<j)+1;return{min(mn[j][l],mn[j][p]),max(mx[j][l],mx[j][p]),min(pos[j][l],pos[j][p]),max(neg[j][l],neg[j][p])};}};
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,m,q;cin>>n>>m>>q;vector<long long>a(n),b(m);for(auto&x:a)cin>>x;for(auto&x:b)cin>>x;Table A(a),B(b);while(q--){int l1,r1,l2,r2;cin>>l1>>r1>>l2>>r2;auto x=A.query(--l1,--r1),y=B.query(--l2,--r2);long long ans=-INF;for(long long v:x)if(v>-INF&&v<INF)ans=max(ans,min(v*y[0],v*y[1]));cout<<ans<<'\n';}}

+ 7 - 0
参考实现/12-历年真题/洛谷-P9166.cpp

@@ -0,0 +1,7 @@
+#include <algorithm>
+#include <iostream>
+#include <set>
+#include <utility>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n,m,x;cin>>n>>m>>x;vector<pair<int,int>>seg(m);for(auto&[l,r]:seg)cin>>l>>r;set<int>answer;auto by_left=seg;sort(by_left.begin(),by_left.end());int right=x;for(size_t i=0;i<by_left.size()&&by_left[i].first<=right;++i){if(by_left[i].second>x)answer.insert(by_left[i].second);right=max(right,by_left[i].second);}auto by_right=seg;sort(by_right.begin(),by_right.end(),[](auto a,auto b){return a.second>b.second;});int left=x;for(size_t i=0;i<by_right.size()&&by_right[i].second>=left;++i){if(by_right[i].first<x)answer.insert(by_right[i].first);left=min(left,by_right[i].first);}for(int v:answer)cout<<v<<' ';cout<<'\n';}

+ 223 - 0
参考实现/12-历年真题/洛谷-P9167.cpp

@@ -0,0 +1,223 @@
+#include <algorithm>
+#include <cstdint>
+#include <iostream>
+#include <limits>
+#include <utility>
+#include <vector>
+
+using int64 = std::int64_t;
+
+namespace {
+constexpr int MOD = 998244353;
+
+int original_vertices;
+int difference_limit;
+int total_nodes;
+int timer_value;
+std::vector<std::vector<std::pair<int, int>>> graph;
+std::vector<std::vector<int>> block_cut_tree;
+std::vector<int> discovery;
+std::vector<int> low;
+std::vector<int> vertex_stack;
+
+void build_block_cut_tree(int vertex, int parent_edge) {
+    discovery[vertex] = low[vertex] = ++timer_value;
+    vertex_stack.push_back(vertex);
+    for (auto [next, edge_id] : graph[vertex]) {
+        if (!discovery[next]) {
+            build_block_cut_tree(next, edge_id);
+            low[vertex] = std::min(low[vertex], low[next]);
+            if (low[next] >= discovery[vertex]) {
+                ++total_nodes;
+                while (true) {
+                    int current = vertex_stack.back();
+                    vertex_stack.pop_back();
+                    block_cut_tree[total_nodes].push_back(current);
+                    block_cut_tree[current].push_back(total_nodes);
+                    if (current == next) break;
+                }
+                block_cut_tree[total_nodes].push_back(vertex);
+                block_cut_tree[vertex].push_back(total_nodes);
+            }
+        } else if (edge_id != parent_edge) {
+            low[vertex] = std::min(low[vertex], discovery[next]);
+        }
+    }
+}
+
+std::vector<int> subtree_size;
+std::vector<int> maximum_part;
+int centroid = 0;
+
+void find_original_centroid(int vertex, int parent) {
+    subtree_size[vertex] = vertex <= original_vertices ? 1 : 0;
+    maximum_part[vertex] = 0;
+    for (int next : block_cut_tree[vertex]) {
+        if (next == parent) continue;
+        find_original_centroid(next, vertex);
+        subtree_size[vertex] += subtree_size[next];
+        maximum_part[vertex] = std::max(maximum_part[vertex], subtree_size[next]);
+    }
+    maximum_part[vertex] =
+        std::max(maximum_part[vertex], original_vertices - subtree_size[vertex]);
+    if (vertex <= original_vertices &&
+        (centroid == 0 || maximum_part[vertex] < maximum_part[centroid]))
+        centroid = vertex;
+}
+
+std::vector<int> order;
+std::vector<std::vector<int>> rooted_children;
+
+void root_tree(int vertex, int parent) {
+    order.push_back(vertex);
+    subtree_size[vertex] = vertex <= original_vertices ? 1 : 0;
+    for (int next : block_cut_tree[vertex]) {
+        if (next == parent) continue;
+        rooted_children[vertex].push_back(next);
+        root_tree(next, vertex);
+        subtree_size[vertex] += subtree_size[next];
+    }
+}
+
+std::vector<int> ways;
+
+void calculate_sizes_zero(int component_size) {
+    for (auto iterator = order.rbegin(); iterator != order.rend(); ++iterator) {
+        int vertex = *iterator;
+        if (subtree_size[vertex] < component_size) continue;
+        if (vertex <= original_vertices) {
+            int accumulated = 1;
+            bool exists = true;
+            for (int child : rooted_children[vertex]) {
+                if (subtree_size[child] < component_size)
+                    accumulated += subtree_size[child];
+                else if (ways[child] == 0)
+                    exists = false;
+            }
+            ways[vertex] = accumulated == component_size && exists;
+        } else {
+            ways[vertex] = 1;
+            for (int child : rooted_children[vertex]) {
+                if (subtree_size[child] < component_size || ways[child] == 0) {
+                    ways[vertex] = 0;
+                    break;
+                }
+            }
+        }
+        if (subtree_size[vertex] > component_size + 1 && ways[vertex] == 0) {
+            ways[centroid] = 0;
+            break;
+        }
+    }
+}
+
+void calculate_sizes_one(int component_size) {
+    for (auto iterator = order.rbegin(); iterator != order.rend(); ++iterator) {
+        int vertex = *iterator;
+        if (subtree_size[vertex] < component_size) continue;
+        if (vertex <= original_vertices) {
+            int accumulated = 1;
+            int product = 1;
+            int one_large_choice = 0;
+            for (int child : rooted_children[vertex]) {
+                if (subtree_size[child] < component_size) {
+                    accumulated += subtree_size[child];
+                } else if (subtree_size[child] == component_size) {
+                    if (ways[child] != 0)
+                        ++one_large_choice;
+                    else
+                        accumulated += component_size;
+                } else {
+                    product = static_cast<int>(static_cast<int64>(product) *
+                                               ways[child] % MOD);
+                }
+            }
+            ways[vertex] = 0;
+            if (component_size <= accumulated && accumulated <= component_size + 1)
+                ways[vertex] = product;
+            if (accumulated == 1)
+                ways[vertex] = static_cast<int>((ways[vertex] +
+                    static_cast<int64>(product) * one_large_choice) % MOD);
+        } else {
+            ways[vertex] = 1;
+            for (int child : rooted_children[vertex]) {
+                if (subtree_size[child] < component_size) {
+                    ways[vertex] = 0;
+                    break;
+                }
+                ways[vertex] = static_cast<int>(static_cast<int64>(ways[vertex]) *
+                                                ways[child] % MOD);
+            }
+        }
+        if (subtree_size[vertex] > component_size + 1 && ways[vertex] == 0) {
+            ways[centroid] = 0;
+            break;
+        }
+    }
+}
+
+int solve_exact_or_adjacent(int component_size, int limit) {
+    std::fill(ways.begin(), ways.end(), 0);
+    if (limit == 0) {
+        if (original_vertices % component_size != 0) return 0;
+        calculate_sizes_zero(component_size);
+        return ways[centroid];
+    }
+    calculate_sizes_one(component_size);
+    int adjacent = ways[centroid];
+    if (original_vertices % (component_size + 1) == 0) {
+        std::fill(ways.begin(), ways.end(), 0);
+        calculate_sizes_zero(component_size + 1);
+        adjacent -= ways[centroid];
+        if (adjacent < 0) adjacent += MOD;
+    }
+    return adjacent;
+}
+}  // namespace
+
+int main() {
+    std::ios::sync_with_stdio(false);
+    std::cin.tie(nullptr);
+
+    int edge_count;
+    std::cin >> original_vertices >> edge_count >> difference_limit;
+    int capacity = original_vertices + edge_count + 5;
+    graph.assign(original_vertices + 1, {});
+    block_cut_tree.assign(capacity, {});
+    discovery.assign(original_vertices + 1, 0);
+    low.assign(original_vertices + 1, 0);
+    for (int id = 0; id < edge_count; ++id) {
+        int u, v;
+        std::cin >> u >> v;
+        graph[u].push_back({v, id});
+        graph[v].push_back({u, id});
+    }
+
+    total_nodes = original_vertices;
+    build_block_cut_tree(1, -1);
+    subtree_size.assign(total_nodes + 1, 0);
+    maximum_part.assign(total_nodes + 1, 0);
+    find_original_centroid(1, 0);
+
+    rooted_children.assign(total_nodes + 1, {});
+    order.reserve(total_nodes);
+    root_tree(centroid, 0);
+    ways.assign(total_nodes + 1, 0);
+
+    std::vector<bool> candidate(original_vertices / 2 + 1, false);
+    for (int parts = 2; parts <= original_vertices; ++parts) {
+        int small = original_vertices / parts;
+        if (small <= original_vertices / 2) candidate[small] = true;
+        if (original_vertices % parts == 0 && small > 0)
+            candidate[small - 1] = true;
+    }
+
+    int answer = 0;
+    for (int size = 1; size <= original_vertices / 2; ++size) {
+        if (!candidate[size]) continue;
+        answer += solve_exact_or_adjacent(size, difference_limit);
+        if (answer >= MOD) answer -= MOD;
+    }
+    std::cout << answer << '\n';
+    return 0;
+}

+ 12 - 0
参考实现/12-历年真题/洛谷-P9169.cpp

@@ -0,0 +1,12 @@
+#include <algorithm>
+#include <cstdint>
+#include <iostream>
+#include <queue>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int id,T;cin>>id>>T;while(T--){int n,m;cin>>n>>m;vector<string>board(n);for(auto&s:board)cin>>s;vector<pair<int,int>>cell;vector<vector<int>>index(n,vector<int>(m,-1));int black=-1;vector<int>red;for(int i=0;i<n;++i)for(int j=0;j<m;++j)if(board[i][j]!='#'){int z=cell.size();cell.push_back({i,j});index[i][j]=z;if(board[i][j]=='X')black=z;if(board[i][j]=='O')red.push_back(z);}int S=cell.size(),P=S*(S-1)/2;vector<vector<int>>pair_id(S,vector<int>(S,-1));vector<pair<int,int>>pairs;for(int a=0;a<S;++a)for(int b=a+1;b<S;++b)pair_id[a][b]=pair_id[b][a]=pairs.size(),pairs.push_back({a,b});auto encode=[&](int b,int p,int turn){return (b*P+p)*2+turn;};int total=S*P*2;vector<uint8_t>outcome(total);vector<int>distance(total),remaining(total),max_child(total);vector<vector<int>>red_move(S),black_move(S),black_pred(S);int dr[4]={-1,1,0,0},dc[4]={0,0,-1,1};for(int u=0;u<S;++u){auto[r,c]=cell[u];for(int z=0;z<4;++z){int x=r+dr[z],y=c+dc[z];if(0<=x&&x<n&&0<=y&&y<m&&index[x][y]>=0)red_move[u].push_back(index[x][y]);}for(int z:{0,2,3}){int x=r+dr[z],y=c+dc[z];if(0<=x&&x<n&&0<=y&&y<m&&index[x][y]>=0)black_move[u].push_back(index[x][y]);}int x=r+1;if(x<n&&index[x][c]>=0)black_pred[u].push_back(index[x][c]);for(int z:{2,3}){int y=c+dc[z];if(0<=y&&y<m&&index[r][y]>=0)black_pred[u].push_back(index[r][y]);}}
+using Item=pair<int,int>;priority_queue<Item,vector<Item>,greater<Item>>pq;for(int b=0;b<S;++b)for(int p=0;p<P;++p){auto[r1,r2]=pairs[p];for(int turn=0;turn<2;++turn){int st=encode(b,p,turn);bool terminal=false;if(cell[b].first==0){outcome[st]=turn==1?1:2;terminal=true;}else if(b==r1||b==r2){outcome[st]=2;terminal=true;}int deg=0;if(!terminal){if(turn==0){for(int v:red_move[r1])if(v!=r2)++deg;for(int v:red_move[r2])if(v!=r1)++deg;}else deg=black_move[b].size();remaining[st]=deg;if(deg==0){outcome[st]=2;terminal=true;}}if(terminal)pq.push({0,st});}}
+auto predecessors=[&](int st,auto emit){int turn=st%2,z=st/2,p=z%P,b=z/P;auto[r1,r2]=pairs[p];if(turn==0){for(int pb:black_pred[b])emit(encode(pb,p,1));}else{for(int prev:red_move[r1])if(prev!=r2){int a=min(prev,r2),c=max(prev,r2);emit(encode(b,pair_id[a][c],0));}for(int prev:red_move[r2])if(prev!=r1){int a=min(prev,r1),c=max(prev,r1);emit(encode(b,pair_id[a][c],0));}}};while(!pq.empty()){auto[dist,st]=pq.top();pq.pop();if(dist!=distance[st])continue;predecessors(st,[&](int pre){if(outcome[pre])return;if(outcome[st]==2){outcome[pre]=1;distance[pre]=dist+1;pq.push({distance[pre],pre});}else{--remaining[pre];max_child[pre]=max(max_child[pre],dist);if(remaining[pre]==0){outcome[pre]=2;distance[pre]=max_child[pre]+1;pq.push({distance[pre],pre});}}});}int a=min(red[0],red[1]),c=max(red[0],red[1]),start=encode(black,pair_id[a][c],0);if(!outcome[start])cout<<"Tie\n";else if(outcome[start]==1)cout<<"Red "<<distance[start]<<'\n';else cout<<"Black "<<distance[start]<<'\n';}}

+ 6 - 0
参考实现/12-历年真题/洛谷-P9753.cpp

@@ -0,0 +1,6 @@
+#include <cstdint>
+#include <iostream>
+#include <unordered_map>
+#include <vector>
+using namespace std;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;string s;cin>>n>>s;vector<int>parent(1);vector<char>top(1);vector<long long>frequency(1,1);unordered_map<uint64_t,int>id;id.reserve(n*2);int state=0;long long answer=0;for(unsigned char c:s){if(state&&top[state]==c)state=parent[state];else{uint64_t key=(uint64_t(state)<<8)|c;auto it=id.find(key);if(it==id.end()){state=parent.size();id[key]=state;parent.push_back((int)(key>>8));top.push_back(c);frequency.push_back(0);}else state=it->second;}answer+=frequency[state]++;}cout<<answer<<'\n';}

+ 9 - 0
参考实现/12-历年真题/洛谷-P9755.cpp

@@ -0,0 +1,9 @@
+#include <algorithm>
+#include <cstdint>
+#include <iostream>
+#include <queue>
+#include <vector>
+using namespace std;using i128=__int128_t;
+int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;vector<long long>a(n),b(n),c(n);for(int i=0;i<n;++i)cin>>a[i]>>b[i]>>c[i];vector<vector<int>>children(n);vector<int>parent(n,-1);for(int i=1,u,v;i<n;++i){cin>>u>>v;--u;--v;children[u].push_back(v);children[v].push_back(u);}vector<int>order{0};for(size_t i=0;i<order.size();++i){int u=order[i];for(int v:children[u])if(v!=parent[u])parent[v]=u,order.push_back(v);}
+auto growth=[&](int i,long long start,long long finish)->i128{if(start>finish)return 0;i128 count=finish-start+1;if(c[i]>=0)return count*b[i]+(i128)c[i]*(start+finish)*count/2;long long z=(b[i]-1)/(-c[i]);long long high=min(finish,z);i128 sum=0;if(high>=start){i128 cnt=high-start+1;sum=cnt*b[i]+(i128)c[i]*(start+high)*cnt/2;}long long ones=finish-max(high,start-1);return sum+ones;};
+auto feasible=[&](long long days){if(days<n)return false;vector<long long>deadline(n);for(int i=0;i<n;++i){if(growth(i,1,days)<a[i])return false;long long lo=1,hi=days;while(lo<hi){long long mid=(lo+hi+1)/2;if(growth(i,mid,days)>=a[i])lo=mid;else hi=mid-1;}deadline[i]=lo;}vector<int>remaining(n);priority_queue<pair<long long,int>>heap;for(int u=0;u<n;++u){for(int v:children[u])if(parent[v]==u)++remaining[u];if(remaining[u]==0)heap.push({deadline[u],u});}for(int time=n;time>=1;--time){if(heap.empty())return false;auto[ddl,u]=heap.top();heap.pop();if(ddl<time)return false;int p=parent[u];if(p>=0&&--remaining[p]==0)heap.push({deadline[p],p});}return true;};long long lo=n,hi=1000000000LL;while(lo<hi){long long mid=(lo+hi)/2;if(feasible(mid))hi=mid;else lo=mid+1;}cout<<lo<<'\n';}

+ 60 - 0
课程/00-CF2400-2700高阶扩展路线.md

@@ -0,0 +1,60 @@
+# CF 2400–2700 高阶扩展路线
+
+## 扩展口径
+
+“每个课程”按 `主题.md` 的 11 个算法大主题计算;“历年真题”保持中国竞赛真题体系,不用国际平台替代。每个主题以 3 道 Codeforces 2400–2700 或思维强度相当的 AtCoder Grand Contest 题为主,只有转化彼此独立时才增至 4 道。已有详细讲解的题可计入。AGC 只在转化更典型时替换同质 CF 题,不作为降低难度或凑数量的来源。
+
+高阶题不按“用了更复杂的数据结构”入选。若去掉模板名后只剩常规分层图、常规矩阵 Lazy 或直接 CRT,则降为练习;主池优先保留需要改变对象、补图/对偶、隐式图、参数化、状态压缩或反向建模的题。
+
+每道扩展题正文必须按以下考虑链展开:
+
+1. 数据范围允许/排除哪些复杂度;
+2. 最自然的两种尝试及最小反例或瓶颈;
+3. 第一个改变模型的观察;
+4. 状态、图、代数对象或数据结构的形式化;
+5. 从朴素到目标复杂度的演化;
+6. 正确性的合法性、完备性、最优性/计数不重证明;
+7. 实现边界与去掉关键条件后的失效点;
+8. 类 Python 核心伪代码和独立 C++17 附件。
+
+## 题目矩阵
+
+| 主题 | VJudge 查询 | 难度 | 核心转化 |
+|---|---|---:|---|
+| 欧拉路径 | CodeForces-508D | 2500 | 固定窗口重建 → 后缀点、窗口边、欧拉路径 |
+| 欧拉路径 | CodeForces-547D | 2600 | 坐标奇偶约束 → 边二染/欧拉定向 |
+| 欧拉路径 | CodeForces-527E | 2600 | 奇度与边数奇偶补边 → 欧拉回路交替定向 |
+| 欧拉路径 | CodeForces-1361C | 2500 | 二进制答案单调性 → 掩码点上的欧拉回路 |
+| 强/双连通 | CodeForces-962F | 2400 | “恰属一个环” → 点双块边数等于点数 |
+| 强/双连通 | CodeForces-467D | 2400 | 单词替换闭包 → SCC 缩点 DAG 反向 DP |
+| 强/双连通 | CodeForces-1344C | 2600 | 量词可达条件 → SCC 与缩点偏序结构 |
+| Bitset/位并行 | CodeForces-1097F | 2500 | gcd 多重集 → 整除 zeta 坐标上的 AND/XOR |
+| Bitset/位并行 | CodeForces-986C | 2500 | AND 为 0 → 补集子掩码图上的隐式遍历 |
+| Bitset/位并行 | CodeForces-1523D | 2400 | 高维公共 1 → 随机抽行与子集 DP |
+| KMP/Manacher | CodeForces-825F | 2400 | 子串压缩 → KMP 周期代价 + 区间 DP |
+| KMP/Manacher | CodeForces-1827C | 2600 | 回文后缀限制 → Manacher/哈希与 DP 跳转 |
+| KMP/Manacher | CodeForces-955D | 2600 | 模式拆成两段 → 正反前缀匹配拼接 |
+| 最短路 | CodeForces-1340C | 2400 | 周期通行规则 → 位置×绿灯时间的 0-1 BFS |
+| 最短路 | CodeForces-1442C | 2400 | 翻转代价指数增长 → 次数优先的分阶段最短路 |
+| 最短路 | CodeForces-1051F | 2400 | 图近似一棵树 → LCA 距离 + 少量特殊源 Dijkstra |
+| 生成树 | CodeForces-125E | 2400 | 指定特殊边数量 → 权值加参数的 WQS/Kruskal |
+| 生成树 | CodeForces-1408E | 2400 | 禁止彩虹环 → 二分关联图上的最大生成森林补集 |
+| 生成树 | CodeForces-1508C | 2500 | 隐式完全图 → 补图连通块与候选边削减 |
+| 二分图 | CodeForces-741C | 2600 | 三连续约束 → 补固定配对边后的偶环二染 |
+| 二分图 | CodeForces-1634E | 2400 | 多重出现公平分配 → 关联二分图欧拉交替 |
+| 二分图 | CodeForces-1009G | 2400 | 字典序贪心可行性 → Hall/最大流动态检查 |
+| Segment/Fenwick | CodeForces-484E | 2500 | 区间连续高值段 → 按阈值持久化版本 |
+| Segment/Fenwick | CodeForces-786C | 2400 | 对所有容量求最少分段 → 大小参数分治计算 |
+| Segment/Fenwick | CodeForces-1439C | 2600 | 单调区间购买 → 最大值剪枝与批量覆盖 |
+| Segment/Fenwick | CodeForces-1172F | 3300(灵活性) | 区间视为函数 → 合成函数摘要而非数值摘要 |
+| 基环树 | CodeForces-835F | 2500 | 基环树直径 → 挂树直径 + 环上单调队列 |
+| 基环树 | CodeForces-1270G | 2700 | 零和子集构造 → 函数图中取一个有向环 |
+| 基环树 | CodeForces-875F | 2500 | 最大权可选边 → 伪森林独立性上的 Kruskal 贪心 |
+| 高斯/CRT | CodeForces-724G | 2600 | 图上 XOR 路径全集 → 生成树势能与环线性基 |
+| 高斯/CRT | CodeForces-906D | 2700 | 非互质幂塔取模 → Euler 链与“大数标记” |
+| 高斯/CRT | CodeForces-959F | 2400 | 前缀 XOR 表示方案数 → 增量线性基与自由维数 |
+| 平衡树/序列结构 | CodeForces-455D | 2700 | 在线循环移位与频次 → 分块/隐式树结构选择 |
+| 平衡树/序列结构 | CodeForces-702F | 2800(灵活性) | 购买过程按能力分组 → 带 Lazy 的按值 Treap |
+| 平衡树/序列结构 | CodeForces-896C | 2600 | 随机区间操作 → 有序区间树的 split/assign |
+
+其中平衡树组会明确比较 FHQ/Splay、分块、ODT、线段树等接口:重点不是强迫所有题使用平衡树,而是学习从操作集合判断哪种动态序列结构真正合适。

+ 99 - 0
课程/00-课程使用说明.md

@@ -0,0 +1,99 @@
+# 课程使用说明:把例题读成一节课
+
+## 本节目标
+
+读完后,你应能选择适合自己的阅读路线,知道每个折叠区何时展开,并能在不提交每一道课内题的情况下提炼可迁移的算法能力。
+
+## 前置知识与课前自测
+
+前置只需要 C++ 基础、常见 STL 和基础复杂度分析。先回答:
+
+1. 看到 $n=2\times 10^5$,为什么通常要先排除 $O(n^2)$?“常数小”能否挽救它?
+2. 一份题解说“用 Tarjan”时,你还需要追问哪些正确性和实现问题?
+3. 如果读懂了代码却说不出算法在什么条件下失效,算不算掌握?
+
+<details>
+<summary>展开自测参考</summary>
+
+1. $O(n^2)$ 约为 $4\times 10^{10}$ 次基本操作,远超常规时限;只有证明实际访问量更小,才可改变判断。
+2. 至少要问:维护什么状态和不变量、何时入栈/出栈、边的分类、重边与自环、递归深度、复杂度。
+3. 不算。能说明适用条件、最小反例和替代方案,才说明掌握的是模型而不是代码形状。
+
+</details>
+
+## 两条阅读路线
+
+### 尝试路线
+
+适合有完整训练时间时:读题后先只看 Hint 1;卡住 15–25 分钟再逐级展开。写完后必须对照 Editorial 的观察链和证明,而不是只检查代码是否相似。
+
+### 直接学习路线
+
+适合“今天不做这题,但要获得尽可能大收益”时。每道课内题按下面顺序读:
+
+1. **约束翻译**:先把数据范围变成可接受复杂度候选。
+2. **模型信号**:圈出决定建模的动词、对象和不变量。
+3. **错误路线**:看一个最小反例,明确常见直觉错在哪里。
+4. **Observations**:逐条确认每个观察究竟删掉了哪些状态或转移。
+5. **Editorial 与证明**:先复述算法,再检查合法性、完备性和终止结论。
+6. **代码走读**:给每个数组写一句语义;模拟一个正常样例和一个边界样例。
+7. **反事实变化**:修改一个条件,判断原算法哪里先失效。
+
+这条路线不要求提交,但要求留下三行复盘:识别信号、核心不变量、最容易写错的一行。
+
+## 例题在课程中的分工
+
+- **模型建立题**:通常为 CodeForces 1600–2000 或等价难度,负责把定义变成算法。
+- **组合迁移题**:通常为 CodeForces 2000–2500,要求把本节技巧与已有工具组合。
+- **灵活性实验室**:全课程每 2–3 个大主题安排一道,允许达到 2800+,也允许只与当前主题部分相关;重点是构造、交互、反向思考或异常建模,不作为后续课程的硬前置。
+- **课后训练题**:用于独立提交。若没有完整 Editorial,就不会冒充正式例题。
+
+## 正式例题的阅读结构
+
+从本批课程起,正式例题不在正文铺开完整 C++。每题按以下顺序组织:
+
+1. **Observations**:至少说明数据范围排除了什么、朴素路线卡在哪里、哪条新观察真正改变状态数或复杂度。
+2. **Editorial**:从对象与关系的建模开始,逐步推出算法;不能用“套模板”替代推导。
+3. **正确性证明**:分别证明每步合法、不会漏解/重复、终止答案达到目标;最优化题还要写出下界或交换论证。
+4. **复杂度与适用边界**:把复杂度代回本题范围,并给出至少一个去掉关键条件后会失效的情形。
+5. **类 Python 核心伪代码**:只保留决定算法结构的状态和转移,隐藏 C++ 容器噪声。
+6. **参考实现附件**:完整 GNU C++17 放在仓库根目录 `参考实现/`,讲义用链接引用;附件仍参与统一编译和测试。
+
+若只阅读不提交,至少应能在看附件前根据伪代码复述完整数据流。
+
+## 如何使用 Hint
+
+每级 Hint 必须改变你能做的事:
+
+- Hint 1 只指出模型识别方向;
+- Hint 2 给出关键性质,但保留算法组织;
+- Hint 3 给出算法骨架;
+- Hint 4 才触及实现中的下标、状态或边界。
+
+若相邻两级只是换句话说,应视为文档质量问题。
+
+## 代码、测试与评测声明
+
+所有参考实现以 GNU C++17 为准。课程中的“已验证”分为三层:
+
+本查看器中的多行展示公式统一使用独占行的双美元符号作为起止定界符。
+
+1. **编译验证**:通过 `-Wall -Wextra`,只说明语法、类型和链接成立。
+2. **本地行为验证**:通过来源样例或随机对拍,说明覆盖范围内的行为一致。
+3. **在线评测**:只有确实提交并获得记录时才会声明;本课程默认不虚构此层。
+
+交互题没有普通标准输入输出。课程会提供最小模拟器检查协议、查询次数与答案恢复,但这仍不等价于原平台在线通过。
+
+## 总结与自检
+
+完成任一章节后,尝试脱离文档回答:
+
+1. 这个算法解决的瓶颈是什么?
+2. 它依赖的关键条件是什么?去掉该条件的最小反例是什么?
+3. 正确性证明的核心不变量是什么?
+4. 数据范围为何允许该复杂度?
+5. 如果明天忘了模板,能否从定义重新推导出主要步骤?
+
+## 课后训练建议
+
+模型建立题建议独立实现;组合迁移题至少口述完整算法后再看代码;灵活性题先画状态或构造小例,30 分钟没有新观察再展开下一层 Hint。复盘时优先记录“我为何没识别出来”,而不是抄一遍模板。

Деякі файли не було показано, через те що забагато файлів було змінено