赞
踩
这个洛谷怎么对于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 = l
- self.r = r
- self.cnt = cnt
- self.len = len
-
- def build(idx, l, r):
- tr[idx] = node(l, r, 0, 0)
- if l == r: return
- mid = l + r >> 1
- build(2*idx, l, mid)
- build(2*idx+1, mid+1, r)
-
- def dich(num):
- l, r = 0, length-1
- while l < r:
- mid = l + r >> 1
- if X[mid] < num:
- l = mid + 1
- else:
- r = mid
- return l
-
-
- def 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].len
- except:
- tr[idx].len = 0
-
-
- def modify(idx, l, r, tag):
- if tr[idx].l > r or tr[idx].r < l: return
- elif l <= tr[idx].l and tr[idx].r <= r:
- tr[idx].cnt += tag
- pushup(idx)
- return
- modify(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)-1
- modify(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。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。