P4390 [BOI2007]Mokia 摩基亚 题解

Description

Luogu传送门

Solution

CDQ分治板题

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

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

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

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

  1. (x,y) 这个点之前出现。
  2. x2<x
  3. y2<y

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

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

注意这题的边界有点小问题,二维前缀和中我们要用到 (x11,y11),但这可能是 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 @   xixike  阅读(61)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示