递归式学习
闵可夫斯基和
定义
比较严谨的定义:两个图形 $A, B$ 的闵可夫斯基和 $C = \{a + b |a \in A, b \in B \}$
我的李姐:对于图形 $A$ 中每个点和图形 $B$ 中每个点两两求和( $(x_a, y_a) + (x_b, y_b) = (x_a + x_b, y_a + y_b)$ )
盗张图:
粉色区域是三角形和一个不规则四边形的闵可夫斯基和
有啥用
当然说有用我才来递归式学习的了
一般用在求凸包上,就以我学这个东西的目的为例吧(顺便说说凸包有啥用)
比如,我们维护了区间和,区间最大后缀和,区间最大前缀和,区间最大子段和分别取名叫 $sum, lmx, rmx, mx$
现在我们要区间加 $k$ ,怎么维护?最简单的是 $sum$ 就不管了
较难的是 $lmx, rmx$ ,以 $rmx$ 为例(注意它是区间最大前缀和,取名为 $r$ 只是因为它在右子树),我们要维护函数 $y = pre(x) + k * x$ 的最大值,其中 $pre(x)$ 代表 $[l, x]$ 的和(前缀和);考虑斜率优化,我们将函数化为 $pre(x) = kx + y$ ,就是把 $(x, pre(x))$ 看做是一个个点,把斜率为 $k$ 的直线带入这一个个点中,最大化截距,不难发现这就是在凸包上二分切点,因为此时凸包中的所有点都在直线的一侧,自然是在直线上的点代进去之后截距最大
而最毒瘤的就是 $mx$ 了,仿造上面,写出式子: $y = as(x) + k * x$ ,其中 $as(x)$ 代表长度为 $x$ 的最大子段和,但是,求出 $as(x)$ 是 $n^2$ 的,有救吗?有救
考虑分治,我们关心的就是 $(x, as(x))$ 这个点集构成的凸包,不妨来看看 $mx$ 的推导式(在线段树上用过无数次的那个): mx[l][r] = max(mx[l][mid], mx[mid + 1][r], lmx[l][mid] + r[mid + 1][r])
,发现前两个可以直接递归求 $[l, mid]$ 和 $[mid + 1, r]$ 的凸包解决,麻烦的是最后那个求和的式子,不难发现它代表的是“跨过 $mid$ 的区间”
考虑我们要求的是什么,是 $(x, as(x))$ 的凸包,将,每个跨过 $mid$ 的区间化作一个点 $(x, y)$ , $x$ 代表区间长度, $y$ 代表区间和,就是求这个点集(设为 $C$ )的凸包
点集大小是 $O(n^2)$ 的,当然不能直接求,设点集 $A = \{(x, y) | x \in [l, mid], y = suf(x)\}$ ,其中 $suf(x)$ 表示区间 $[l, mid]$ 的后缀和;再设 $B = \{(x, y) | x \in [mid + 1, r], y = pre(x)\}$ ,其中 $pre(x)$ 表示区间 $[mid + 1, r]$ 的前缀和;那么, $C = \{(x, y) | x = x_A + x_B, y = y_A + y_B\}$ ,这就是闵可夫斯基和呀
而用闵可夫斯基和,我们可以 $O(n)$ 归并出点集 $C$ 的凸包
做法
那怎么合并呢?再看图(回去翻那张)
我们(baidu得)发现发现新的凸包就是原来的两个凸包的边重新极角排序一边,证明?咕咕咕
于是我们得到了一个很有用的结论,求凸包只需要求原来的凸包,然后在一起重新排序就可以了。
但直接重排有点浪费,由于原来两个凸包都已经求好了,于是可以类似归并排序,重新归并一次
代码
例题就不讲了,我要回溯去递归下一条路径了(dfs式学习,艹)
1 | struct Point |
这个板子优点是快,缺点是指针需要人工分配内存