概念
维护原二维数列的差分数列,从而用二维树状数组进行单点修改,求二维前缀和等操作,进而转化为区域加,区域求和等操作。
例题
[Luogu] P4514 上帝造题的七分钟
Description
对(n imes{m})矩阵进行区域加,区域求和。((1≤n≤2048,1≤m≤2048,−500≤d≤500))
Solution
(egin{aligned}& ext {设} a_{x, y}=sum_{i=1}^{x} sum_{j=1}^{y} Delta a_{x, y}, ext { 则 }\&Delta a_{x, y}=a_{x, y}+a_{x-1, y-1}-a_{x, y-1}-a_{x-1, y} quad ext { (最终求区间和时同理})\&sum_{x=1}^{n} sum_{y=1}^{m} a_{x, y}=sum_{x=1}^{n} sum_{y=1}^{m} sum_{i=1}^{x} sum_{j=1}^{y} Delta a_{x, y}=sum_{x=1}^{n}(n-x+1) sum_{y=1}^{m}(m-y+1) Delta a_{x, y}\&=(n+1)(m+1) sum_{x=1}^{n} sum_{y=1}^{m} Delta a_{x, y}-(n+1) sum_{x=1}^{n} sum_{y=1}^{m} y Delta a_{x, y}-(m+1) sum_{x=1}^{n} sum_{y=1}^{m} x Delta a_{x, y}+sum_{x=1}^{n} sum_{y=1}^{m} x y Delta a_{x, y}\& ext { 二维树状数组维护 } sum_{x=1}^{n} sum_{y=1}^{m} Delta a_{x, y}, sum_{x=1}^{n} sum_{y=1}^{m} y Delta a_{x, y}, sum_{x=1}^{n} sum_{y=1}^{m} x Delta a_{x, y},sum_{x=1}^{n} sum_{y=1}^{m} x y Delta a_{x, y} ext { 即可 }end{aligned})
Code
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) ((x) & (-x))
int n, m, t[2050][2050][5];
char ch[2];
int read()
{
int x = 0, fl = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
return x * fl;
}
void add(int x, int y, int d, int tp)
{
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= m; j += lowbit(j))
t[i][j][tp] += d;
return;
}
int ask(int x, int y, int tp)
{
int sum = 0;
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
sum += t[i][j][tp];
return sum;
}
void modify(int x, int y, int d)
{
add(x, y, d, 1); add(x, y, d * x, 2); add(x, y, d * y, 3); add(x, y, d * x * y, 4);
return;
}
int query(int x, int y)
{
return (x + 1) * (y + 1) * ask(x, y, 1) - (y + 1) * ask(x, y, 2) - (x + 1) * ask(x, y, 3) + ask(x, y, 4);
}
int main()
{
cin >> ch >> n >> m;
while (~scanf("%s", ch))
{
int a, b, c, d, x;
if (ch[0] == 'L')
{
cin >> a >> b >> c >> d >> x;
modify(a, b, x); modify(a, d + 1, -x); modify(c + 1, b, -x); modify(c + 1, d + 1, x);
}
else
{
cin >> a >> b >> c >> d;
int res = query(c, d) - query(c, b - 1) - query(a - 1, d) + query(a - 1, b - 1);
printf("%d
", res);
}
}
return 0;
}
[Luogu] CF341D Iahub and Xors
Description
对(n imes{n})矩阵,(m)次进行区域异或(d),区域求异或和。((1≤n≤1000,1≤m≤10^5,0≤d≤2^{62}))
Solution
和上一题挺像的。注意到同一个数异或偶数次是(0),异或奇数次是它本身。
Code
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) ((x) & (-x))
int n, m, t[2050][2050][5];
char ch[2];
int read()
{
int x = 0, fl = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
return x * fl;
}
void add(int x, int y, int d, int tp)
{
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= m; j += lowbit(j))
t[i][j][tp] += d;
return;
}
int ask(int x, int y, int tp)
{
int sum = 0;
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
sum += t[i][j][tp];
return sum;
}
void modify(int x, int y, int d)
{
add(x, y, d, 1); add(x, y, d * x, 2); add(x, y, d * y, 3); add(x, y, d * x * y, 4);
return;
}
int query(int x, int y)
{
return (x + 1) * (y + 1) * ask(x, y, 1) - (y + 1) * ask(x, y, 2) - (x + 1) * ask(x, y, 3) + ask(x, y, 4);
}
int main()
{
cin >> ch >> n >> m;
while (~scanf("%s", ch))
{
int a, b, c, d, x;
if (ch[0] == 'L')
{
cin >> a >> b >> c >> d >> x;
modify(a, b, x); modify(a, d + 1, -x); modify(c + 1, b, -x); modify(c + 1, d + 1, x);
}
else
{
cin >> a >> b >> c >> d;
int res = query(c, d) - query(c, b - 1) - query(a - 1, d) + query(a - 1, b - 1);
printf("%d
", res);
}
}
return 0;
}