区间和--离散化

本文介绍了一种使用离散化和前缀和的方法来处理区间和问题,避免了大范围数据导致的内存问题。通过排序、去重和二分查找,将区间映射到固定范围,实现O(1)查询区间和的高效解决方案,并给出了C++实现的AC代码。
摘要由CSDN通过智能技术生成

题目描述

题目传送门
在这里插入图片描述

输出样例
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例
8
0
5

思路

离散化 + 前缀和

为什么用前缀和?
求解问题为给定区间的和,且求解的整个区间已经是固定的(对数轴上每个点的操作在之前已经全部完成),这样我们只进行一次前缀和,之后便可以在O(1)的时间复杂度内访问给定区间内的和。

为什么用离散化?
题目给定的数轴上的数据范围为-1e9~1e9,跨度为2e9,如果用数组数轴上的每个点都存储下来,需要开2e9的数组,肯定会爆内存。但是,我们可以看到,访问的区间最多有105,因此我们可以将-1e9至1e9映射到0至105,这样数组就可以放的下了

如何进行离散化,即如何进行映射?
首先我们需要对操作的所有区间端点进行排序和去重,去重的目的是了使每一个端点都对应唯一的映射值,排序是为了让区间端点映射后的值不改变相对位置
接着,我们借助二分,使每个值找到其对应的映射值,二分的范围就是不同的区间端点数

AC代码

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
const int N=1000010;
vector<PII> add;//每次操作将某一位置x上的数加c
vector<int> pos;//出现的点
vector<PII> p;//待访问的点
int a[N];//前缀和数组
int find(int x)
{
    int l = 0,r = pos.size() - 1;
    while(l < r)
    {
        int mid = l + r >> 1;
        if(pos[mid] < x)
            l = mid + 1;
        else
            r = mid;
    }
    return l + 1; //为了与前缀和下标保持一致,我们将下标映射到1~pos.size() - 1 
}
int main()
{
    int n, m;
    cin >> n >> m;
    int x, c;
    for(int i = 0; i < n; i ++)
    {
        cin >> x >> c;
        add.push_back({x, c});
        pos.push_back(x);
    }
    for(int i = 0; i < m;i ++)
    {
        int l, r;
        cin >> l >> r;
        pos.push_back(l);
        pos.push_back(r);
        p.push_back({l, r});
    }
    sort(pos.begin(),pos.end());
    pos.erase(unique(pos.begin(),pos.end()),pos.end());
    for(int i = 0; i < add.size(); i++)
    {
        int b = find(add[i].first);
        a[b] += add[i].second;
    }
    for(int i = 1; i <= pos.size(); i ++) //前缀和操作
        a[i] += a[i-1];
    for(int i = 0;i < p.size(); i ++)
    {
        int b = find(p[i].first);
        int c = find(p[i].second);
        cout << a[c] - a[b - 1] << endl;
    }
    return 0;
}

欢迎大家批评指正!!!

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值