# 题目大意

1. 给一个矩阵的子矩阵的所有元素同时加一个数。
2. 计算子矩阵和。

# 题解

## 使用二维树状数组的正解

$g(i,j) = s(i,j)$

$g(i,j) = s(i,j) + (ij+(x_0-1)(y_0-1))k - (j(x_0-1)+i(y_0-1))k$

$g(i,j) = s(i,j) + (iy_1+(x_0-1)(y_0-1))k - ((x_0-1)y_1+i(y_0-1))k$

$g(i,j) = s(i,j) + (jx_1+(x_0-1)(y_0-1))k - (j(x_0-1)+x_1(y_0-1))k$

$g(i,j) = s(i,j) + (x_1y_1+(x_0-1)(y_0-1))k - ((x_0-1)y_1+x_1(y_0-1))k$

# 代码（使用二维线段树的错误解答）

#include <algorithm>
#include <cstdio>
const int maxm = 3000;
const int maxn = 2048 * 2048 * 4;
int sum[maxn], ll[maxn], rr[maxn], add[maxn], lc[maxn], rc[maxn], sz = 0,
gg[maxm];
char wtf;
int n, m;
void pushdown(int k) {
int mid = (ll[k] + rr[k]) >> 1;
sum[lc[k]] += (mid - ll[k] + 1) * (add[k]);
sum[rc[k]] += (rr[k] - mid) * (add[k]);
}
return;
}
void update(int k) { sum[k] = sum[lc[k]] + sum[rc[k]]; }
int build(int k, int l, int r, int a) {
ll[k] = l, rr[k] = r;
if (l == r) {
if (a == 0) {
gg[k] = ++sz;
build(gg[k], 1, m, 1);
} else if (a == 1) {
sum[k] = 0;
}
return k;
}
int mid = (l + r) >> 1, left = build(++sz, l, mid, a),
right = build(++sz, mid + 1, r, a);
lc[k] = left, rc[k] = right;
sum[k] = sum[lc[k]] + sum[rc[k]];
return k;
}
void change(int k, int y0, int y1, int val) {
int l = ll[k], r = rr[k], mid = (l + r) >> 1;
if (y0 <= l && r <= y1) {
sum[k] += (r - l + 1) * (val);
return;
}
pushdown(k);
if (y0 <= mid)
change(lc[k], y0, y1, val);
if (y1 > mid)
change(rc[k], y0, y1, val);
update(k);
}
void plus(int k, int x0, int x1, int y0, int y1, int val) {
int l = ll[k], r = rr[k], mid = (l + r) >> 1;
if (x0 <= l && r <= x1 && l == r) {
change(gg[k], y0, y1, val);
return;
}
if (x0 <= mid)
plus(lc[k], x0, x1, y0, y1, val);
if (x1 > mid)
plus(rc[k], x0, x1, y0, y1, val);
update(k);
return;
}
int query(int k, int x0, int x1, int y0, int y1, int a) {
int l = ll[k], r = rr[k], mid = (l + r) >> 1;
if (a == 0) {
if (x0 <= l && r <= x1 && l == r) {
return query(gg[k], x0, x1, y0, y1, 1);
}
int ans = 0;
if (x0 <= mid)
ans += query(lc[k], x0, x1, y0, y1, 0);
if (x1 > mid)
ans += query(rc[k], x0, x1, y0, y1, 0);
return ans;
}
if (a == 1) {
if (y0 <= l && r <= y1) {
return sum[k];
}
pushdown(k);
int ans = 0;
if (y0 <= mid)
ans += query(lc[k], x0, x1, y0, y1, 1);
if (y1 > mid)
ans += query(rc[k], x0, x1, y0, y1, 1);
update(k);
return ans;
}
}
int main() {
#ifdef D
freopen("input", "r", stdin);
#endif
scanf("%c %d %d", &wtf, &n, &m);
int t = build(++sz, 1, n, 0);
char ch;
while (scanf("%c", &ch) == 1) {
if (ch == 'L') {
int x0, y0, x1, y1, val;
scanf("%d %d %d %d %d", &x0, &y0, &x1, &y1, &val);
if (x0 > x1) {
std::swap(x0, x1);
std::swap(y0, y1);
}
plus(t, x0, x1, y0, y1, val);
}
if (ch == 'k') {
int x0, y0, x1, y1;
scanf("%d %d %d %d", &x0, &y0, &x1, &y1);
if (x0 > x1 && y0 < y1) {
std::swap(y0, y1);
}
if (x0 > x1)
std::swap(x0, x1);
int ans = query(t, x0, x1, y0, y1, 0);
printf("%d\n", ans);
}
}
return 0;
}


# 代码（使用树状数组的正解）

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#ifdef D
const int maxn = 30;
#else
const int maxn = 2052;
#endif
int n, m;
int c
[4][maxn]
[maxn]; // a:与i无关与j无关,b:与i有关与j无关,c:与i无关与j有关,d:与i有关与j有关
char opt;
void change(int id, int x, int y, int val) {
for (int i = x; i <= n; i += i & -i) {
for (int j = y; j <= m; j += j & -j) {
c[id][i][j] += val;
}
}
}
int qu(int id, int x, int y) {
int ans = 0;
for (int i = x; i > 0; i -= i & -i) {
for (int j = y; j > 0; j -= j & -j) {
ans += c[id][i][j];
}
}
return ans;
}
void pls(int x0, int y0, int x1, int y1, int k) {
change(0, x0 + 1, y0 + 1, (x0 * y0) * k);
change(0, x0 + 1, y1 + 1, -(x0 * y1) * k);
change(0, x1 + 1, y0 + 1, -(x1 * y0) * k);
change(0, x1 + 1, y1 + 1, (x1 * y1) * k);
//-------
change(1, x0 + 1, y0 + 1, -(y0 * k));
change(1, x1 + 1, y0 + 1, (y0 * k));
change(1, x0 + 1, y1 + 1, (y1 * k));
change(1, x1 + 1, y1 + 1, -(y1 * k));
//-------
change(2, x0 + 1, y0 + 1, -(x0 * k));
change(2, x0 + 1, y1 + 1, (x0 * k));
change(2, x1 + 1, y0 + 1, (x1 * k));
change(2, x1 + 1, y1 + 1, -(x1 * k));
//-------
change(3, x0 + 1, y0 + 1, k);
change(3, x0 + 1, y1 + 1, -k);
change(3, x1 + 1, y0 + 1, -k);
change(3, x1 + 1, y1 + 1, k);
}
int sum(int x, int y) {
return qu(0, x, y) + (qu(1, x, y) * x) + (qu(2, x, y) * y) +
(qu(3, x, y) * x * y);
}
int query(int x0, int y0, int x1, int y1) {
int sum1 = sum(x0 - 1, y0 - 1);
int sum2 = sum(x0 - 1, y1);
int sum3 = sum(x1, y0 - 1);
int sum4 = sum(x1, y1);
return sum4 - sum2 - sum3 + sum1;
}
int main() {
#ifdef D
freopen("input", "r", stdin);
#endif
scanf("%c %d %d", &opt, &n, &m);
n++, m++;
memset(c, 0, sizeof(c));
while (scanf("%c", &opt) == 1)
if (opt == 'L' || opt == 'k') {
int x0, y0, x1, y1;
scanf("%d %d %d %d", &x0, &y0, &x1, &y1);
x0++;
x1++;
y0++;
y1++;
if (x0 > x1) {
std::swap(x0, x1);
std::swap(y0, y1);
}
if (opt == 'L') {
int v;
scanf("%d ", &v);
x0--, y0--;
pls(x0, y0, x1, y1, v);
}
if (opt == 'k') {
#ifdef D
for (int k = 0; k < 4; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
std::cout << c[k][i][j] << ' ';
std::cout << std::endl;
}
std::cout << std::endl << std::endl;
}
#endif
int ans = query(x0, y0, x1, y1);
printf("%d\n", ans);
}
}
}


posted on 2017-03-03 21:44  蒟蒻konjac  阅读(782)  评论(0编辑  收藏  举报