离散化,简单来说就是将一些分散不集中的点经过映射,让这些点不改变原来顺序,让其集中起来。
举个例子:
离散化的操作:排序->去重
//s储存的是需要离散的值
sort(s.begin(), s.end());
s.erase(unique(s.begin(), s.end()), s.end())
对于离散化的用途:再举一个非常极端的例子,假设有1000个数,分布在[0, 10 ^ 9],我要对区间[l, r]询问区间和,你被要求用前缀和做,那你难道要开一个10 ^ 9的数组吗,这显然是行不通的。
然后我们可以将其离散化,将这一千个数的下标离散到[1,1000],这样我们只需要维护一个1000的数组了!!!
一道小小的模板不成敬意区间和
本题的情况就像我上面所说的那样,范围很大,但是数比较少,我们维护一个alls的向量保存需要访问的下标,然后排序去重,就映射到一个小数组了。
答案是从Y总那学的
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 300010;//需要离散的个数
int n,m;
int a[N],s[N];//a储存离散化后的数组,s为其前缀和
vector <int> alls;//离散后的结果
vector <PII> add, query;//储存题目的操作
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;//映射到1,2,3,4,...
}
int main()
{
cin>>n>>m;
for(int i = 0; i < n; i++)
{
int x, c;
scanf("%d%d", &x, &c);
add.push_back({x, c});//存入操作
alls.push_back(x);//将涉及的坐标存入
}
for(int i = 0; i < m; i++)
{
int l, r;
scanf("%d%d", &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;
}