题目描述
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c 。
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r ,你需要求出在区间 [l,r] 之间的所有数的和。
输入格式
第一行包含两个整数 n 和 m 。
接下来 n 行,每行包含两个整数 x 和 c 。
再接下来 m 行,每行包含两个整数 l 和 r 。
输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。
输入输出样例
输入 #1复制
3 3 1 2 3 6 7 5 1 3 4 6 7 8
输出 #1复制
8 0 5
说明/提示
−10e9≤x≤10e9
1≤n,m≤10e5
−10e9≤l≤r≤10e9
−10000≤c≤10000
思路:
初看题目,会觉得这个题目是关于求前缀和的,然后看到说明提示时会发现,数的范围很大−10e9≤x≤10e9,−10e9≤l≤r≤10e9,但是数的个数少,1≤n,m≤10e5,相当于是在负这么多到正这么多的数轴上去找1到10e5这么多个数,如果直接按照前缀和进行操作那么会超时,这个时候可以采取离散化的方法,
离散化思路:
1.构造离散化数组(排序,去重)
2. 查找,在离散化数组中找到对应下标的值
代码:
#离散化
#find函数查找,映射后对应的小的数组
def find(x,p):
l=0#这里从0开始,a数组也是从0开始的
r=p
while l<r:
mid = (l + r) // 2
if alls[mid]>=x:
r=mid
else:
l=mid+1
return l+1
n,m=map(int,input().split())
#数组的功能分为两种,存储操作和对应的值
#第一个数组,装所有要离散化的数,alls
#第二个数组,装操作后对应的值a
#第三个数组,运算前缀和s
#存储操作
#第四个数组,存储(x,c)add
#第五个数组,存储(l,r)query
N=30010
alls=[]
a,s=[0]*N,[0]*N#初始化数组
add,query=[],[]
for i in range(n):
x,c=map(int,input().split())
alls.append(x)#离散化x
add.append((x,c))
for i in range(m):
l,r=map(int,input().split())
alls.append(l)#参与题目的数轴上所有下标都要离散
alls.append(r)
query.append((l,r))
#构造离散化数组,排序去重
alls=list(sorted(set(alls)))#set函数变成集合,sorted函数排序,再加上list函数变成列表类型
L=len(alls)
for x,c in add:#映射到小的数轴上,需要查找x对应新的小的数轴上哪里
x2=find(x,L)#通过传入的x值以及边界L找对应的下标,数组本来就是排好序了的从0开始
a[x2]+=c#a数组存储的是进行操作后的一系列数
#进行前缀和运算
for i in range(1,L+1):
s[i]=s[i-1]+a[i]
#处理结果
for l,r in query:
l2=find(l,L)
r2=find(r,L)
print(s[r2]-s[l2-1])