现在,我们首先进行 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 思路:看到这道题想到的肯定是利用前缀和进行计算,但是如果直接使用前缀和的话我们需要开一个数量级为1e9的数组,这显然不太可能,而发现n与m最多就访问1e5次,所以我们用的空间最多数量级也就1e5,所以 n m x 一共用到的空间是3e5就足够了,因此我们就把用到的数都通过离散化映射到小范围中去,再使用前缀和。 那么离散化的方法:首先把所有要离散化的数据都 push_back() 到 all 数组中去,然后先排序,再去重,再利用二分来离散化。 排序:
1 sort(alls.begin(), alls.end());
去重:运用erase,unique来去重(经典方法)
1 alls.erase(unique(alls.begin(), alls.end()), alls.end());
unique的去重原理是将所用不重复的元素放到前边,将重复的元素放到数组后边,最后将迭代器指向最后不重复下标并返回,所以这个操作完美去重。
离散化:即运用二分,也可直接用 low_bound ,把数插入到a数组中去。
二分写法:因为是用到前缀和,所以我们的下标从1开始,返回的是r+1
1 int find(int x) 2 { 3 int l = 0, r = alls.size()-1; 4 while(l < r) 5 { 6 int mid = l+r >> 1; 7 if(alls[mid] >= x) r = mid; //依据的是原先数字在alls数组中的相对位置 8 else l = mid+1; 9 } 10 11 return r+1; 12 }
low_bound() 写法:
1 int find(int x) //lower_bound二分写法 2 { 3 return lower_bound(alls.begin(), alls.end(), x) - alls.begin() + 1; 4 }
总代码
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 5 using namespace std; 6 7 typedef pair<int, int> PII; 8 9 const int N = 300010; 10 int n, m; 11 int a[N], s[N]; //a存放离散化后的序列 12 13 vector<int> alls; //要散化的所有数据 14 vector<PII> add, query; //add是存x+c的 query用来存区间两边 15 16 int find(int x) 17 { 18 int l = 0, r = alls.size()-1; 19 while(l < r) 20 { 21 int mid = l+r >> 1; 22 if(alls[mid] >= x) r = mid; //依据的是原先数字在alls数组中的相对位置 23 else l = mid+1; 24 } 25 26 return r+1; 27 } 28 29 int main() 30 { 31 cin >> n >> m; 32 for(int i = 0; i < n; i++) 33 { 34 int x, c; 35 cin >> x >> c; 36 add.push_back({x, c}); //在某个数上加c 37 38 alls.push_back(x); 39 } 40 41 for(int i = 0; i < m; i++) 42 { 43 int l, r; 44 cin >> l >> r; 45 query.push_back({l, r}); 46 47 alls.push_back(l); 48 alls.push_back(r); 49 } 50 51 //去重 52 sort(alls.begin(), alls.end()); 53 alls.erase(unique(alls.begin(), alls.end()), alls.end()); 54 55 //处理插入 56 for(auto item : add) 57 { 58 int x = find(item.first); 59 a[x] += item.second; 60 } 61 62 //预处理前缀和 63 for(int i = 1; i <= alls.size(); i++) s[i] = s[i-1] + a[i]; 64 65 //处理询问 66 for(auto item : query) 67 { 68 int l = find(item.first), r = find(item.second); 69 cout << s[r] - s[l-1] << endl; 70 } 71 system("pause"); 72 return 0; 73 }
标签:end,int,mid,back,离散,alls 来源: https://www.cnblogs.com/ZhengLijie/p/13335531.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。