首先进行问题分析
看到执行n次在某位置x上加上c,并且还询问m次给定区间的和这种问题。第一反应就是这是道考察前缀和的题目。
static class Pair{
int x;
int c;
Pair(int x , int c){
this.x = x;
this.c = c;
}
}
static class Range{
int l;
int r;
Range(int l , int r){
this.l = l;
this. r = r;
}
}
(2)创建一个存储Pair的集合和一个存储Range的集合以及一个存储x坐标值的集合
//创建一个集合存储Pair
List list = new ArrayList<>();
//存储x的值,因为x是坐标轴上的值非常大,所以要对其进行系列化
Set points = new TreeSet<>();
List ranges = new ArrayList<>();
(3)分别填充三个集合
首先我们可以在控制台输入对应的修改次数(n)和查询次数(m)
Scanner scanner = new Scanner(System.in);
int m,n;//n次修改,m次查询
System.out.println("请以此输入m,n");
m = scanner.nextInt();
n = scanner.nextInt();
接下来填充集合
//输入n次修改操作,(将位置为x的值加c)
for (int i = 0; i < n; i++) {
int x = scanner.nextInt();
int c = scanner.nextInt();
list.add(new Pair(x,c));
points.add(x);
}
//进行m次查询操作
for (int i = 0; i < m; i++) {
int l = scanner.nextInt();
int r = scanner.nextInt();
ranges.add(new Range(l,r));
points.add(l);
points.add(r);
}
//排序(离散化的数组)
int[] discretization = points.stream().sorted().mapToInt(Integer::valueOf).toArray();
但是目前为止我们集合中存放的并不是值, 而是坐标位置x , 所以我们还要创建一个数组来存储
int []c = new int[discretization.length];
//接下来填充数组c
list.stream().forEach(list -> {
int x = list.x;
int v = list.c;
int index = BinnearySearch(x);
c[index] += v;
});
上述代码的解读如下:
首先创建一个长度和discretization[n]数组一样的数组 , 再对存储Pair的数组中循环 , 拿出其中的x和对应的值c , 然后利用二分查找法将x在discretization[n]数组中的索引拿出来 , 填充到对应数组c[]的索引的地方 , 找到要填充的c的索引后, 对其进行操作 , 也就是c[index] += v;
二分查找法代码如下:
//二分查找法
public int BinnearySearch(int x){
int l = 0;
int r = discretization.length-1;
while (l<=r){
int mid = l+(r-l)/2;
if(discretization[mid] == x){
return mid;
}else if(discretization[mid] > x){
r = mid-1;
}else {
l = mid+1;
}
}
return -1;
}
(6) 创建一个sum数组 , 用来存储c中前i项的值的和
//创建一个sum数组
sum = new int[c.length+1];
for (int i = 1; i < sum.length; i++) {
sum[i] = sum[i-1] + c[i-1];
}
(7)用Range数组中的l和r分别对应的sum中的值相减就是l和r中间值的和
ranges.stream().forEach(range ->{
int lrange = range.l;
int rrange = range.r;
System.out.println(sum[rrange+1]-sum[lrange]);
});