P4390 [BOI2007]Mokia 摩基亚 题解

\(Description\)

Luogu传送门

\(Solution\)

CDQ分治板题

由于找一个矩形并不好处理,利用类似于二维前缀和的思想,把一个矩形拆成从 \((1, 1)\) 开始的 4 个矩形。

具体是哪 4 个从 \((1, 1)\) 开始的矩形自己手推一下吧,懒得打了。

考虑什么样的矩形对 \((x, y)\) 有贡献。

那么它需要满足三个条件:

  1. \((x, y)\) 这个点之前出现。
  2. \(x_2 < x\)
  3. \(y_2 < y\)

于是这道题就变成了经典的三维偏序问题!

所以它就是个 \(CDQ\) 分治板子题。

注意这题的边界有点小问题,二维前缀和中我们要用到 \((x_1 - 1, y_1 - 1)\),但这可能是 0,所以输入时把所有坐标 +1 即可,包括 \(w\)

\(Code\)

#include <bits/stdc++.h>

using namespace std;

namespace IO{
    inline int read(){
        int x = 0;
        char ch = getchar();
        while(!isdigit(ch)) ch = getchar();
        while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x;
    }

    template <typename T> inline void write(T x){
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace IO;

const int N = 2e5 + 10;
const int M = 2e6 + 10;
struct node{
    int op, id, x, y, val;
    bool operator < (const node &b) const{
        return x != b.x ? x < b.x : y < b.y;
    }
}p[N];
int n, op, w;

namespace BIT{
    int c[M];

    inline void add(int x, int y){
        for(; x <= w; x += x & (-x)) c[x] += y;
    }

    inline int qry(int x){
        int res = 0;
        for(; x; x -= x & (-x)) res += c[x];
        return res;
    }
}
using namespace BIT;

inline bool cmp(node a, node b){
    return a.id < b.id;
}

inline void CDQ(int l, int r){
    if(l == r) return;
    int mid = (l + r) >> 1;
    CDQ(l, mid), CDQ(mid + 1, r);
    sort(p + l, p + mid + 1);
    sort(p + mid + 1, p + r + 1);
    int i = l, j = mid + 1;
    while(j <= r){
        while(p[i].x <= p[j].x && i <= mid){
            if(!p[i].op) add(p[i].y, p[i].val);
            ++i;
        }
        if(p[j].op) p[j].val += qry(p[j].y);
        ++j;
    }
    for(j = l; j < i; ++j)
        if(!p[j].op) add(p[j].y, -p[j].val);
}

int main(){
    op = read(), w = read() + 1;
    while(op != 3){
        op = read();
        if(op == 1){
            int x = read() + 1, y = read() + 1, a = read();
            p[++n] = (node){0, n, x, y, a};
        }else if(op == 2){
            int x1 = read(), y1 = read(), x2 = read() + 1, y2 = read() + 1;
            p[++n] = (node){1, n, x1, y1, 0};
            p[++n] = (node){1, n, x2, y2, 0};
            p[++n] = (node){1, n, x2, y1, 0};
            p[++n] = (node){1, n, x1, y2, 0};
        }
    }
    CDQ(1, n);
    sort(p + 1, p + 1 + n, cmp);
    for(int i = 1; i <= n; ++i)
        if(p[i].op) write(p[i].val + p[i + 1].val - p[i + 2].val - p[i + 3].val), puts(""), i += 3;
    return 0;
}

\[\_EOF\_ \]

posted @ 2022-01-17 16:40  xixike  阅读(60)  评论(1编辑  收藏  举报