#求区间和(Java实现)题目:
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。
输入格式
第一行包含两个整数 n 和 m。
接下来 n 行,每行包含两个整数 x 和 c。
再接下来 m 行,每行包含两个整数 l 和 r。
输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。
数据范围
−10^ 9≤ x ≤ 10^ 9,
1≤n,m≤10^5,
−10^ 9≤ l ≤ r ≤ 10^ 9,
−10000≤c≤10000
##解题思维:
此题要运用离散化思维,将x,l,r各下标离散化,因为其本来的数轴是无限长的,不可能设置那么长的一个数组来存储所有数据,但n,m都是大于1小于10^ 5的,所以下标个数最多有3*10^5,可以用一个数组alls存储所有离散化后的坐标。
所以此题总共可以分为五个步骤:
1.输入数据n,m,确定操作和询问的次数
2.输入x,c并添加到数组add中;输入l,r并添加到数组query中;同时把x,l,r存入数组alls离散化
3.将alls数组进行排序(因为要进行二分查找,排序后才有单调性)和去重(alls数组存放的数是数轴上的下标)
4.利用find()函数二分查找离散化后的x对应的下标,并遍历add数组执行操作一
5.再查找离散化后的l,r对应的下标,再遍历query数组通过前缀和计算出l到r之间的数的和,执行查询二
###具体实现代码如下:
package lisanhua;
import java.util.*;
public class qujianhe {
final static int N = 300010;
static int n, m;
static int[] a = new int[N];
static int[] s = new int[N];
static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
n = sc.nextInt();
m = sc.nextInt();
List<Integer> alls = new ArrayList<>(); //序列化数组,存x,l,r的下标并进行序列化
List<pairs> add = new ArrayList<>();
List<pairs> query = new ArrayList<>();
//输入操作数x,c并将x,c打包存入add数组;将x存入离散化序列alls
for(int i = 0; i < n; i ++){
int x = sc.nextInt();
int c = sc.nextInt();
add.add(new pairs(x, c));
alls.add(x);
}
//输入操作数l,r并将l,r打包存入query数组;并将l,r存入离散化序列alls
for(int i = 0; i < m; i ++){
int l = sc.nextInt();
int r = sc.nextInt();
query.add(new pairs(l, r));
alls.add(l);
alls.add(r);
}
//排序和去重
Collections.sort(alls);
alls = removeDuplicate(alls); //要去重是因为x和l,r可能一样(即是同一个点),x和x本身也可能会重复在一个点上加c
//alls数组内存放的是数轴上的下标,所以alls数组内重复的数表示的都是同一个点
//第一组操作
for(pairs item:add){ //for each循环中item类型是和pairs一致的
int index = find(item.first,alls);
a[index] += item.second;
}
//a数组前缀和
for(int i = 1; i <= alls.size(); i ++){
s[i] = s[i - 1] + a[i];
}
//第二组操作
for(pairs item:query){
int l = find(item.first, alls);
int r = find(item.second, alls);
System.out.println(s[r] - s[l - 1]);
}
}
//去重操作
static List removeDuplicate(List<Integer> list) {
List<Integer> temp = new ArrayList<>();
temp.add(list.get(0));
for(int i = 1; i < list.size(); i ++){
if(!list.get(i).equals(list.get(i - 1))) temp.add(list.get(i));
}
list.clear();
list.addAll(temp);
return list;
}
//查询离散化后的数组下标
static int find(int x,List<Integer> list){
int l = 0,r = list.size() - 1;
while(l < r){
int mid = l + r >> 1;
if(list.get(mid) >= x) r = mid;
else l = mid + 1;
}
return l + 1; //考虑前缀和从1开始
}
}
//pairs类将x,c和l,r打包一起存储
class pairs{
int first,second;
public pairs(int first, int second){
this.first = first;
this.second = second;
}
}