假定有一个无限长的数轴,数轴上每个坐标上的数都是0。
现在,我们首先进行 n 次操作,每次操作将某一位置x上的数加c。
近下来,进行 m 次询问,每个询问包含两个整数l和r,你需要求出在区间[l, r]之间的所有数的和。
输入格式
第一行包含两个整数n和m。
接下来 n 行,每行包含两个整数x和c。
再接下里 m 行,每行包含两个整数l和r。
输出格式
共m行,每行输出一个询问中所求的区间内数字和。
数据范围
−109≤x≤109−109≤x≤109,
1≤n,m≤1051≤n,m≤105,
−109≤l≤r≤109−109≤l≤r≤109,
−10000≤c≤10000−10000≤c≤10000
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
离散化的本质,是映射,将间隔很大的点,映射到相邻的数组元素中。减少对空间的需求,也减少计算量。
离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。
如果开数组,那么需要的数组就太大了,可以用合适大小的数组将已更改值的下标存入,按顺序存,这样节省空间。
所以要进行排序,然后去重;具体看代码;
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int n,sum[N];
typedef struct{
int num;
int val;
}pill;
pill a[N];
//排序也可用sort
void quick_sort(int l,int r,pill q[]){
if(l >= r) return ;
int temp = q[l + r >> 1].num;
int i = l - 1,j = r + 1;
while(i < j){
do i++;while(q[i].num < temp);
do j--;while(q[j].num > temp);
if(i < j){
// pill t = q[i];
// q[i] = q[j];
// q[j] = t;
swap(q[i],q[j]);
}
}
quick_sort(l,j,a);quick_sort(j + 1,r,a);
}
//寻找大于x的最小下标,也就是更改的第一个数,没更改就是0;
int findl(int x){
int l = 1,r = n;
while(l < r){
int mid = l + r >> 1;
if(a[mid].num >= x) r = mid;
else l = mid + 1;
}
if(x <= a[l].num)
return l;
else return n + 1;
}
//寻找小于r的最大值,也就是在区间[l,r]找已更改的上线;
int findr(int x){
int l = 1,r = n;
while(l < r){
int mid = l + r + 1 >> 1;
if(a[mid].num <= x) l = mid;
else r = mid - 1;
}
if(x >= a[l].num)
return l;
else return 0;
}
int main(){
int m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)scanf("%d%d",&a[i].num,&a[i].val);
quick_sort(1,n,a);
//讲相同的去掉,并把数组变小;
int j = 1;
for(int i = 2; i <= n; i++){
if(a[i].num > a[i - 1].num)a[++j] = a[i];
else a[j].val += a[i].val;
}
n = j;
//前缀和;
for(int i = 1; i <= j; i++) sum[i] = sum[i - 1] + a[i].val;
while(m--){
int l,r;
scanf("%d%d",&l,&r);
l = findl(l),r = findr(r);
printf("%d\n",sum[r] - sum[l - 1]);
}
//for(int i = 1; i <=n; i++)printf("%d ",a[i].num);
return 0;
}