二维数点问题
二维数点问题
整体思路
将所有点按x值从小到大排序,那么查询满足特定条件的点的时候,可以转化为只对y值查询,由此,只需要遍历横坐标,并在遍历过程中用树状数组等数据结构维护对y的操作即可。
P2163 [SHOI2007] 园丁的烦恼
题目链接:园丁的烦恼
题意
给n个点,m次询问,每次询问给出一个矩形,对于每次询问回答每个矩形里包含多少个点。不要求在线, \(0≤n≤5×10^5, 1≤m≤5×10^5, 0≤x,y,a,b,c,d≤10^7, a≤c, b≤d\)。
思路
由于是离线的,可以把每个矩形看成从\((0,0)\)开始的四个矩形部分内点的数量加减得到的,即:
这样我们可以把矩形对应的四个点全部放到一个数组里,对其按从小到大排序即可(重载运算符,按横坐标从小到大,纵坐标从下到大排序)。
依次遍历排完序后每个矩阵的点,依次向树状数组中“小于”当前点的点的值加一,查询所有“小于”当前点的y值的点的个数,累加(或累减)到对应的第id次查询的答案中即可。
注意:由于树状数组的输入和查询是从1到x,而本题中的x和y是从0开始,因此需要把坐标都先加一。
由于y值只到1e7,所以可不进行离散化(该题测试数据比较水,测试集的y值最大似乎还不到5e5)
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 5, maxnn = 1e7 + 3;
struct poi {
int x, y;
bool operator<(const poi b) const {
return x < b.x || (x == b.x && y < b.y);
}
bool operator==(const poi b) const { return x == b.x && y == b.y; }
} a[maxn];
struct matrix {
poi x;
int k, id;
bool operator<(const matrix b) const { return x < b.x; }
} q[4 * maxn];
int lowbit(int x) { return x & -x; }
int y[maxnn], n, m, ans[maxn];
void add(int x, int d) {
while (x <= n) {
y[x] += d;
x += lowbit(x);
}
}
int query(int x) {
int sum = 0;
while (x > 0) {
sum += y[x];
x -= lowbit(x);
}
return sum;
}
void sol() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> a[i].x >> a[i].y;
for (int i = 1; i <= n; ++i) a[i].x++, a[i].y++;
sort(a + 1, a + n + 1);
for (int i = 1; i <= m; ++i) {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
q[4 * i - 3] = matrix{x1, y1, 1, i};
q[4 * i - 2] = matrix{x2 + 1, y2 + 1, 1, i};
q[4 * i - 1] = matrix{x1, y2 + 1, -1, i};
q[4 * i] = matrix{x2 + 1, y1, -1, i};
}
m *= 4;
sort(q + 1, q + m + 1);
int idx = 1;
for (int i = 1; i <= m; ++i) {
while (idx <= n && (a[idx] < q[i].x || a[idx] == q[i].x)) {
add(a[idx].y, 1);
idx++;
}
ans[q[i].id] += q[i].k * query(q[i].x.y);
}
for (int i = 1; i <= m / 4; ++i) cout << ans[i] << endl;
}
int main() {
sol();
return 0;
}
P3755 [CQOI2017] 老C的任务
原文链接:老C的任务https://www.luogu.com.cn/problem/P3755
题意
给n个点,每个点都有一个权值,有m个询问,每个询问一个矩形,问矩形内点的权值和为多少。不要求在线,\(1≤n,m≤1e5,-2^{31}<x_i,y_i,p_i,x1_j,y1_j,x2_j,y2_j<2^{31},x1_j≤x2_j,y1_j≤y2_j\)。
思路
跟上题的差别在于,这个题x,y坐标值范围更广,需要离散化,并且权值范围覆盖整个int取值范围,需要适当地用long long避免溢出。
这个题测试数据也很坑,n,m的范围写的是1e5,但是实测发现maxn需要改到3e5才对(也可能我写的有错误我没看到,如果有发现,可以评论,感谢指正)。而很明显容易出问题的数据范围方面,又没有测试点卡着,导致有的题解随便出个卡边界的数据就寄了,但是能过该题。
代码
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 3e5 + 5;
struct poi {
LL x, y;
bool operator<(const poi b) const {
return x < b.x || (x == b.x && y < b.y);
}
bool operator==(const poi b) const { return x == b.x && y == b.y; }
};
pair<poi, int> a[maxn];
struct matrix {
poi x;
int k, id;
bool operator<(const matrix b) const { return x < b.x; }
} q[4 * maxn];
LL y[5 * maxn], ans[maxn];
int n, m;
vector<LL> all_y;
int lowbit(int x) { return x & -x; }
void add(int x, int d) {
while (x <= n + 4 * m) {
y[x] += d;
x += lowbit(x);
}
}
LL query(int x) {
LL sum = 0;
while (x > 0) {
sum += y[x];
x -= lowbit(x);
}
return sum;
}
void sol() {
cin >> n >> m;
for (int i = 1; i <= n; ++i)
cin >> a[i].first.x >> a[i].first.y >> a[i].second,
all_y.push_back(a[i].first.y);
sort(a + 1, a + n + 1);
for (int i = 1; i <= m; ++i) {
LL x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
q[4 * i - 3] = matrix{x1 - 1, y1 - 1, 1, i};
q[4 * i - 2] = matrix{x2, y2, 1, i};
q[4 * i - 1] = matrix{x1 - 1, y2, -1, i};
q[4 * i] = matrix{x2, y1 - 1, -1, i};
all_y.push_back(y2);
all_y.push_back(y1 - 1);
}
sort(all_y.begin(), all_y.end());
m *= 4;
sort(q + 1, q + m + 1);
int idx = 1;
for (int i = 1; i <= m; ++i) {
while (idx <= n && (a[idx].first < q[i].x || a[idx].first == q[i].x)) {
int y_idx =
lower_bound(all_y.begin(), all_y.end(), a[idx].first.y) -
all_y.begin() + 1;
add(y_idx, a[idx].second);
idx++;
}
int y_idx = lower_bound(all_y.begin(), all_y.end(), q[i].x.y) -
all_y.begin() + 1;
ans[q[i].id] += q[i].k * query(y_idx);
}
for (int i = 1; i <= m / 4; ++i) cout << ans[i] << endl;
}
int main() {
sol();
return 0;
}