离散化(整数)

(整数有序)离散化就是将少量较大范围的数值,映射到从0开始的连续的自然数。

注意:

  ①数值中可能含有重复元素,故需要去重;

  ②如何计算出num离散化后的数值 => 二分

 

题目描述

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

 

鉴于数据x的范围十分大,而插入操作次数n以及问询操作次数m相较于x比较小,即插入数据范围较大,但数量比较少,如果直接开大数组计算前缀和比较浪费时间空间,因此使用离散化思想,将所有用到的坐标离散化到自然数1开始的所有自然数中,映射到1开始主要是为了方便计算前缀和。

至于如何查找x映射后的自然数,使用二分查找即可。

 

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N = 300009;
 6 int s[N];
 7 vector<int> alls;
 8 vector <pair<int,int>> add,query;
 9 int n,m;
10 
11 int find(int x)
12 {
13     int l = 0,r = alls.size() - 1;
14     while(l < r)
15     {
16         int mid = l + r >> 1;
17         if(alls[mid] >= x)
18             r = mid;
19         else
20             l = mid + 1;
21     }
22     return r + 1;
23 }
24 
25 int main()
26 {
27     cin >> n >> m;
28     for(int i = 0;i < n;++i)
29     {
30         int x,c;
31         cin >> x >> c;
32         add.push_back({x,c});
33         alls.push_back(x);
34     }
35     for(int i = 0;i < m;++i)
36     {
37         int l,r;
38         cin >> l >> r;
39         query.push_back({l,r});
40         alls.push_back(l);
41         alls.push_back(r);
42     }
43     sort(alls.begin(),alls.end());
44     alls.erase(unique(alls.begin(),alls.end()),alls.end());
45     for(int i = 0;i < add.size();++i)
46         s[find(add[i].first)] += add[i].second;
47     for(int i = 1;i <= alls.size();++i)
48         s[i] += s[i - 1];
49     for(auto& q:query)
50         cout << s[find(q.second)] - s[find(q.first) - 1] << endl;
51     return 0;
52 }

 

posted @ 2021-10-16 23:59  Modest-Hamilton  阅读(237)  评论(0)    收藏  举报