Address
Solution
调了一整个下午
发现每次询问的矩形一定包含
(
X
,
Y
)
(X,Y)
(X,Y) ,所以我们自然地想到把棋盘拆成
4
4
4 个部分,分别为
(
X
,
Y
)
(X,Y)
(X,Y) 的左上部分(横坐标小于等于
X
X
X 且纵坐标小于等于
Y
Y
Y ),右上部分(横坐标小于等于
X
X
X 且纵坐标大于等于
Y
Y
Y ),左下部分,右下部分。修改则可以在每个部分进行修改一次(如果修改操作的子矩形与这个部分有交集)
这样就相当于支持矩形加,求二维前缀
gcd
\gcd
gcd 。
先考虑如果这是一个序列,支持区间加和求前缀
gcd
\gcd
gcd 。
众所周知,处理区间加有一种很好的方法,那就是通过差分把区间修改转成单点修改。
设这个序列是
a
a
a ,这个序列的差分为
b
b
b ,那么
[
1
,
x
]
[1,x]
[1,x] 的
gcd
\gcd
gcd 为:
gcd
i
=
1
x
∑
j
=
1
i
b
j
\gcd_{i=1}^x\sum_{j=1}^ib_j
i=1gcdxj=1∑ibj
gcd
\gcd
gcd 有一个性质:
gcd
(
a
,
b
)
=
gcd
(
a
,
a
+
b
)
\gcd(a,b)=\gcd(a,a+b)
gcd(a,b)=gcd(a,a+b) 。
于是上式实际上可以转成:
gcd
i
=
1
x
b
i
\gcd_{i=1}^xb_i
i=1gcdxbi
用线段树就能轻松维护。
而一个矩形的二维差分定义为:
b
i
,
j
=
a
i
,
j
−
a
i
−
1
,
j
−
a
i
,
j
−
1
+
a
i
−
1
,
j
−
1
b_{i,j}=a_{i,j}-a_{i-1,j}-a_{i,j-1}+a_{i-1,j-1}
bi,j=ai,j−ai−1,j−ai,j−1+ai−1,j−1
用二维线段树维护
gcd
b
\gcd b
gcdb 即可。
复杂度
O
(
(
N
M
+
T
)
log
N
log
M
)
O((NM+T)\log N\log M)
O((NM+T)logNlogM) 。
Code
这应该是到现在写过最长的代码了
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define p2 p << 1
#define p3 p << 1 | 1
using namespace std;
inline int read()
{
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll;
inline ll readll()
{
ll res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
template <class Orz>
Orz Max(Orz a, Orz b) {return a > b ? a : b;}
template <class Orz>
Orz Min(Orz a, Orz b) {return a < b ? a : b;}
const int N = 5e5 + 5, M = N << 2, L = 3e7 + 5;
int n, m, X, Y, q, rt[4][M], ToT;
struct node
{
int lc, rc; ll xgcd;
} T[L];
vector<ll> a[N];
void modify(int l, int r, int pos, ll x, int &p)
{
if (!p) p = ++ToT;
if (l == r) return (void) (T[p].xgcd += x);
int mid = l + r >> 1;
if (pos <= mid) modify(l, mid, pos, x, T[p].lc);
else modify(mid + 1, r, pos, x, T[p].rc);
T[p].xgcd = __gcd(T[T[p].lc].xgcd, T[T[p].rc].xgcd);
}
void upt(int l, int r, int k, int &p, int lp, int rp)
{
if (!p) p = ++ToT;
T[p].xgcd = __gcd(T[lp].xgcd, T[rp].xgcd);
if (l == r) return;
int mid = l + r >> 1;
if (k <= mid) upt(l, mid, k, T[p].lc, T[lp].lc, T[rp].lc);
else upt(mid + 1, r, k, T[p].rc, T[lp].rc, T[rp].rc);
}
void change(int l, int r, int id, int x, int y, ll v, int p)
{
if (l == r)
{
if (id & 1) modify(Y, m, y, v, rt[id][p]);
else modify(1, Y, y, v, rt[id][p]);
return;
}
int mid = l + r >> 1;
if (x <= mid) change(l, mid, id, x, y, v, p2);
else change(mid + 1, r, id, x, y, v, p3);
if (id & 1) upt(Y, m, y, rt[id][p], rt[id][p2], rt[id][p3]);
else upt(1, Y, y, rt[id][p], rt[id][p2], rt[id][p3]);
}
ll query(int l, int r, int s, int e, int p)
{
if (!p) return 0;
if (l == s && r == e) return T[p].xgcd;
int mid = l + r >> 1;
if (e <= mid) return query(l, mid, s, e, T[p].lc);
else if (s >= mid + 1) return query(mid + 1, r, s, e, T[p].rc);
else return __gcd(query(l, mid, s, mid, T[p].lc),
query(mid + 1, r, mid + 1, e, T[p].rc));
}
ll ask(int l, int r, int id, int lx, int rx, int ly, int ry, int p)
{
if (l == lx && r == rx)
return id & 1 ? query(Y, m, ly, ry, rt[id][p])
: query(1, Y, ly, ry, rt[id][p]);
int mid = l + r >> 1;
if (rx <= mid) return ask(l, mid, id, lx, rx, ly, ry, p2);
else if (lx >= mid + 1) return ask(mid + 1, r, id, lx, rx, ly, ry, p3);
else return __gcd(ask(l, mid, id, lx, mid, ly, ry, p2),
ask(mid + 1, r, id, mid + 1, rx, ly, ry, p3));
}
void submat(int lx, int ly, int rx, int ry, int id, ll delta)
{
int _lx, _ly, _rx, _ry;
if (id == 0) _lx = 1, _ly = 1, _rx = X, _ry = Y;
else if (id == 1) _lx = 1, _ly = Y, _rx = X, _ry = m;
else if (id == 2) _lx = X, _ly = 1, _rx = n, _ry = Y;
else _lx = X, _ly = Y, _rx = n, _ry = m;
if (rx < _lx || _rx < lx || ry < _ly || _ry < ly) return;
lx = Max(lx, _lx); ly = Max(ly, _ly);
rx = Min(rx, _rx); ry = Min(ry, _ry);
if (id == 0)
{
change(1, X, 0, rx, ry, delta, 1);
if (lx > 1) change(1, X, 0, lx - 1, ry, -delta, 1);
if (ly > 1) change(1, X, 0, rx, ly - 1, -delta, 1);
if (lx > 1 && ly > 1) change(1, X, 0, lx - 1, ly - 1, delta, 1);
}
else if (id == 1)
{
change(1, X, 1, rx, ly, delta, 1);
if (lx > 1) change(1, X, 1, lx - 1, ly, -delta, 1);
if (ry < m) change(1, X, 1, rx, ry + 1, -delta, 1);
if (lx > 1 && ry < m) change(1, X, 1, lx - 1, ry + 1, delta, 1);
}
else if (id == 2)
{
change(X, n, 2, lx, ry, delta, 1);
if (rx < n) change(X, n, 2, rx + 1, ry, -delta, 1);
if (ly > 1) change(X, n, 2, lx, ly - 1, -delta, 1);
if (rx < n && ly > 1) change(X, n, 2, rx + 1, ly - 1, delta, 1);
}
else
{
change(X, n, 3, lx, ly, delta, 1);
if (rx < n) change(X, n, 3, rx + 1, ly, -delta, 1);
if (ry < m) change(X, n, 3, lx, ry + 1, -delta, 1);
if (rx < n && ry < m) change(X, n, 3, rx + 1, ry + 1, delta, 1);
}
}
void matrix_change(int lx, int ly, int rx, int ry, ll delta)
{
submat(lx, ly, rx, ry, 0, delta);
submat(lx, ly, rx, ry, 1, delta);
submat(lx, ly, rx, ry, 2, delta);
submat(lx, ly, rx, ry, 3, delta);
}
ll matrix_ask(int lx, int ly, int rx, int ry)
{
return __gcd(__gcd(ask(1, X, 0, lx, X, ly, Y, 1),
ask(1, X, 1, lx, X, Y, ry, 1)),
__gcd(ask(X, n, 2, X, rx, ly, Y, 1),
ask(X, n, 3, X, rx, Y, ry, 1)));
}
int main()
{
int i, j, x, lx, ly, rx, ry, op; ll v;
n = read(); m = read();
X = read(); Y = read(); q = read();
For (i, 1, n) a[i].push_back(0);
For (i, 1, n) For (j, 1, m)
{
ll x = readll();
a[i].push_back(x);
}
For (x, 0, 3)
{
int _lx, _ly, _rx, _ry;
if (x == 0) _lx = 1, _ly = 1, _rx = X, _ry = Y;
else if (x == 1) _lx = 1, _ly = Y, _rx = X, _ry = m;
else if (x == 2) _lx = X, _ly = 1, _rx = n, _ry = Y;
else _lx = X, _ly = Y, _rx = n, _ry = m;
For (i, 1, n) For (j, 1, m)
{
if (i < _lx || i > _rx || j < _ly || j > _ry) continue;
if (x == 0)
{
ll delta = a[i][j];
if (i < X) delta -= a[i + 1][j];
if (j < Y) delta -= a[i][j + 1];
if (i < X && j < Y) delta += a[i + 1][j + 1];
change(1, X, 0, i, j, delta, 1);
}
else if (x == 1)
{
ll delta = a[i][j];
if (i < X) delta -= a[i + 1][j];
if (j > Y) delta -= a[i][j - 1];
if (i < X && j > Y) delta += a[i + 1][j - 1];
change(1, X, 1, i, j, delta, 1);
}
else if (x == 2)
{
ll delta = a[i][j];
if (i > X) delta -= a[i - 1][j];
if (j < Y) delta -= a[i][j + 1];
if (i > X && j < Y) delta += a[i - 1][j + 1];
change(X, n, 2, i, j, delta, 1);
}
else
{
ll delta = a[i][j];
if (i > X) delta -= a[i - 1][j];
if (j > Y) delta -= a[i][j - 1];
if (i > X && j > Y) delta += a[i - 1][j - 1];
change(X, n, 3, i, j, delta, 1);
}
}
}
while (q--)
{
op = read(); lx = read(); ly = read();
rx = read(); ry = read();
if (op == 1) v = readll(),
matrix_change(lx, ly, rx, ry, v);
else printf("%lld\n",
abs(matrix_ask(X - lx, Y - ly, X + rx, Y + ry)));
}
return 0;
}