离散化
离散化是一种常用的处理方法,用于将具有一定范围的数值映射到一个连续的区间内,从而方便进行处理。
具体步骤如下:
- 将所有需要离散化的数值(这里是横坐标)收集到一个列表中。
- 对列表进行排序,并去重,得到离散化后的数值集合。
- 对于原始数值,使用二分查找或其他方法,找到其在离散化后的数值集合中的位置。
java
private static int find(List<Integer> alls, int x) {
int l = 0, r = alls.size() - 1;
while (l < r) {
int mid = l + r >> 1;
if (alls.get(mid) >= x) r = mid;
else l = mid + 1;
}
return r + 1; // 返回元素 x 在列表中的位置(从 1 开始)
}
题目
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。
输入格式
第一行包含两个整数 n 和 m
接下来 n 行,每行包含两个整数 x 和 c
再接下来 m 行,每行包含两个整数 l 和 r
输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。
数据范围
−109≤x≤109 1≤n,m≤105 −109≤l≤r≤109
−10000≤c≤10000
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
代码
- 读取输入的插入操作和查询操作,将它们分别存储在 add 和 query 列表中。
- 将所有插入操作和查询操作中的横坐标提取出来,存储在 alls 列表中,并进行去重。
- 对于插入操作,根据横坐标找到在 alls 列表中的位置,将对应位置的值更新为插入操作的值。
- 预处理前缀和数组 s,s[i] 表示前 i 个横坐标位置的累计值。
- 对于查询操作,根据查询操作的横坐标范围,找到对应在 alls 列表中的位置,利用前缀和数组 s 计算结果并输出。
java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
public class Main {
static class Pair {
int x, y;
Pair(int x, int y) {
this.x = x;
this.y = y;
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt(); // 插入操作的数量
int m = scanner.nextInt(); // 查询操作的数量
List<Integer> alls = new ArrayList<>(); // 存储所有的横坐标
List<Pair> add = new ArrayList<>(); // 存储插入操作
List<Pair> query = new ArrayList<>(); // 存储查询操作
// 读取插入操作
for (int i = 0; i < n; i++) {
int x = scanner.nextInt();
int c = scanner.nextInt();
add.add(new Pair(x, c));
alls.add(x);
}
// 读取查询操作
for (int i = 0; i < m; i++) {
int l = scanner.nextInt();
int r = scanner.nextInt();
query.add(new Pair(l, r));
alls.add(l);
alls.add(r);
}
// 去重
Collections.sort(alls);
List<Integer> uniqueAlls = new ArrayList<>(alls);
alls.clear();
alls.addAll(uniqueAlls);
// 处理插入操作
int[] a = new int[alls.size() + 1];
for (Pair item : add) {
int x = find(alls, item.x);
a[x] += item.y;
}
// 预处理前缀和
int[] s = new int[alls.size() + 1];
for (int i = 1; i <= alls.size(); i++) s[i] = s[i - 1] + a[i];
// 处理查询操作
for (Pair item : query) {
int l = find(alls, item.x);
int r = find(alls, item.y);
System.out.println(s[r] - s[l - 1]); // 输出查询结果
}
}
// 在列表 alls 中查找元素 x 的位置
private static int find(List<Integer> alls, int x) {
int l = 0, r = alls.size() - 1;
while (l < r) {
int mid = l + r >> 1;
if (alls.get(mid) >= x) r = mid;
else l = mid + 1;
}
return r + 1; // 返回元素 x 在列表中的位置(从 1 开始)
}
}