U410974 区间和

题目描述

假定有一个无限长的数轴,数轴上每个坐标上的数都是 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])

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值