「Luogu P4390」Mokia

Posted hlw1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「Luogu P4390」Mokia相关的知识,希望对你有一定的参考价值。

给出一个空的二维矩形( w 行 w 列)和一些操作,操作包括单点修改和查询子矩形内的数量和。 ((1 le w le 2000000))

Luogu

分析

典型的三维偏序问题。

显然,要求 ((x_1,y1)(x_2,y_2)) 中的贡献,用一点点容斥,那么它就等于 ((1,1)(x_2,y_2)-(1,1)(x_1-1,y_2)-(1,1)(x_2,y_1-1)+(1,1)(x_1-1,y_1-1)) ,然后以时间为一维,我们就可以愉快地 CDQ 了。

当然,如果 y = 1 的话,我们将 y - 1 = 0 插入树状数组,会导致树状数组陷入死循环,所以我们将所有的坐标都 +1 ,同样的, w 也要 +1 。

代码

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 200005
#define M 2000003
#define lowbit(i) i&-i
#define tie0 cin.tie(0),cout.tie(0)
#define fastio ios::sync_with_stdio(false)
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
typedef long long ll;

template <typename T> inline void read(T &x) {
    T f = 1; x = 0; char c;
    for (c = getchar(); !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    x *= f;
}

struct ele { int x, y, tot, id, pa; } e[N];

int w, cnt, q;
int ans[N];

struct TreeArray {
    int c[M];

    void add(int i, int k) {
        while (i <= w) {
            c[i] += k;
            i += lowbit(i);
        }
    }

    int query(int i) {
        int ret = 0;
        while (i) {
            ret += c[i];
            i -= lowbit(i);
        }
        return ret;
    }
} tr;

bool cmpid(ele a, ele b) { return a.id < b.id; }
bool cmpdt(ele a, ele b) { return a.x == b.x ? a.y < b.y : a.x < b.x; }

void CDQ(int l, int r) {
    if (l == r) return;
    int mid = l + r >> 1;
    CDQ(l, mid), CDQ(mid + 1, r);
    sort(e + l, e + 1 + mid, cmpdt), sort(e + 1 + mid, e + 1 + r, cmpdt);
    int i, j;
    for (i = l, j = mid + 1; j <= r; ++j) {
        while (i <= mid && e[i].x <= e[j].x) {
            if (!e[i].pa) tr.add(e[i].y, e[i].tot);
            i++;
        }
        if (e[j].pa) e[j].tot += tr.query(e[j].y);
    }
    for (j = l; j < i; ++j) if (!e[j].pa) tr.add(e[j].y, -e[j].tot);
}

int main() {
    //freopen("data.in", "r", stdin);
    //freopen("my.out", "w", stdout);
    int opt, x1, x2, y1, y2, k;
    read(opt), read(w);
    w++;
    while (true) {
        read(opt);
        if (opt == 1) {
            read(x1), read(y1), read(k);
            e[++cnt] = (ele){++x1, ++y1, k, cnt, 0};
        }
        else if (opt == 2) {
            read(x1), read(y1), read(x2), read(y2);
            e[++cnt] = (ele){x1, y1, 0, cnt, 1};
            e[++cnt] = (ele){++x2, ++y2, 0, cnt, 1};
            e[++cnt] = (ele){x2, y1, 0, cnt, 1};
            e[++cnt] = (ele){x1, y2, 0, cnt, 1};
        }
        else if (opt == 3) break;
    }
    //printf("cnt:%d
", cnt);
    CDQ(1, cnt);
    sort(e + 1, e + 1 + cnt, cmpid);
    //for (int i = 1; i <= cnt; ++i)
    //printf("id:%d x:%d y:%d tot:%d pa:%d
", e[i].id, e[i].x, e[i].y, e[i].tot, e[i].pa);
    for (int i = 1; i <= cnt; ) {
        if (e[i].pa) ans[++q] = e[i].tot + e[i+1].tot - e[i+2].tot - e[i+3].tot, i += 4;
        else ++i;
    }
    for (int i = 1; i <= q; ++i) printf("%d
", ans[i]);
    return 0;
}

以上是关于「Luogu P4390」Mokia的主要内容,如果未能解决你的问题,请参考以下文章

Mokia(三维偏序)P4390

洛谷 - P4390 [BOI2007]Mokia 摩基亚(带修二维数点-四叉线段树/CDQ分治)

[Luogu4390][BOI2007]Mokia 摩基亚

「BOI2007」Mokia

[Balkan 2007] Mokia

COGS1752 BOI2007—摩基亚Mokia