本文主要是介绍P5490.扫描线(python),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
这个洛谷怎么对于python不太友好呢,没几次能全过的
本题使用扫描线的模板,首先把所有x坐标排序去重,放进列表X中。把所有横线lines排序。这样把所有矩阵都分成了块。对于每一块,高=lines[i+1]-lines[i],宽就等于在这一块中,每个矩阵的并。
比如说图中,纵坐标在3-5之间,那么高度就是2,其中有两块矩阵并起来,计算并起来的宽度=80-10=70,高×宽就是这一块的面积。
所有块的面积之和就是ans。
class node:def __init__(self, l = None, r = None, cnt = 0, len = 0):self.l = lself.r = rself.cnt = cntself.len = lendef build(idx, l, r):tr[idx] = node(l, r, 0, 0)if l == r: returnmid = l + r >> 1build(2*idx, l, mid)build(2*idx+1, mid+1, r)def dich(num):l, r = 0, length-1while l < r:mid = l + r >> 1if X[mid] < num:l = mid + 1else:r = midreturn ldef pushup(idx):if tr[idx].cnt:tr[idx].len = X[tr[idx].r+1] - X[tr[idx].l]else:try:tr[idx].len = tr[2*idx].len + tr[2*idx+1].lenexcept:tr[idx].len = 0def modify(idx, l, r, tag):if tr[idx].l > r or tr[idx].r < l: returnelif l <= tr[idx].l and tr[idx].r <= r:tr[idx].cnt += tagpushup(idx)returnmodify(2*idx, l, r, tag)modify(2*idx+1, l, r, tag)pushup(idx)n = int(input())
X = [-float('inf')]
lines = []
# tr中存放所有节点的,l, r, cnt覆盖次数, len覆盖长度
tr = [node()]*(8*n)
ans = 0
for i in range(n):x1, y1, x2, y2 = map(int, input().split())X.append(x1)X.append(x2)lines.append([y1, x1, x2, 1])lines.append([y2, x1, x2, -1])
X = sorted(list(set(X)))
length = len(X)
lines.sort()
build(1, 1, length-2)
# 扫描开始
for i in range(len(lines)-1):y, x1, x2, tag = lines[i]l = dich(x1)r = dich(x2)-1modify(1, l, r, tag)ans += tr[1].len*(lines[i+1][0] - lines[i][0])
print(ans)
其中需要注意的是,把X排完序,想要从坐标1开始计算,那在X最前面加一个-inf,保证排序从1开始。
又发现X是离散的,所以需要离散化
这样线段树的就以下标为值,例如根节点就是1-5。那么有人就会问为什么不是1-6呢?
如果是1-6,它的左节点就是1-4,右节点就是5-6,我们发现从4到5,实际上差了20,显然不可行。
我们让右左标偏移。
这样右边的5就代表90,左边的1还是代表10。
这篇关于P5490.扫描线(python)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!