离散化
❄️⛄️
-
实际上其主要思想是用一个数组来(这里记为
all
)存储大小两个数组之间的映射关系:小的数组的下标和
all
的下标是一一对应的;
大的数组的下标是all
存的值。 -
但是只有
all
数组还是不够的,all
只是把大小数组的映射关系保存下来了,我们还需要一个find()
函数,这样每次我们给它喂一个大数组的下标,它就会吐出来一个小数组的下标,这样就可以通过大数组的下标来访问小数组了。
离散化例题——区间和
假定有一个无限长的数轴,数轴上每个坐标上的数都是0。
现在,我们首先进行 n 次操作,每次操作将某一位置x上的数加c。
近下来,进行 m 次询问,每个询问包含两个整数l和r,你需要求出在区间[l, r]之间的所有数的和。
输入格式
第一行包含两个整数n和m。
接下来 n 行,每行包含两个整数x和c。
再接下里 m 行,每行包含两个整数l和r。
输出格式
共m行,每行输出一个询问中所求的区间内数字和。
数据范围
$ −10^9 ≤x≤ 10^9 $,
$1≤n,m≤10^5$,
$−10^9≤l≤r≤10^9$,
$−10000≤c≤10000$
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
代码及详细注释
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define f first
#define s second
typedef pair<int,int> PII;
const int N=3e5+10;//l,r,x每个各10^5这样累加起来就是这么多了
int a[N],b[N];//前缀和数组,原数组
vector<PII> op,qu;//把操作和询问保存下来
vector<int> all;//all是allocate的缩写?? 该数组定义了10^9数组到10^5的数组的映射关系;all的下标对应10^5数组下标,值存的是
//10^9数组的下标
int find(int x){//找出大数组下标映射到的小数组的下标
int l=0,r=all.size()-1;
while(l<r){
int mid=l+r>>1;
if(all[mid]>=x) r=mid;
else l=mid+1;
}
return l+1;//涉及前缀和,a,b下标应该从1开始
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
while(n--){
int x,c;
scanf("%d%d",&x,&c);
op.push_back({x,c});
all.push_back(x);//把涉及到的10^9数组下标存入
}
while(m--){
int l,r;
scanf("%d%d",&l,&r);
qu.push_back({l,r});
all.push_back(l);//把涉及到的10^9数组下标存入
all.push_back(r);
}
sort(all.begin(),all.end());
all.erase(unique(all.begin(),all.end()),all.end());//对all去重,要保证和10^5是对应的!
for(int i=0;i<op.size();i++){//对原数组进行操作
int t=find(op[i].f);
b[t]+=op[i].s;
}
for(int i=1;i<=all.size();i++){//前缀和
a[i]=a[i-1]+b[i];
}
for(int i=0;i<qu.size();i++){
int l=find(qu[i].f),r=find(qu[i].s);
printf("%d\n",a[r]-a[l-1]);
}
return 0;
}