acwing_802_区间和
离散化
acwing 802. 区间和
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n次操作,每次操作将某一位置 x上的数加 c。
接下来,进行 m次询问,每个询问包含两个整数 l 和 r ,你需要求出在区间 [l,r]之间的所有数的和。
输入格式
第一行包含两个整数 n 和 m。
接下来 n 行,每行包含两个整数 x 和 c 。
再接下来 m 行,每行包含两个整数 l 和 r 。
输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。
数据范围
-109≤x≤109,
1≤n,m≤10^5,
-109≤l≤r≤109,
-10000≤c≤10000
输入样例
1 2 3 4 5 6 7
| 3 3 1 2 3 6 7 5 1 3 4 6 7 8
|
输出样例
简吸
离散化的整体思路还是简单的,就是当数据相差大而数量小时,用数组把每个数字映射到一个下标上。
~~刚开始不想看这题是因为对于pair的用法有点迷。~~~~~~
浅浅一学以后其实感觉pair跟struct没什么区别。
其次就是这个auto,之前学长来教的时候就没讲清楚.
现在看了题解大概能猜出是什么用的,格式是for(auto opt : add)。
auto是自动的意思,那么这个语法相而易见就是自动地遍历add这个数组中所有数据。
这题思路就是先把所有的数据中提到的点读入,即 n 个有数据的点,及 m 个 l,r(要求的区间和),并将数据中提到的数轴上的点和数值(x,c)放到add中,再把要求的区间 l,r 放入query中,以便后续将这些点在排序过后 point 中找出下标。
当把 point全部排序去重后,遍历一遍add数组,用二分找出每一个数据在 point (存所有数据点)中的下标 i ,在数组 a[ i ] 中加上值 c 。
既然要求区间和,那就用O(N)的时间复杂度 用前缀和的存入s[ N ] 中。
最后再用auto遍历query,用前缀和输出值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include<iostream> #include<algorithm> #include<vector> using namespace std;
#define N 300010 typedef pair<int, int> PII;
int n,m,x,c,a[N],s[N]; vector<PII> adds,query; vector<int> point;
int find(int x){ int l=0,r=point.size()-1; while(l<r){ int mid=l+r>>1; if (point[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 ++){ scanf("%d%d",&x,&c); adds.push_back({x,c}); point.push_back(x); } for(int i=1;i<=m;i++){ int l,r; cin>>l>>r; query.push_back({l,r}); point.push_back(l); point.push_back(r); } sort(point.begin(),point.end()); point.erase(unique(point.begin(),point.end()),point.end()); for(auto opt : adds){ int num=find(opt.first); a[num]+=opt.second; } for(int i=1;i<=point.size();i++) s[i]=s[i-1]+a[i]; for(auto opt : query){ int l=find(opt.first),r=find(opt.second); printf("%d\n",s[r]-s[l-1]); } return 0; }
|
2022-05-02 15:03:35 完结