[BZOJ2877][Noi2012]魔幻棋盘(差分+二维线段树)

Address

洛谷P2086
BZOJ2877
LOJ#2672

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=1ibj
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,jai1,jai,j1+ai1,j1
用二维线段树维护 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值