Acwing基础算法 802. 区间和

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

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

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

输入格式

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

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

再接下来 m𝑚 行,每行包含两个整数 l𝑙 和 r𝑟。

输出格式

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

数据范围

−109≤x≤109−109≤𝑥≤109,
1≤n,m≤1051≤𝑛,𝑚≤105,
−109≤l≤r≤109−109≤𝑙≤𝑟≤109,
−10000≤c≤10000−10000≤𝑐≤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 = 300010; //n次插入和m次查询相关数据量的上界

int n, m;

int a[N];//存储坐标插入的值

int s[N];//存储数组a的前缀和

vector<int> alls;  //存储(所有与插入和查询有关的)坐标

vector<pair<int, int>> add, query; //存储插入和询问操作的数据



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;

}



int main() {

    scanf("%d%d", &n, &m);

    for (int i = 1; i <= n; i++) {

        int x, c;

        scanf("%d%d", &x, &c);

        add.push_back({x, c});  //往后面添加队列

        alls.push_back(x);  //坐标

    }

    for (int i = 1; i <= m; i++) {

        int l , r;

        scanf("%d%d", &l, &r);

        //全都往后加

        query.push_back({l, r});

        alls.push_back(l);

        alls.push_back(r);

    }

    //排序,去重

    sort(alls.begin(), alls.end());   //对alls进行排序

    alls.erase(unique(alls.begin(), alls.end()), alls.end());

    //这时候要求的范围由query记录

    

    for (auto item : add) {

        int x = find(item.first);

        a[x] += item.second;  //x通过alls反应在实际数组中的坐标,x坐标虚拟的。

                              //对a进行赋值

    }

    //前缀和

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

    

    for (auto item : query) {

        int l = find(item.first);    //item.first是实际的位置通过find找出再a中的虚拟位置

        int r = find(item.second);

        printf("%d\n", s[r] - s[l-1]);//输出答案

    }

    

    return 0;

}



/*



对vector定义的动态数组进行排序   sort(alls.begin(), alls.end());



alls.erase(unique(alls.begin(), alls.end()), alls.end());

分析:unique 函数并不真正删除元素,而是将重复的元素移动到容器的末尾,

      并返回一个指向“新”末尾的迭代器。

      然后,可以结合 erase 函数删除这些重复元素。



erase作用:按迭代器范围删除元素  vector<int> vec = {1, 2, 3, 4, 5};

                                 vec.erase(vec.begin() + 2, vec.begin() + 4); 

                                // 删除第3到第4个元素,不包括第5个

                                // vec 现在是 {1, 2, 5}

           删除单个元素         vec.erase(vec.begin() + 1);

                                // 删除第二个元素

                                // vec 现在是 {1, 5}



for (auto item : add)   auto自动判断add的类型用item遍历











*/



/*

对vector定义的动态数组进行排序   sort(alls.begin(), alls.end());

alls.erase(unique(alls.begin(), alls.end()), alls.end());
分析:unique 函数并不真正删除元素,而是将重复的元素移动到容器的末尾,
      并返回一个指向“新”末尾的迭代器。
      然后,可以结合 erase 函数删除这些重复元素。

erase作用:按迭代器范围删除元素  vector<int> vec = {1, 2, 3, 4, 5};
                                 vec.erase(vec.begin() + 2, vec.begin() + 4); 
                                // 删除第3到第4个元素,不包括第5个
                                // vec 现在是 {1, 2, 5}
           删除单个元素         vec.erase(vec.begin() + 1);
                                // 删除第二个元素
                                // vec 现在是 {1, 5}

for (auto item : add)   auto自动判断add的类型用item遍历





*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值