莫基亚

题面

有一个 W×W 的矩阵,所有格子的初始值均为 S。

现在要对该矩阵进行一系列操作。

每次操作可以增加某格子的权值,或询问某子矩阵的总权值。

对于每个询问操作,请你输出被询问子矩阵的总权值是多少。

输入格式

第一行两个整数 S,W,其中 S 为矩阵初始值,W 为矩阵大小。

接下来每行为以下三种输入之一:

“1 x y a”——把第 x 行第 y 列的格子 (x,y) 权值增加 a;
“2 x1 y1 x2 y2”——询问以 (x1,y1) 为左下角,(x2,y2) 为右上角的矩阵内所有格子的权值和;
“3”——输入结束。

输出格式

对于每个询问(即第二种输入),输出一行表示答案。

数据范围

修改操作数M≤160000,询问次数Q≤10000,W≤2000000,1≤a≤10000
1≤x1≤x2≤W,
1≤y1≤y2≤W,
所有数据的矩阵初始值 S 均为 0,

样例

0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3

输出样例:

3
5

题解

刚开始没看范围, 直接写了树状数组, 什么sb题, 然而wa惨了

数据好大啊, 只能开一维的树状数组

那咋办啊...

树状数组维护一维y, 还有一维x, 有时间轴

这不就是cdq分治吗,

直接开始的操作就是按时间轴排序, cdq分治x轴一维, y轴用树状数组维护

修改好说, 那查询面积咋办?

都树状数组了, 当然是差分啊, (也能叫扫描线吧...)

把询问变成两条线(两次操作) 横坐标 x, 做坐标从 a~b, 我们记录 x:a~b, 前面的面积((1,a)~(x,b)的面积), 最后一减不就有了?

至于初始值, 题目说全是0, 就算不全是0, 咱们直接乘下区间大小就行了

反正我是被天使玩偶ex惨了,既然都分治了,直接归并排序,这你还能卡我?

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef pair<ll, int> PLI;
typedef vector<int> VI;
typedef double db;

template<class T1, class T2> bool umin(T1& a, T2 b) { return a > b ? (a = b, true) : false; }
template<class T1, class T2> bool umax(T1& a, T2 b) { return a < b ? (a = b, true) : false; }
template<class T> void clear(T& a) { T().swap(a); }

const int N = 2e5 + 5, M = 2e6 + 5;

int n, m, _, k;

struct Query {
    int op, x, a, b, t;
} a[N], b[N];

int tot, ans[N << 1], c[M], mxx, mxy;

void add(int x, ll k) {
    for (; x <= n; x += -x & x) c[x] += k;
}

ll ask(int x) {
    ll ans = 0;
    for (; x; x -= -x & x) ans += c[x];
    return ans;
}

void cl(int x) {
    for (; x <= n; x += -x & x) c[x] = 0;
}

void cdq(int l, int r) {
    if (l == r) return;
    int mid = l + r >> 1;
    cdq(l, mid); cdq(mid + 1, r);

    int x = l, y = mid + 1, z = l;
    for (; y <= r; b[z++] = a[y++]) {
        for (; x <= mid && a[x].x <= a[y].x; b[z++] = a[x++])
            if (a[x].op > 0) add(a[x].a, a[x].op);
        if (a[y].op == -1) ans[a[y].t] += ask(a[y].b) - ask(a[y].a - 1);
    }
    rep(i, l, x - 1) if (a[i].op > 0) cl(a[i].a);

    for (; x <= mid || y <= r;) {
        if (y > r) while (x <= mid) b[z++] = a[x++];
        else if (x > mid) while (y <= r) b[z++] = a[y++];
        else if (a[x].x <= a[y].x) b[z++] = a[x++];
        else b[z++] = a[y++];
    }
    rep(i, l, r) a[i] = b[i];
}

int main() {
    IOS; cin >> m >> n; VI idx;
    while (cin >> a[++tot].op, a[tot].op != 3) {
        if (a[tot].op == 1)
            cin >> a[tot].x >> a[tot].a >> a[tot].op, a[tot].t = tot;
        else {
            int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
            a[tot] = { -1, x1 - 1, y1, y2, tot };
            ++tot; a[tot] = { -1, x2, y1, y2, tot };
        }
        if (a[tot].op == -1) idx.pb(a[tot].t);
    }

    cdq(1, tot - 1);

    for (auto i : idx) cout << ans[i] - ans[i - 1] << '
';
    return 0;
}
原文地址:https://www.cnblogs.com/2aptx4869/p/13923647.html