[ACW]802区间和
tips:
1.离散化,就是把无限空间中有限个体(稀疏)映射到有限空间中去。
2.值域范围大,个数少,有的题目要以这些值为下标来做,太大无法保存对应的属性。
3.整数,保序离散。
4.相对关系
5.映射到排序后对应的位置(即下标)
5.上一个学的算法是trie树(要温习形成长久记忆)
//要学习的编程技巧
/*
把操作给存起来,如插入,查询
有重新组织输入流程的感觉,代码设计架构师?
*/
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int ,int > PII;//每个操作是两个数
const int N=300010;
int n,m;
int a[N],s[N];//a是我们存的数,s是前缀和
//a[x]x是离散化映射的位置
vector<int> alls;//存我们要离散化的值
//插入操作用vector pair 来存
vector<PII> add,query;
//求x值离散化后的结果,find用来离散化
int find(int x){
int l=0,r=alls.size()-1;
while(l < r){
int mid = l+r >>1;
if(alls[mid] >= x) r=mid;
else l=mid+1;
}
return r+1;//映射到从一开始,前缀和从一开始比较好做,比较好处理边界
}
//先把所有需要操作的数读进来,把所有用到的位置离散化(题目中语言用的是位置)
int main(){
cin>>n>>m;
for(int i=0;i<n;i++){
int x, c;
cin >> x >> c;
add.push_back({x,c});
alls.push_back(x);
}
for(int i=0;i<m;i++){
int l,r;
cin >> l >> r;
query.push_back({l,r});
//把左右区间加到待离散化的数组中去
alls.push_back(l);
alls.push_back(r);
}
//去重
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
//处理插入
for(auto item : add){
int x = find(item.first);
a[x]+=item.second;
}
//预处理前缀和
for(int i=1; i<= alls.size(); i++){
s[i]=s[i-1]+a[i];
}
//处理询问
for(auto item : query){
int l=find(item.first),r=find(item.second);
cout << s[r] -s[l -1 ]<< endl;
}
return 0;
}
3. 离散化
vector<int> alls; // 存储所有待离散化的值
sort(alls.begin(), alls.end()); // 将所有值排序
alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 去掉重复元素
// 二分求出x对应的离散化的值
int find(int x)
{
int l = 0, r = alls.size() - 1;
while (l < r)
{
int mid = l + r >> 1;
if (alls[mid] >= x) r = mid;
else l = mid + 1;
}
return r + 1;
}
好的参考链接:
https://baike.baidu.com/item/%E7%A6%BB%E6%95%A3%E5%8C%96/10501557?fr=aladdin
https://www.cnblogs.com/sun-of-Ice/p/9419857.html
https://blog.csdn.net/weixin_43061009/article/details/82083983
ps:
每天都要在自己想学的东西上投入时间,慢慢来;
时间不会因为自己的懈怠而静止;
实际行动才能产生改变。