题目描述
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。
输入格式
第一行包含两个整数 n 和 m。
接下来 n 行,每行包含两个整数 x 和 c。
再接下来 m 行,每行包含两个整数 l 和 r。
输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。
数据范围
−109≤x≤109,
1≤n,m≤105,
−109≤l≤r≤109,
−10000≤c≤10000
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
Y总思路
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+5;
vector<int> all;//所有坐标
vector<pair<int,int>> add,query; //待执行加法坐标、待查询坐标
int a[N],s[N];
/*找到x离散后的下标*/
int find(int x){
int l=0,r=all.size()-1;
while(l<r){
int mid = l + r >> 1;
if(all[mid]>=x)r=mid;
else l = mid + 1;
}
return l+1; //离散起点从1开始
}
int main(){
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++){
int x,c;
scanf("%d%d",&x,&c);
add.push_back({x,c});
all.push_back(x);
}
for(int i=0;i<m;i++){
int l,r;
scanf("%d%d",&l,&r);
query.push_back({l,r});
all.push_back(l);
all.push_back(r);
}
//去重
sort(all.begin(),all.end());
all.erase(unique(all.begin(),all.end()),all.end());
//离散化并执行加法
for(auto it:add){
int x = find(it.first);
a[x] += it.second;
}
//计算前缀和
for(int i=1;i<=all.size();i++)s[i] = s[i-1]+a[i];
//查询
for(auto it:query){
printf("%d\n",s[find(it.second)]-s[find(it.first)-1]);
}
}
思路二
- 去重:set
- 离散化: map
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+5;
set<int> st; //所有坐标
vector<pair<int,int>> add,query; //待执行加法坐标、待查询坐标
unordered_map<int,int> x_i,i_x; //存储对应下标
int a[N],s[N];
int tindex=1; //用于映射下标
int main(){
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++){
int x,c;
scanf("%d%d",&x,&c);
add.push_back({x,c});
st.insert(x);
}
for(int i=0;i<m;i++){
int l,r;
scanf("%d%d",&l,&r);
query.push_back({l,r});
st.insert(l);
st.insert(r);
}
//离散化坐标
for(auto it:st){
x_i[it] = tindex;
i_x[tindex++] = it;
}
//执行加法
for(auto it:add) a[x_i[it.first]] += it.second;
//计算前缀和
for(int i=1;i<=st.size();i++)s[i] = s[i-1]+a[i];
//查询
for(auto it:query){
printf("%d\n",s[x_i[it.second]]-s[x_i[it.first]-1]);
}
}