id="c_n9"width="1920"height="990"style="position: fixed; top: 0px; left: 0px; z-index: -1; opacity: 0.5;">

关于区间和的一些理解

acwing上一道题

 

这道题的数轴虽然无限长,但是x的范围是正负 1e9 ;审题发现,实际需要用到的坐标会小于等于 x + l + r,也就是数据范围在 3e5 以内。

因此为了防止数据量过大,我们可以考虑区间映射的方式将需要使用的坐标映射到一个新的数组a中。

再看题目是想求区间和,那么我们就应该首先想到前缀和 (前缀和数组求任意区间和时间复杂度为O(1))

 

因此解题可以大致分为四个步骤:

  1. 将初始操作和需求数据读入
  2. 处理数据后将数据映射到新数组a内
  3. 求出数组a的前缀和s
  4. 根据询问依次输出结果
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 3e5 + 10;
int n, m;
int a[N], s[N];

vector<int> alls; //定义alls数组的作用是将所有会用到的坐标记录下来,映射到数组内以节省空间
vector<pair<int, int>> add, query;

int find(int x) //定义find函数寻找离散坐标对应的位置标号
{
    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开始求,所以将返回的值加1
}
int main()
{
    scanf("%d%d", &n, &m);
    while (n -- )
    {
        int x, c;
        cin >> x >> c;
        add.push_back({x, c});
        alls.push_back(x);
    }
    while (m -- )
    {
        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()); //去重
    for (auto item : add) 
        a[find(item.first)] += item.second; //将坐标映射到数组中,并实现对应坐标值加c的操作
    for (int i = 1; i <= alls.size(); i++) s[i] = s[i - 1] + a[i]; //求a数组的前缀和
    for (auto item : query) 
        cout << s[find(item.second)] - s[find(item.first) - 1] << endl; //分别处理每一次询问,输出结果
    return 0;
}

点击提交后可以发现没有问题

 

posted @ 2022-03-26 17:15  My_opt  阅读(264)  评论(0)    收藏  举报