【基础算法】区间和-------离散化

假定有一个无限长的数轴,数轴上每个坐标上的数都是0。

现在,我们首先进行 n 次操作,每次操作将某一位置x上的数加c。

接下来,进行 m 次询问,每个询问包含两个整数l和r,你需要求出在区间[l, r]之间的所有数的和。

输入格式

第一行包含两个整数n和m。

接下来 n 行,每行包含两个整数x和c。

再接下里 m 行,每行包含两个整数l和r。

输出格式

共m行,每行输出一个询问中所求的区间内数字和。

数据范围

109x109−109≤x≤109,
1n,m1051≤n,m≤105,
109lr109−109≤l≤r≤109,
10000c10000−10000≤c≤10000

输入样例:

3 3
1 2
3 6
7 5
1 3
4 6
7 8

输出样例:

8
0
5

思路:

离散化的思路,因为我们的坐标有2e9这么大的数值,而我们用到的只有3e5这么点数值,对于这种类型的,我们就要想到离散化,将各个散开的点用映射到下标(1,2,3,4.......)上,这要如何做呢?我们首先要将输入的数据进行保存,将出现的过的坐标存到数组中,用于映射,进行排序和去重,坐标对应数组的下标就是我们要的映射。然后就进行常规操作,前缀和求区间和。

详细代码解析:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

typedef pair<int, int>  PII;
const int N = 300010;
int a[N], s[N];//储存映射出来的下标保存的值和前缀和。
vector<PII> add, query;//保存数据。
vector<int> alls;//储存所有用到的坐标值。

//二分查找,找出x在alls中的下标。
int find(int x) {
    int l = 0, r = alls.size() - 1, m;
    while (l < r) {
        m = l + r >> 1;
        if (alls[m] >= x) r = m;
        else l = m + 1;
    }

    return l + 1;
}

int main() {
    //保存输入输出的结果。处理输入输出
    int n, m, x, c, l, r;
    cin >> n >> m;

    for (int i = 0;i < n;i++) {
        cin >> x >> c;
        add.push_back({ x,c });
        alls.push_back(x);
    }

    for (int i = 0;i < m;i++) {
        cin >> l >> r;
        query.push_back({ l,r });
        alls.push_back(l), alls.push_back(r);
    }

    //去除重复的坐标值
    sort(alls.begin(), alls.end());
    //unique函数不停的把后面不重复的元素移到前面来,返回最后一个不重复元素的下标
    //erase函数,删除操作。
    alls.erase(unique(alls.begin(), alls.end()), alls.end());

    //对映射的值进行处理
    for (auto item : add) a[find(item.first)] += item.second;

    //求前缀和
    for (int i = 1;i <= alls.size();i++) s[i] = a[i] + s[i - 1];

    //求区间和
    for (auto item : query)
        cout << s[find(item.second)] - s[find(item.first) - 1] << endl;

    return 0;
}

 

 

 
posted @ 2020-05-25 17:04  Vincent&  阅读(437)  评论(0编辑  收藏  举报