文章目录
- 离散化介绍
- 算法模板
- 离散化题目模板
- 模板题
- 区间和
- 原题链接
- 题目
- 题解
- 思路
- unique原理补充介绍
离散化介绍
算法模板
离散化题目模板
vector<int> alls; // 存储所有待离散化的值
sort(alls.begin(), alls.end()); // 将所有值排序
alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 去掉重复元素
// 二分求出x对应的离散化的值
int find(int x) // 找到第一个大于等于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; // 映射到1, 2, ...n
}
模板题
区间和
原题链接
https://www.acwing.com/problem/content/804/
题目
802 . 区间和
假定有一个无限长的数轴,数轴上每个坐标上的数都是 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
题解
思路
进行 n次操作,每次操作将某一位置 x上的数加 c
m次询问,每个询问包含两个整数 l和 r
因此会涉及到n+2m个下标,而1≤n,m≤10^5,所以N开3e5+10
会用到的下标都会被保存到alls数组,这样就可以把这些数对应的下标离散化映射到自然数1,2,3,…下标
使用二分查找函数find(x)(x为原来的下标)即可查找到映射后在alls数组中对应的下标
然后使用前缀和处理来解决查询问题
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 3e5 + 10;
typedef pair<int,int> PII;
int a[N],s[N]; //s[i]为a[i]的前缀和数组
vector<int> alls; //存的是原下标!
vector<PII> add,query;
int n,m;
//二分查找
int find(int x){ //查找x对应在alls数组中的下标
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; //+1表示从1开始映射,不+1表示从0开始映射
}
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); //x即为原下标在alls数组中对应的下标。也即为离散化后映射的下标(1,2,3,...)
a[x]+=item.second;
}
// 预处理前缀和
for(int i=1;i<=alls.size();i++){
s[i] = s[i-1]+a[i];
}
// 处理询问
for(int i=0;i<m;i++){
int l = find(query[i].first);
int r = find(query[i].second);
cout<<s[r] - s[l-1]<<endl;
}
}
unique原理补充介绍