基础算法:离散化实现

1、离散化

值域大而数值稀疏的题目,通常先将需要操作的数映射到一个数组中,再做后续操作,可以大大减少时间复杂度。

以AcWing.802为例,是一个典型的前缀和问题,但问题在于,若仅仅使用前缀和算法,时间复杂度会很高,因此需要先做离散化映射。

题目要求如下:

假定有一个无限长的数轴,数轴上每个坐标上的数都是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;

const int N = 3e5 + 10;
typedef pair<int, int> PII;

vector<PII> add;
vector<PII> query;

vector<int> alls;

int a[N], s[N];

//找到alls对应的x, l, r元素的首个下标,二分查找
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 l;
}

int main() {
    int n, m;
    cin >> n >> m;
    
    int x, c;
    while (n--) {
        cin >> x >> c;
        add.push_back(make_pair(x, c));
        alls.push_back(x);
    }

    int l, r;
    while (m--) {
        cin >> l >> r;
        query.push_back({ l, r });
        alls.push_back(l);
        alls.push_back(r);
    }

    //alls排序、去重
    sort(alls.begin(), alls.end());
    alls.erase(unique(alls.begin(), alls.end()), alls.end());

    //生成前缀和
    for (auto _a : add) {
        int idx = find(_a.first);
        a[idx + 1] += _a.second;
    }
    
    for (int i = 1; i <= alls.size(); i++) {
        s[i] = s[i - 1] + a[i];
    }

    for (auto _q : query) {
        int _r = find(_q.second) + 1;
        int _l = find(_q.first) + 1;
        cout << s[_r] - s[_l - 1] << endl;
    }

    return 0;

}
复制代码

 对以上代码进行整理,我们可以实现更优雅的写法:

复制代码
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

using PII = pair<int, int>;

map<int, int> add;
vector<PII> query;
vector<int> alls;

const int N = 3 * 1e5 + 10;
int a[N], s[N];

int bfind_1(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 l + 1;
}

int main() {
    int n, m;
    cin >> n >> m;

    int x, c;
    while (n--) {
        cin >> x >> c;
        add[x] += c;
        alls.push_back(x);
    }

    int l, r;
    while (m--) {
        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 it = add.begin(); it != add.end(); it++) {
        int idx = bfind_1(it->first);
        a[idx] = it->second; //a[idx] += it->second;
    }

    for (int k = 1; k <= alls.size(); k++) {
        s[k] = s[k - 1] + a[k];
    }

    for (auto q : query) {
        int l = bfind_1(q.first);
        int r = bfind_1(q.second);
        cout << s[r] - s[l - 1] << endl;
    }

    return 0;
}
复制代码

 

posted @   karinto  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示