离散化
整数离散化特点:值域很大(0-10^9),个数少(0-10^5);将值域为0-10^9的数映射到0-10^5区间
离散化的本质:是建立了一个离散区间到一个连续区间之间的映射关系(value -> index),通过建立新索引,来缩小原区间,使得原来的离散区间可以进行连续区间的一些操作比如二分,前缀和等…
映射
将排序后的数组a映射到一个连续的数组b中
-
- 将数组a排序并去重(离散化之前必须先进行排序和去重)
-
- 如何快速求出a[i]离散化后的值(二分查找)
def unique(arrs):
"""
排序并去重
1. 要么这个数是这个区间的第一个值
2. 要么a[i] != a[i-1]
返回当前区间去重后的最后一个索引值
"""
# 对arrs进行排序
arrs.sort()
# 定义双指针
i = j = 0
while i < len(arrs):
if (not i or arrs[i] != arrs[i-1]):
arrs[j] = arrs[i]
j += 1
i += 1
return j
def find(alls,x):
"""
利用二分快速查询离散化后,x的离散化值
"""
l = 0
r = len(alls) - 1
while l < r:
mid = l + r >> 1
if alls[mid] >= x:r = mid
else:l = mid + 1
return r + 1
def main():
s1 = input().split()
n = int(s1[0])
m = int(s1[1])
add = []
query = []
alls = []
a = [0] * 300000
s = [0] * 300000
for i in range(n):
s2 = input().split()
x = int(s2[0])
val = int(s2[1])
# 将需要add的值添加到add数组中
add.append([x,val])
# 将索引值添加到alls数组中
alls.append(x)
for j in range(m):
s3 = input().split()
l = int(s3[0])
r = int(s3[1])
# 将要查询的索引值添加道query数组中
query.append([l,r])
# 将要查询的区间也添加到alls数组中,统一进行离散化处理
alls.append(l)
alls.append(r)
# 对alls进行排序并去重
alls = alls[:unique(alls)]
for items in add:
# 查询add数组中的所有索引值离散化后对应的索引值
index = find(alls,items[0])
# 并在a数组中将对应索引位置的值赋值
a[index] += items[1]
# 对a数组求前缀和
for k in range(1,len(alls)+1):
s[k] = s[k-1] + a[k]
for items in query:
# 查询询问中的区间的索引值得离散化后的值
l = find(alls,items[0])
r = find(alls,items[1])
# 查询前缀表中的值来计算区间值
print(s[r] - s[l-1])
def find(alls,x):
# 二分查找x对应的离散化后的值
l = 0
r = len(alls) - 1
while l < r:
mid = l + r >> 1
if alls[mid] >= x:r = mid
else:l = mid + 1
return r + 1
def unique(arrs):
"""
排序并去重
1. 要么这个数是这个区间的第一个值
2. 要么a[i] != a[i-1]
"""
# 对arrs进行排序
arrs.sort()
# 定义双指针
i = j = 0
while i < len(arrs):
if (not i or arrs[i] != arrs[i-1]):
arrs[j] = arrs[i]
j += 1
i += 1
return j
main()