枚举经过产奶点的左边界并收紧上下界,同时单独扫描贴场地左边界的最大空白纵缝。
OJ: luogu
题目 ID: P1578
难度:提高+/省选-
标签:计算几何枚举扫描线python
日期: 2026-07-16 18:25
题意
在矩形场地内放置不含任何产奶点内部的最大轴对齐矩形;点允许位于浴场边界。
思路
最大矩形的左边要么贴场地左边界,要么经过某个产奶点。
贴左边界时,按 x 扫描点并动态维护已进入内部的 y 坐标最大间隙。左边经过点 (left,anchor_y) 时,向右扫描并用遇到的点收紧 lower/upper;同高内部点会把可选纵向区间分成锚点上方或下方两部分。每个新 x 在加入该竖线上的点之前结算面积,因为点可以位于右边界。
Python 知识
bisect维护有序 y 坐标,Counter + heapq维护当前最大纵缝。set去掉重复产奶点,它们不会增加约束。- 算法为
,但内层只做整数比较,适合 。
代码
python
import heapq
import sys
from bisect import bisect_left
from collections import Counter
data = iter(map(int, sys.stdin.buffer.read().split()))
length, width = next(data), next(data)
points = sorted(set((next(data), next(data)) for _ in range(next(data))))
# Rectangles whose left side is the field boundary.
ys = [0, width]
gap_count = Counter({width: 1})
max_gap_heap = [-width]
answer = 0
i = 0
while i < len(points):
x = points[i][0]
while max_gap_heap and not gap_count[-max_gap_heap[0]]:
heapq.heappop(max_gap_heap)
answer = max(answer, x * -max_gap_heap[0])
j = i
while j < len(points) and points[j][0] == x:
if 0 < x < length:
y = points[j][1]
position = bisect_left(ys, y)
if position == len(ys) or ys[position] != y:
low, high = ys[position - 1], ys[position]
gap_count[high - low] -= 1
for gap in (y - low, high - y):
gap_count[gap] += 1
heapq.heappush(max_gap_heap, -gap)
ys.insert(position, y)
j += 1
i = j
while max_gap_heap and not gap_count[-max_gap_heap[0]]:
heapq.heappop(max_gap_heap)
answer = max(answer, length * -max_gap_heap[0])
# Rectangles whose left side passes through a production point.
point_count = len(points)
for left, anchor_y in points:
lower, upper = 0, width
split_at_anchor = False
j = bisect_left(points, (left + 1, -1))
while j < point_count:
x, y = points[j]
if split_at_anchor:
below, above = anchor_y - lower, upper - anchor_y
height = below if below > above else above
else:
height = upper - lower
area = (x - left) * height
if area > answer:
answer = area
if y < anchor_y:
if y > lower:
lower = y
elif y > anchor_y:
if y < upper:
upper = y
else:
split_at_anchor = True
j += 1
if split_at_anchor:
below, above = anchor_y - lower, upper - anchor_y
height = below if below > above else above
else:
height = upper - lower
area = (length - left) * height
if area > answer:
answer = area
print(answer)复杂度
时间复杂度
总结
最大空矩形必有边界贴场地或穿过障碍点,枚举这条支撑边即可收紧另一维。