首先解释一下什么叫离散化,离散化就是把大而分散的一段段使用到的稀疏区间,整合映射到连续的一段较小的稠密区间里
就拿上面这题来讲,我们要求区间和肯定要用到前缀和数组。我们观察到 下标是[-1e9,1e9],我们没办法开一个1e9的数组,太大了。
再观察,发现其实最多出现3e5个点(n+2*m),3e5的数组我们是可以开出来的,那我们就只关心已经出现过的点,并这些点的下标进行“重新赋值”。
例如有三个数,下标分别为:2,8,1e8。我们就可以将其下标“重写成1,2,3”,达到节省空间的目的。
我自己喜欢用map进行重写,y总用了二分重写,个人觉得我的比较方便且容易理解一些
vector<PII> add_op;
vector<PII> q_op;
vector<int> alls;
int pre[N],a[N];
int find(int x) {
//查询x在离散化区间里的位置。
//返回的是x的下标
int index = 0;
int l = 0, r = alls.size() - 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (alls[mid] >= x) {
r = mid - 1;
index = mid;
}
else {
l = mid + 1;
}
}
return index + 1;
}
void solve()
{
int n, m; cin >> n >> m;
rep(i, 1, n) {
int x, c; cin >> x >> c;
add_op.push_back({ x,c });
alls.push_back(x);
}
rep(i, 1, m) {
int l, r; cin >> l >> r;
q_op.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 it : add_op) {
int x = find(it.first);
a[x] += it.second;
}
for (int i = 1; i <= alls.size(); i++) {
pre[i] = pre[i - 1] + a[i];
}
for (auto it : q_op) {
int l = find(it.first);
int r = find(it.second);
cout << pre[r] - pre[l - 1] << endl;
}
}
y总模板
vector<PII> add_op;
vector<PII> q_op;
vector<int> alls;
int pre[N],a[N];
void solve()
{
int n, m; cin >> n >> m;
rep(i, 1, n) {
int x, c; cin >> x >> c;
add_op.push_back({ x,c });
alls.push_back(x);
}
rep(i, 1, m) {
int l, r; cin >> l >> r;
q_op.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());
unordered_map<int, int> mp;
int j = 1;
for (auto it : alls) {
mp[it] = j++;
}
for (auto it : add_op) {
int index = mp[it.first];
int val = it.second;
a[index] += val;
}
for (int i = 1; i <= alls.size(); i++) {
pre[i] = pre[i - 1] + a[i];
}
for (auto it : q_op) {
int l = mp[it.first];
int r = mp[it.second];
cout << pre[r] - pre[l - 1] << endl;
}
}