《区间和》离散化+前缀和

区间和

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

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

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

输入格式
第一行包含两个整数n和m。

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

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

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

数据范围
− 1 0 9 ≤ x ≤ 1 0 9 −10^9≤x≤10^9 109x109
1 ≤ n , m ≤ 1 0 5 1≤n,m≤10^5 1n,m105
− 1 0 9 ≤ l ≤ r ≤ 1 0 9 −10^9≤l≤r≤10^9 109lr109
− 10000 ≤ c ≤ 10000 −10000≤c≤10000 10000c10000
输入样例:

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

输出样例:

8
0
5

由于给定 x x x数据范围为 − 1 0 9 ≤ x ≤ 1 0 9 −10^9≤x≤10^9 109x109,但是所要操作的 x x x的个数至多为 3 × 1 0 5 3×10^5 3×105(远小于总的点的个数),那么需要将插入和查询所涉及到的点离散化。

在这里插入图片描述

代码:

#include <bits/stdc++.h>
using namespace std;

typedef pair<int,int> pii; 
//
	const int maxn = 3e5+5;//开3e5+5 
	int n,m;
	int value[maxn];	//存放离散化后的点的值 
	int preSum[maxn];	//前缀和
	vector<int> points;	//下标为离散化之后的点 
	vector<pii> ins; 	//插入操作
	vector<pii> query;	//查询操作 
//
int find(int x)  //返回离散化之后的位置 ,利用二分法找 
{
	//找到 >= x 的第一个值 
	int res = lower_bound(points.begin(),points.end(),x) - points.begin(); 
	return res+1; //返回序号从1开始 
}
int main()
{
	scanf("%d%d",&n,&m);
    int x,c,l,r;
    for(int i=0;i<n;i++)  //读取插入操作 
    {
        scanf("%d%d",&x,&c);
        ins.push_back({x,c});  //记录操作 
        points.push_back(x); //记录下标 待离散化使用 
    }
    for(int i=0;i<m;i++)  	//读取查询操作 
    {
        scanf("%d%d",&l,&r);
        query.push_back({l,r});//记录操作 
        points.push_back(l); //记录下标 待离散化使用 
        points.push_back(r);
    }
	
	//排序
	sort(points.begin(),points.end());
	//去重
	points.erase(unique(points.begin(),points.end()) , points.end());
	
	//处理插入
	for(int i=0;i<ins.size();i++)	
	{
		value[ find(ins[i].first) ] += ins[i].second;
	}
	
	//预处理前缀和
	for(int i=1;i<=points.size();i++)  //离散化后的点的个数 (从 1 开始 ,方便处理边界问题)
	{
		preSum[i] = preSum[i-1] + value[i]; 
	}
	
	//处理Query
	for(int i=0;i<query.size();i++)
	{
		int l = find(query[i].first);
		int r = find(query[i].second);
		printf("%d\n",preSum[r] - preSum[l-1]);
	}
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值