目录

P4390-[BOI2007]Mokia 摩基亚

P4390-[BOI2007]Mokia 摩基亚

题目:

题目描述:

摩尔瓦多的移动电话公司摩基亚(Mokia)设计出了一种新的用户定位系统。和其他的定位系统一样,它能够迅速回答任何形如“用户 C 的位置在哪?”的问题,精确到毫米。但其真正高科技之处在于,它能够回答形如“给定区域内有多少名用户?”的问题。

在定位系统中,世界被认为是一个 W×W 的正方形区域,由 1×1 的方格组成。每个方格都有一个坐标(x,y),1<=x,y<=W。坐标的编号从 1 开始。对于一个 4×4 的正方形,就有 1<=x<=4,1<=y<=4(如图):

https://cdn.luogu.com.cn/upload/pic/17271.png

请帮助 Mokia 公司编写一个程序来计算在某个矩形区域内有多少名用户。

输入格式:

有三种命令,意义如下:

命令 参数 意义

  • 0 W 初始化一个全零矩阵。本命令仅开始时出现一次。
  • 1 x y A 向方格(x,y)中添加 A 个用户。A 是正整数。
  • 2 X1 Y1 X2 Y2 查询 X1<=x<=X2,Y1<=y<=Y2 所规定的矩形中的用户数量
  • 3 无参数 结束程序。本命令仅结束时出现一次。

输出格式:

对所有命令 2,输出一个一行整数,即当前询问矩形内的用户数量。

样例:

样例输入 1:

1
2
3
4
5
6
0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3

样例输出 1:

1
2
3
5

思路:

基于时间序的 cdq 分治 + 二维偏序

实现:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
#include <bits/stdc++.h>
#include "ybwhead/ios.h"
const int maxn = 1e5 + 10;
struct pos
{
    bool op;
    int x, y;
    long long v;
    int id;
} e[maxn << 2];
int w;
int tot, cnt;
bool cmp(pos a, pos b) { return a.x < b.x; }
#define lowbit(x) x & -x
long long a[maxn << 6];
long long s;
long long ans[maxn];
void add(int p, long long x)
{
    for (; p <= w + 1; p += lowbit(p))
        a[p] += x;
}
int q(int p)
{
    long long ans = 0;
    for (; p; p -= lowbit(p))
        ans += a[p];
    return ans;
}
void cdq(int l, int r)
{
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    cdq(l, mid);
    sort(e + l, e + mid + 1, cmp);
    cdq(mid + 1, r);
    sort(e + mid + 1, e + r + 1, cmp);
    int p1 = l, p2 = mid + 1;
    while (p2 <= r)
    {
        while (p1 <= mid && e[p1].x <= e[p2].x)
        {
            if (e[p1].op == 0)
                add(e[p1].y, e[p1].v);
            p1++;
        }
        if (e[p2].op == 1)
            ans[e[p2].id] += q(e[p2].y) * e[p2].v;
        p2++;
    }
    p1 = l, p2 = mid + 1;
    while (p2 <= r)
    {
        while (p1 <= mid && e[p1].x <= e[p2].x)
        {
            if (e[p1].op == 0)
                add(e[p1].y, -e[p1].v);
            p1++;
        }
        // if (e[p2].op == 2)
        //     ans[e[p2].id] += q(e[p2].y) * e[p2].v;
        p2++;
    }
    return;
}
int main()
{
    yin >> s >> w;
    int op = 0;
    while (yin >> op && op != 3)
    {
        int x, y, x1, y1;
        long long v;
        if (op == 1)
        {
            yin >> x >> y >> v;
            x++;
            y++;
            e[++tot] = {0, x, y, v, 0};
        }
        else
        {
            yin >> x >> y >> x1 >> y1;
            x++;
            y++;
            x1++;
            y1++;
            ++cnt;
            e[++tot] = {1, x - 1, y - 1, 1, cnt};
            e[++tot] = {1, x1, y1, 1, cnt};
            e[++tot] = {1, x - 1, y1, -1, cnt};
            e[++tot] = {1, x1, y - 1, -1, cnt};
        }
    }
    cdq(1, tot);
    for (int i = 1; i <= cnt; i++)
        yout << ans[i] + s << endl;
    return 0;
}