离散化

离散化:

如果数据范围很大,但是分布稀疏,可以考虑离散化做题,就是将在一个大范围里面把所有用到的数据映射到一个小范围里面比如下面的这个题

eg 求区间和:

假定有一个无限长的数轴,数轴上每个坐标上的数都是0。

现在,我们首先进行 n 次操作,每次操作将某一位置x上的数加c。

近下来,进行 m 次询问,每个询问包含两个整数l和r,你需要求出在区间[l, r]之间的所有数的和。

输入格式

第一行包含两个整数n和m。

接下来 n 行,每行包含两个整数x和c。

再接下里 m 行,每行包含两个整数l和r。

输出格式

共m行,每行输出一个询问中所求的区间内数字和。

数据范围

109x109−109≤x≤109,
1n,m1051≤n,m≤105,
109lr109−109≤l≤r≤109,
10000c10000−10000≤c≤10000

输入样例:

3 3
1 2
3 6
7 5
1 3
4 6
7 8

输出样例:

8
0
5

分析:

题目数据范围是 -10^9 --- +10^9,范围很大,但是我们用到的数据只有下标 n,还有下标 m的l 和 r,总共 3e5,所以属于数据稀疏,我们可以把用到的数据都映射到一个连续的小范围里面,比如开一个 3e5 的数组存储 所有用到的下标,那么每一个下标就被映射成了 1 2 3 4 。。。n,我们在对原下标操作时就可以先找到它的映射后的下标,然后对映射后的下标操作,下面是这个题用离散化的解法。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 
 5 using namespace std;
 6 
 7 const int N = 3e5+10;
 8 
 9 vector<pair<int, int> > index_val;//用来保存index下标对应的值
10 vector<pair<int, int> > query;//用来记录每次询问的 l 和 r 的下标
11 vector<int> all;//用来记录所有用到的下标,对这个集合进行排序,去重后,这个集合的下标对应一个用到的下标
12 vector<int> a(N,0), sum(N,0);//a 用来求出在映射后的下标处加上相应的数c,sum用来求出前缀和
13 
14 int n, m;//n次操作,m次询问,那么总共用到的下标个数为 10^5 + 2*10^5
15 
16 int find(int x){
17     int l = 0, r = all.size() - 1;
18     while(l < r){
19         int mid = l + r >> 1;
20         if(all[mid] >= x)r = mid;
21         else l = mid + 1;
22     }
23     //将每个值映射到1 2 3 ...的位置,为了求前缀和方便
24     return l + 1;
25 }
26 
27 int main(){
28     cin >> n >> m;
29     //把每次增加值的位置的下标记录,及其相应的值
30     for(int i = 0;i < n;++ i){
31         int x, c;
32         cin >> x >> c;
33         
34         index_val.push_back({x, c});
35         all.push_back(x);
36     }
37     //把每次询问用到的下标记录
38     for(int i = 0;i < m;++ i){
39         int l, r;
40         cin >> l >> r;
41         
42         query.push_back({l, r});
43         all.push_back(l);
44         all.push_back(r);
45     }
46     //排序,去重进行映射
47     sort(all.begin(),all.end());
48     all.erase(unique(all.begin(),all.end()),all.end());
49     //在映射后的位置上加上相应的值
50     for(auto intex : index_val){
51         int x = find(intex.first);//查找映射后的下标的位置
52         a[x] += intex.second;
53     }
54     //求出前缀和
55     for(int i = 1;i <= all.size();++ i){
56         sum[i] = sum[i-1] + a[i];
57     }
58     //处理每次的询问
59     for(auto intex : query){
60         int l = find(intex.first);
61         int r = find(intex.second);
62         cout << sum[r] - sum[l-1] << endl;
63     }
64     
65     return 0;
66 }
View Code

end

原文地址:https://www.cnblogs.com/sxq-study/p/12079214.html