某岛

… : "…アッカリ~ン . .. . " .. .
June 9, 2023

Luogu P2086. [NOI2012] 魔幻棋盘

差分维护 gcd 是一个很常见的技巧了。。
先写个线段树拿点部分分吧。。。(然后发现讨论 n,m 大小。。暴力开 o2 能过。)

#include <lastweapon/io>
// #include <lastweapon/segtree>
using namespace lastweapon;

const int N = int(5e5)+9;

/*
LL gcd(LL a,LL b)
{
    return b?gcd(b,a%b):abs(a);
}*/

inline LL gcd(LL a,LL b)
{
	if(a<0) a=-a;
	if(b<0) b=-b;
	if(!a) return b;
	if(!b) return a;
	LL t=__builtin_ctzll(a|b),tmp;
	a>>=__builtin_ctzll(a);
	do
	{
		b>>=__builtin_ctzll(b);
		if(a>b)
		{
			tmp=a,a=b,b=tmp;
		}
		b-=a;
	} while(b);
	return a<<t;
}

LL op(LL a, LL b) { return gcd(a, b); }
LL e() { return 0; }
int m, n;

const int TN = 4*N, M = 710;


#define lx (x<<1)
#define rx (lx|1)
#define ml ((l+r)>>1)
#define mr (ml+1)
#define lc lx,l,ml
#define rc rx,mr,r
#define rt 1,0,n-1

struct SegTree{

    vector<LL> T;

    void add(int x, LL d) {
        T[x] += d;
    }

    void Build(int x, int l, int r, vector<LL> &a) {
        if (l < r) {
            T[x] = 0;
            Build(lc, a), Build(rc, a);
        } else {
            T[x] = a[l];
        }
    }

    LL Query(int x, int l, int r, const int p) {
        if (l == r) {
            return T[x];
        } else {
            return T[x] + (p < mr ? Query(lc, p) : Query(rc, p));
        }
    }

    void Add(int x, int l, int r, const int a, const int b, const LL d) {
        if (b < l || r < a) return;
        if (a <= l && r <= b) {
            add(x, d);
        } else {
            Add(lc, a, b, d); Add(rc, a, b, d);
        }
    }
} S[M];


struct SegTree2{

    vector<LL> T;

    void upd(int x) {
        T[x] = gcd(T[lx], T[rx]);
    }

    void add(int x, LL d) {
        T[x] += d;
    }

    void Build(int x, int l, int r, vector<LL> &a) {
        if (l < r) {
            Build(lc, a), Build(rc, a);
            upd(x);
        } else {
            T[x] = a[l];
        }
    }

    LL Query(int x, int l, int r, const int a, const int b) {
        if (b < l || r < a) return 0;
        if (a <= l && r <= b) {
            return T[x];
        } else {
            return gcd(Query(lc, a, b), Query(rc, a, b));
        }
    }

    void Add(int x, int l, int r, const int p, const LL d) {
        if (l == r) {
            add(x, d);
        } else {
            if (p < mr) Add(lc, p, d);
            else Add(rc, p, d);
            upd(x);
        }
    }
} T[M];

bool flip;

int main() {

#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif

    RD(m, n); // if (m != 1) return 0;
    int y0, x0; RD(y0, x0); --x0; --y0; int Q; RD(Q);

    if (m > n) {
        swap(m, n);
        flip = 1;
    }

    vector<vector<LL>> a, d; a.resize(m); d.resize(m);

    if (flip) {
        REP(i, n) REP(j, m) a[j].PB(RD());
    } else {
        REP(j, m) REP(i, n) a[j].PB(RD());
    }

    REP(j, m) {
        REP(i, n-1) d[j].PB(a[j][i+1] - a[j][i]);
        d[j].PB(0);
    }

    REP(i, m) S[i].T.resize(4*n), S[i].Build(rt, a[i]);
    REP(i, m) T[i].T.resize(4*n), T[i].Build(rt, d[i]);

    DO(Q) {

        int cmd, u, l, d, r; RD(cmd, u, l, d, r);

        if (!cmd) {
            u = y0 - u; d = y0 + d; l = x0 - l; r = x0 + r;
            if (flip) swap(u, l), swap(d, r);

            LL z = 0; FOR_1(i, u, d) {
                z = gcd(z, gcd(S[i].Query(rt, l), l < r ? T[i].Query(rt, l, r-1) : 0));
            }
            printf("%lld\n", abs(z));
        } else {
            LL delta; RD(delta); //continue;
            --l; --r; --u; --d; if (flip) swap(u, l), swap(d, r);

            FOR_1(i, u, d) {
                S[i].Add(rt, l, r, delta);
                if (l) T[i].Add(rt, l-1, delta);
                T[i].Add(rt, r, -delta);
            }
        }
    }
}