Skip to content

使用约定与迁移

源码、头文件路径和网页分类采用同一套目录:

目录 内容
noya/head.hpp 高频使用的公共入口,保留简短 include
noya/ds/ 数据结构
noya/graph/ 图与树算法
noya/string/ 字符串
noya/math/ 数论、代数、多项式
noya/geometry/ 计算几何
noya/dp/ 动态规划
noya/optimization/ 优化与搜索
noya/utility/ 调试、I/O、随机工具

写题仍可用 #include "noya/head.hpp";具体模板例如 #include "noya/ds/sparse_table.hpp"。除公共入口外,旧的平铺路径不再保留; 仓库内测试、验证程序和展开工具已同步迁移。网站从目录发现分类,新增头文件 仍需写明复杂度、前置条件、中文用途,并补充对应的验证用例。

写题与预编译

保留源码开头的 #include "noya/head.hpp",方便普通编译和展开提交。 Linux/macOS 安装 Python 3 与 GCC/Clang 后,可以从题目目录直接编译:

bash ~/libra/compile.sh main.cpp -o main -- -O2
CXX=clang++ bash ~/libra/compile.sh main.cpp -o main -- -O2
# 可选:在同一工作目录提前构建同样选项的缓存
bash ~/libra/precompile.sh -- -O2
# 使用提交模式编译,关闭默认 local 调试宏
bash ~/libra/compile.sh main.cpp -o main --submission -- -O2

第一次自动构建 PCH,之后复用;编译器、选项、模式或依赖变化会选择新的缓存。 缓存位于库内 .cache/pch/,不会在源码旁生成 .gch。 默认选项来自 compile_flags.txt,额外编译选项放在 -- 后面; 配置文件的相对 include 路径基于库目录,命令行相对路径基于当前题目目录。

这个入口会在源码之前载入公共头。影响公共头的宏(例如 local、NDEBUG) 必须通过 -D/-U 设置,不要依赖源码中 include 前的宏定义。 --submission 是本地编译模式,单文件提交仍使用展开器。 普通编译命令不会自动使用这里的独立缓存;使用 compile.sh,或在自己的 CMake 目标上调用 target_precompile_headers。详细缓存说明见仓库 tools/README.md。

Monoid 与 build

build 是正常的重建入口,构造函数使用同一套实现。Monoid 统一提供 value_type、unit()、op(a, b)。op 必须满足结合律,unit() 是双侧单位元; 普通 sparse table 还要求幂等性。运算须保持从左到右的顺序,不要求交换律。

#include "noya/ds/sparse_table.hpp"
#include <algorithm>
#include <limits>
#include <vector>

struct minimum {
  using value_type = int;
  static int unit() { return std::numeric_limits<int>::max(); }
  static int op(int a, int b) { return std::min(a, b); }
};

int main() {
  std::vector<int> values{5, 2, 7, 1};
  noya::sparse_table<minimum> table(values);
  int x = table.prod(1, 4); // [1,4),得到 1
  table.build(std::vector<int>{8, 3});
  int y = table.get(0);    // 8
  table.build(4, [](int i) { return i * i; });
  return x + y == 9 ? 0 : 1;
}

sparse_table、disjoint_sparse_table、segtree、lazy_segtree 共用数组构造、 build(values)、build(n, generator)、get(i)、prod(l,r)、all_prod()、 size()、empty() 约定。默认构造为空;空区间返回 unit()。 lazy_segtree<Monoid, Action> 的 Action 仍需提供映射及复合操作。

场景 类型 构建 区间查询 更新
静态幂等运算,如 min/max/gcd sparse_table<Monoid> O(n log n) O(1) 重建
静态一般结合运算 disjoint_sparse_table<Monoid> O(n log n) O(1) 重建
单点修改 segtree<Monoid> O(n) O(log n) O(log n)
区间映射 lazy_segtree<Monoid, Action> O(n) O(log n) O(log n)
队尾加入、队首删除 swag<Monoid> O(n) 整队 O(1) 均摊 O(1)

复杂度按值类型和 op/映射为 O(1) 计;例如字符串拼接的实际代价取决于字符串长度。 SWAG 使用 push_back、pop_front、all_prod,也支持数组构造、build 和 clear。 旧的 sparse_table<Value, op, identity> 与 swag<Value, op, identity_function> 改为 Monoid 类型接口。

容器拥有自己的值,不保存调用者数组的引用。静态表可用 table.build(std::move(values)) 接管原数组存储,调用后不要依赖原数组内容。 线段树的生成器版本直接填充叶子,不构造中间数组。静态表重建复用各层容量并按下标写入; 不使用 clear 破坏内层缓冲区,也不把 reserve + push_back 当成通用优化。 Monoid 和树查询均在编译期分派,没有虚函数或 std::function 调用。

树接口分层

根深度统一为 0,根父亲为 -1,子树区间为 [l,r)。

需求 类型 构建 查询 存储
父亲、深度、DFS 序、子树区间 tree_preprocessing O(n) O(1) 五个线性数组
高频 LCA 与距离 fastlca O(n log n) O(1) 基础数组与单整数 RMQ 表
路径拆分、向上跳、路径第 k 点 hld O(n) O(log n) 基础数组、重儿子和链顶

三者共用迭代遍历;HLD 不保留邻接表副本,RMQ LCA 不建立额外倍增表。 通用的祖先判断、换根 LCA、路径相交等由编译期分派共用。 build_virtual_tree(tree, vertices) 接受任一查询实现的 const 引用, 复杂度为 O(k log k + k × LCA 查询耗时),不会复制底层树。

fastlca(graph, root) 根据边类型识别无权/整数权树,不再接收权重开关。 有权根距离和查询结果须能用 int64_t 表示。 fastlca 原来的 kth_ancestor、kth_on_path 改用 HLD; HLD 原来的 get_kth_ancestor、get_kth_node_on_path 统一为 kth_ancestor、kth_on_path。重建为空树会清除旧状态。

几何覆盖

原有模块包括二维基本谓词、凸包、半平面交、最近/最远点对、最小覆盖圆、圆交点与切线、 Minkowski 和、矩形面积并、凸层、三角形计数和欧氏最小生成树。 补充的常用接口如下:

头文件 接口与复杂度
geometry_distance.hpp 投影、对称点、点到直线/线段、线段间距离,O(1)
convex_polygon.hpp O(n) 规范化,O(log n) 点定位;O(n) 裁剪和重心
circle_polygon_area.hpp 两圆交面积 O(1),圆与多边形交面积 O(n)
geometry_3d.hpp 三维向量、混合积、点线面距离、平面投影、线面交、四面体体积,O(1)

点定位沿用 -1 外部、0 边界、1 内部。直线和三维平面的退化结果使用 std::optional;零长线段按点处理;零面积多边形没有面积重心。 原有 point<T> 的整数点积、叉积及方向判断在 T 内计算,调用者须保证中间结果不溢出, 必要时用 point<__int128>。浮点距离和面积接口使用 long double;容差含义及输入 前置条件以各函数注释为准,并非任意量级下的精确几何。

仍可按题目需求补充的方向是三维凸包、多边形布尔运算、圆面积并,以及独立的 Delaunay/Voronoi 接口。这些没有以未验证的占位实现加入本库。

展开器

Python/Sublime 与 VS Code 实现使用同一组语义测试:

  • 支持单行字面量 quoted include、子目录、相对依赖和 #pragma once。
  • 提交输出删除头文件宏守卫和 #pragma once,并对受保护的重复依赖去重。
  • 保留 #if defined(local) 等功能条件;跨条件分支的重复依赖按实际包含条件处理,不生成头文件守卫。
  • 系统 include 保持原位置;条件分支、宏开关、重复无守卫包含和 #undef 后重包含交给编译器处理。
  • 有守卫的循环依赖可展开;活动的无守卫循环产生编译错误,避免无限递归。

宏生成的 include 和系统头不进行本地展开。Python 配置中的相对库路径按配置文件目录解析, 不依赖当前终端目录。VS Code 多选复制按文档换行风格连接。 上面的多选行为仅用于显式展开命令;普通 Cmd/Ctrl+C 与 Sublime 适配层一致, 仅展开单个非空 C++ 选区中的真实库 include。空选区、多选、普通文本、注释和字符串 使用原生复制;展开保留选区空行、换行风格和末尾换行。 若控制重复包含的条件宏中途变化,且清理守卫需要其旧值,展开会报错,普通复制回退为原生复制。