二维数点问题

二维数点问题

整体思路

将所有点按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)\)开始的四个矩形部分内点的数量加减得到的,即:

\[N_{total} = N_{x_2,y_2}-N_{x_1-1,y_2}-N_{x_2,y_1-1}+N_{x_1-1,y_1-1} \]

这样我们可以把矩形对应的四个点全部放到一个数组里,对其按从小到大排序即可(重载运算符,按横坐标从小到大,纵坐标从下到大排序)。
依次遍历排完序后每个矩阵的点,依次向树状数组中“小于”当前点的点的值加一,查询所有“小于”当前点的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;
}
posted @ 2023-07-05 14:50  FlyingLight  阅读(339)  评论(0编辑  收藏  举报