[SHOI2007]园丁的烦恼 CDQ三维偏序

[SHOI2007]园丁的烦恼
题意:平面图上有n个点,m次询问,每次询问一个二维区间中包含了多少点。
使用CDQ三维偏序,第一维是时间,第二维是x坐标,第三维是y坐标。
时间开始就已经排好,x坐标是CDQ排序关键,y坐标可以用树状数组计算前缀。
注意:
1、树状数组update和clean开始不能是0
2、ask数组大小开为5倍大小N+M*4

#include <bits/stdc++.h>
#define lb(x) (x & -x)
#define ll long long
#define int long long
using namespace std;
inline void read(int &x) {
    x = 0; int f = 1; char ch = getchar();
    while (!(ch >= '0' && ch <= '9')){if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
    x *= f;
}
inline void Max(int &x, int y) {if (y > x) x = y;}
const int N = 5e5 + 10;
const int M = 1e7 + 10;
const int Q = N * 6;
int n, m, tot1, tot2;
int ans[N];
struct Ask {
    int type, x, y, w, aid;
    bool operator < (const Ask &a) {return x == a.x ? type < a.type : x < a.x;}
}ask[Q], tmp[Q];
inline void init(int type, int x, int y, int w, int aid) {
    ask[++tot1] = (Ask){type, x, y, w, aid};
}
int T[M], mxy;
inline void update(int x, int v) {for (; x <= mxy; x += lb(x)) T[x] += v;}
inline int query(int x) {
    int ret = 0;
    for (; x; x -= lb(x)) ret += T[x];
    return ret;
}
inline void clean(int x) {for (; x <= mxy; x += lb(x)) T[x] = 0;}
inline void cdq(int l, int r) {
    if (l == r) return;
    int mid = (l + r) >> 1; cdq(l, mid), cdq(mid + 1, r);
    int p = l, q = mid + 1, o = l;
    while (p <= mid && q <= r) {
        if (ask[p] < ask[q]) {
            if (ask[p].type == 1) update(ask[p].y, 1);
            tmp[o++] = ask[p++];
        } else {
            if (ask[q].type == 2) ans[ask[q].aid] += query(ask[q].y) * ask[q].w;
            tmp[o++] = ask[q++];
        }
    }
    while (p <= mid) tmp[o++] = ask[p++];
    while (q <= r) {
        if (ask[q].type == 2) ans[ask[q].aid] += query(ask[q].y) * ask[q].w;
        tmp[o++] = ask[q++];
    }
    for (int i = l; i <= r; i++) {
        if (ask[i].type == 1) clean(ask[i].y);
        ask[i] = tmp[i];
    }
}
signed main() {
    int n, m; read(n), read(m);
    for (int i = 1; i <= n; i++) {
        int x, y; read(x), read(y); ++x, ++y;
        init(1, x, y, 0, 0); Max(mxy, y);
    }
    for (int i = 1; i <= m; i++) {
        int x1, y1, x2, y2; read(x1), read(y1), read(x2), read(y2); ++x1, ++y1, ++x2, ++y2;
        init(2, x1 - 1, y1 - 1, 1, ++tot2), init(2, x1 - 1, y2, -1, tot2);
        init(2, x2, y1 - 1, -1, tot2), init(2, x2, y2, 1, tot2);
        Max(mxy, max(y1, y2));
    }
    cdq(1, tot1);
    for (int i = 1; i <= tot2; i++) printf("%lld\n", ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44627639/article/details/88647236
今日推荐