qoj # 9711 K-rectangle

qoj # 9711 K-rectangle

简要题意:

平面上有 \(n\) 个点,保证 \(x\) 单调递增,\(y>0\)

你需要放置一些矩形来覆盖所有点,点在矩形边界也为覆盖。

矩形需要满足底边为 \(x\) 轴,一个矩形的成本为 \(\Delta y*(\Delta x+k)\)

一个矩形的 \(\Delta x\) 可以为 \(0\)

计算覆盖所有点的最小花费。

题解:

根据题意不难直接写出转移方程 \(f_i=\min(f_{j-1}+\max_{j}^{i} y*(x_i-x_j+k))\)

这个式子中最难解决的是 \(\max\) 的这一项 ,直接带着 \(\max\) 优化显然不太行,那我们考虑把所有 \(\max\) 相等的归为一项 \(g(y)\)\(f\)\(g\) 转移。\(g(y)=\min (f_{j-1}-y*x_j)\)\(f_i=\min (y*(x_i+k)+g(y))\)。我们发现 \(g\) 是一个关于 \(y\) 斜率优化的式子,\(f\) 是一个关于 \(g\) 斜率优化的式子。

我们考虑将 \(g,f\) 分开维护,考虑在不断往右扫的过程中 \(g\) 发生的改变。

新增了当前点 \(y_i\) 作为最大值的部分,同时会有一段比 \(y_i\) 小的 \(g\) 消失。

对于第一种操作,我们用单调栈找到以 \(y_i\) 作为最大值的左端点 \(l\),查询 \(y_i\)\([l,i]\) 区间的凸包上的最小值,转移 \(g\) 的凸包我们只需要插入和查询,所以直接用线段树维护就可以解决区间查询。

第二个操作,我们把查询出的值加入转移 \(f\) 的凸包,同时把凸包中 \(y\)\(y_i\) 小的部分弹出(只存在于末尾),同时要要回退在这些点插入时因维护凸包凸性而被弹出的点,然后将当前值正常插入凸包。但对于回退部分我们如果直接采用逐个记录,逐个回退的过程,可能一个点被反复弹出,反复加入,时间复杂度不正确,此时我们发现在维护凸包凸性的弹栈过程中我们我们实际改变的存储位置的值只有一个位置,其他值我们还存储在原数组中,我们只需要覆盖一个位置,同时移动指针即可完成回退,我们弹栈的过程也可以直接用二分找到分界点。

这样就保证了时间复杂度为 \(n\log n\) ,代码细节较多。

posted @ 2025-08-21 08:04  shanganze  阅读(7)  评论(0)    收藏  举报