AcWing 802. 区间和

题面:
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c
接下来,进行 m 次询问,每个询问包含两个整数 lr ,求出在区间 [l,r] 之间的所有数的和。

原题链接:802. 区间和 - AcWing

保序离散化

离散化就是把大而分散的一段段使用到的稀疏区间,整合映射到连续的一段较小的稠密区间里,然后就可以通过普通前缀和公式来计算连续一段的区间和,本质上就是化大为小,把稀疏离散化简为稠密连续的一段。—— acvv_motibodo

离散化可以理解为一种特殊的哈希,只不过离散化属于算法,而哈希表属于数据结构。

建立键值对(离散化模板)

去重:原数组中可能拥有重复元素

//使用库函数快速去重
vector<int> alls; //存储所有待离散化的值
sort(alls.begin(), alls.end()); //排序
//去重:unique负责去重并返回数组尾端点,erase负责释放多余空间
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; //映射到1,2,...n
}

解题思路

迄今为止看到思路最清晰的图解之一,来自liangshang大佬,搬运仅作学习,非常感谢:
image

代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 3e5 + 10; //1e5会报SE
int n, m;
int a[N], s[N];
vector<int> alls; //alls数组中存储的均为坐标(key)
vector<PII> add, query; //对应两种操作,插入与查询
//找到第一个大于等于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; //映射到1,2,...n
}
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());
//处理插入,未涉及添加操作的端点值为默认0
for (auto i : add) {
int x = find(i.first); //键
a[x] += i.second; //值
}
//预处理前缀和
for (int i = 1; i <= alls.size(); i++)
s[i] = s[i - 1] + a[i];
//处理查询
for (auto i : query) {
int l = find(i.first);
int r = find(i.second);
cout << s[r] - s[l - 1] << endl;
}
}
posted @   蒟蒻爬行中  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示