题目:
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。
刚开始接触离散化,不是很熟悉,一开始还弄了个二维数组,用来存坐标的值与下标,后来发现很难办,而且空间开得太大了,浪费很多资源
这个时候,我在题解中学到一招,用vector<pair<int,int>>来节省大量空间资源
const int N = 300010;
vector<pair<int, int>>f, s;
int n, m, x, c, l, r;
int a[N];
那么,这样的向量可以存所有的下标与值,还可以用它来存要搜寻的数据,同时向量还有很多数组做不到的骚操作,简单地完成复杂需求
for (int i = 0; i < n; i++) {
scanf("%d%d", &x, &c);
f.push_back({ x,c });
}
for (int i = 0; i < m; i++) {
scanf("%d%d", &l, &r);
/*f.push_back({ l,0 });
f.push_back({ r,0 });*/(注释的后面解释)
s.push_back({ l,r });(这里用来存查询)
}
那么下一个问题:怎么快速查询l与r
一开始,我在想,能不能构造一个函数,通过不断二分,使r的值不断逼近f[x].first(pair里面的第一个数,即下标),但很明显,这样子做很绕,边界问题很难处理
看了解答的思路,我恍然大悟,把l与r也存到f里面,不久让l与r天然是其边界了吗,而且不影响求值,顺着这个思路,很自然就有
f.push_back({ l,0 });
f.push_back({ r,0 });
后面的显而易见,编一个cmp,升序排列
bool cmp(pair<int, int>a1, pair<int, int>a2) {
return a1.first < a2.first;
}
sort(f.begin(), f.end(), cmp);
再后面是第二个难点:如何将相同下标的值合并
答案是:再开一个vector
vector<pair<int, int>>temp;
temp.push_back(f[0]);
for (int i = 1; i < f.size(); i++) {
if (f[i].first == temp.back().first) {
temp.back().second += f[i].second;
}
else {
temp.push_back(f[i]);
}
}
f = temp;
前缀和没有什么好说的,查询次数大就用它
a[0] = f[0].second;
for (int i = 1; i < f.size(); i++) {
a[i] = a[i - 1] + f[i].second;
}
最终,来到最后一个难点:怎么找到与目标值相同的f[i].first并取出i,二分的思路是有手就行的,但二分的边界问题一直让人头疼,建议直接背模板,不然像我一样调好几次
int find(int y) {
int Left = 0, Right = f.size()-1;
while (Left < Right) {
int mid = Left + (Right - Left) / 2;
if (f[mid].first >= y) Right = mid;
else Left = mid + 1;
}
return Right;
}
输出
for (int i = 0; i < m; i++) {
printf("%d\n", a[find(s[i].second)] - a[find(s[i].first)-1]);
}
因为这个输出与读入量很大,把我从cin与cout逼到了printf与scanf,scanf在vs2022里面想用还得多写一个取消警告,南蚌
下面是ac的源代码:
#define _CRT_SECURE_NO_WARNINGS /*让vs能用scanf*/
#include <iostream>
#include<cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 300010;
vector<pair<int, int>>f, s;
int n, m, x, c, l, r;
int a[N];
bool cmp(pair<int, int>a1, pair<int, int>a2) {
return a1.first < a2.first;
}
int find(int y) {
int Left = 0, Right = f.size()-1;
while (Left < Right) {
int mid = Left + (Right - Left) / 2;
if (f[mid].first >= y) Right = mid;
else Left = mid + 1;
}
return Right;
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
scanf("%d%d", &x, &c);
f.push_back({ x,c });
}
for (int i = 0; i < m; i++) {
scanf("%d%d", &l, &r);
f.push_back({ l,0 });
f.push_back({ r,0 });
s.push_back({ l,r });
}
sort(f.begin(), f.end(), cmp);
vector<pair<int, int>>temp;
temp.push_back(f[0]);
for (int i = 1; i < f.size(); i++) {
if (f[i].first == temp.back().first) {
temp.back().second += f[i].second;
}
else {
temp.push_back(f[i]);
}
}
f = temp;
a[0] = f[0].second;
for (int i = 1; i < f.size(); i++) {
a[i] = a[i - 1] + f[i].second;
}
for (int i = 0; i < m; i++) {
printf("%d\n", a[find(s[i].second)] - a[find(s[i].first)-1]);
}
}