Stern-Brocot 树
基础定义
Stern-Brocot 树是一种维护最简分数的数据结构。
逐层构造
Stern-Brocot 树可以在迭代构造第 \(k\) 阶 Stern-Brocot 序列的过程中得到。
第 \(0\) 阶 Stern-Brocot 序列由两个分数组成:
此处的 \(\frac{1}{0}\) 严格意义上并不算是有理分数,可以理解为表示 \(\infty\) 的最简分数。
在第 \(k\) 阶 Stern-Brocot 序列相邻的两个分数 \(\frac{a}{b}\) 和 \(\frac{c}{d}\) 中间插入 \(\frac{a+c}{b+d}\),就得到第 \(k+1\) 阶 Stern-Brocot 序列。
前几次迭代的结果如下:
将每次迭代中新添加的分数连结成树状结构,就得到了 Stern-Brocot 树。如下图所示(图片来自 OI-wiki):
三元组构造
另一种等价的构造方式是以三元组 \((\frac{0}{1},\frac{1}{1},\frac{1}{0})\) 作为根节点,且在每个节点 \((\frac{a}{b},\frac{p}{q},\frac{c}{d})\) 后都分别添加 \((\frac{a}{b},\frac{a+p}{b+q},\frac{p}{q}),\ (\frac{p}{q},\frac{p+c}{q+d},\frac{c}{d})\) 为左右子节点,就可以构造出整个 Stern-Brocot 树。
Stern-Brocot 树的每个节点记录的三元组中,实际存储的分数是位于三元组中间的分数 \(\frac{p}{q}\),而左右两个分数 \(\frac{a}{b}\) 和 \(\frac{c}{d}\) 是更早就出现过的分数。
性质
-
基本性质:Stern-Brocot 树是分数的二叉搜索树,即树上节点的中序遍历得到的分数序列是递增的。
-
单调性:Stern-Brocot 树中,每一层的分数都是单调递增的。
-
最简性:Stern-Brocot 树构造出来的所有分数都是最简分数。
-
完全性:Stern-Brocot 树能构造出来任意一个正的最简分数。
这些性质的证明略去,可自行搜索。
应用
基础应用
在 Stern-Brocot 树上查找一个确定的分数 \(\frac{p}{q}\)。
sol:
每次暴力往左或右跳的复杂度为 \(O(p+q)\),无法接受。
我们发现,这个方法复杂度高的原因是我们经常会连续往左或往右跳很多步。
考虑优化。观察到一次往左跳再接一次往右跳一定会让分子分母都至少变为原来的两倍,所以“拐弯”的次数是 \(O(\log(p+q))\) 的。
于是现在我们需要快速确定每次拐弯的位置。
假设当前节点为 \((\frac{a}{b},\frac{x}{y},\frac{c}{d})\),如果 \(\frac{x}{y}\le\frac{p}{q}\),那么需要向右递归。设递归次数为 \(t\),则 \(\frac{x+tc}{y+td}\ge\frac{p}{q}\),解这个不等式即可。向左递归同理。
时间复杂度 \(O(\log(p+q))\)。
拓展应用
大部分时候,我们在树上查找的分数其实是不确定的,比如我们需要根据当前分数的值跑一个二分查找的检验算法来决定具体是往左走还是往右走。
这个时候,把刚才通过解方程来确定次数的部分改为二分连续向左或向右的次数 \(t\) 即可。复杂度 \(O(\log^2(p+q))\)。
例题
- Fraction
\(T\) 组数据,给定四个正整数 \(a,b,c,d\),求一个最简分数 \(\frac{p}{q}\) 满足 \(\frac{a}{b}<\frac{p}{q}<\frac{c}{d}\)。
若有多解,输出 \(q\) 最小的一组,若仍有多解,输出 \(p\) 最小的一组。
sol:
Stern-Brocot 树上二分的板子,连续移动次数可以列不等式解出来,复杂度 \(O(T\log a)\)。
- Farey 序列
求分子和分母都 \(\le n\) 的最简真分数组成的序列中第 \(k\) 小的数。
sol:
在 Stern-Brocot 树上二分,剩下的就是类似二分答案地,对于一个分数 \(\frac{x}{y}\),我们需要计算 \(\le\frac{x}{y}\) 的分子和分母都 \(\le n\) 的最简真分数数量,这个数量为:
\(\begin{aligned}&\sum\limits_{i=1}^n\sum\limits_{j=1}^i[\gcd(i,j)=1]\left[\frac{j}{i}\le\frac{x}{y}\right]\\&=\sum\limits_{i=1}^n\sum\limits_{j=1}^i\sum\limits_{d\mid\gcd(i,j)}\mu(d)\left[\frac{j}{i}\le\frac{x}{y}\right]\\&=\sum\limits_{d=1}^n\mu(d)\sum\limits_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum\limits_{j=1}^i\left[\frac{j}{i}\le\frac{x}{y}\right]\\&=\sum\limits_{d=1}^n\mu(d)\sum\limits_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum\limits_{j=1}^i\left[j\le\frac{ix}{y}\right]\\&=\sum\limits_{d=1}^n\mu(d)\sum\limits_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\left\lfloor\frac{ix}{y}\right\rfloor\end{aligned}\)
整除分块,\(\mu\) 的前缀和用杜教筛求,预处理 \(O(n^{\frac{2}{3}})\),单次询问 \(O(1)\)。后面是类欧,对于每个 \(\frac{x}{y}\),需要做 \(O(\sqrt n)\) 次类欧,每次类欧 \(O(\log n)\)。
而 Stern-Brocot 树上二分复杂度为 \(O(\log^2 n)\),所以总复杂度 \(O(n^{\frac{2}{3}}+\sqrt{n}\log^3n)\)。

浙公网安备 33010602011771号