题面
有一个 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;
}