题解
由
gcd(a,b)=c
g
c
d
(
a
,
b
)
=
c
,可得
c|a,c|b
c
|
a
,
c
|
b
,那么
(a−b)|c
(
a
−
b
)
|
c
,由可以把
b
b
全部提出来,即为,所以求
gcd
g
c
d
可以欧几里得辗转相除。
那么对于这道题,显然是一个线段树的操作。
维护区间
gcd
g
c
d
可以直接维护上传,维护区间加也显然可以。但两个操作一起执行就不可以了。
那么结合求
gcd
g
c
d
可以辗转相除的性质,我们对这个矩形进行二维差分。差分后的区间
gcd
g
c
d
不变,但区间加操作转变为四个单点加,显然单点加直接
log2n
l
o
g
2
n
更新后
update
u
p
d
a
t
e
上来即可。
考虑到差分求
gcd
g
c
d
也需要从差分的起始点求,而
gcd
g
c
d
并不支持删去和加成。
而这道题恰恰规定了起始点(向四个方向延伸),那么就可以按四个象限的方向分别做差分,询问的时候就不需要再做任何处理了。但这样也造成了修改的麻烦。
因为是二维平面上的差分,而且四个象限中都需要讨论到,所以很麻烦。要把这个加操作区域分成四个顶点,两对对边,一个中心点来讨论(具体也可以看代码实现。
ps:题面有一个错误:
表示询问的区域是以棋盘守护者的位置为基础向上扩展x1行,向下扩展y1行,向左扩展x2列,向右扩展y2列得到的矩形区域(详见样例
这里应改为:向上扩展 x1 x 1 行,向下扩展 x2 x 2 行,向左扩展 y1 y 1 列,向右扩展 y2 y 2 列,这题面真的坑人啊。
if i f else e l s e 一定要多打括号…
代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+1000,M=2e7;
typedef long long ll;
int n,m,T,tot;ll ans;
struct Array{
ll num[N];
ll * operator[] (int x){return &num[(x-1)*m];}
}a,b;
struct P{
int x,y;
P(){}
P(int X,int Y){x=X;y=Y;}
}ori,st,ed,des;
int ch[M][2],rt[N<<2],cnt;
ll w[M];
template<class T>
inline void rd(T &x){
x=0;char c=getchar();int f=0;
while(!isdigit(c)){if(c=='-') f=1;c=getchar();}
while(isdigit(c)){x=x*10+(c^48);c=getchar();}
if(f) x=-x;
}
inline ll bs(ll x) {return x<0?-x:x;}
inline ll gcd(ll x,ll y){return y==0?bs(x):gcd(y,x%y);}
namespace tree{
#define ls (k<<1)
#define rs (k<<1|1)
#define lc ch[k][0]
#define rc ch[k][1]
#define mid (((l)+(r))>>1)
inline void pushup(int k){w[k]=gcd(w[lc],w[rc]);}
inline void setup(int &k,int l,int r,int pos)
{
k=++cnt;
if(l==r) {w[k]=b[pos][l];return;}
setup(lc,l,mid,pos);setup(rc,mid+1,r,pos);
pushup(k);
}
inline void merge(int &k,int ix,int iy,int l,int r)
{
if(!k) k=++cnt;
w[k]=gcd(w[ix],w[iy]);
if(l==r) return;
merge(lc,ch[ix][0],ch[iy][0],l,mid);
merge(rc,ch[ix][1],ch[iy][1],mid+1,r);
}
inline void build(int k,int l,int r)
{
if(l==r) {setup(rt[k],1,m,l);return;}
build(ls,l,mid);build(rs,mid+1,r);
merge(rt[k],rt[ls],rt[rs],1,m);
}
inline ll get(int k,int l,int r)
{
if(ed.x<=l && r<=ed.y) return w[k];
ll re=0;
if(ed.x<=mid) re=get(lc,l,mid);
if(ed.y>mid) re=gcd(get(rc,mid+1,r),re);
return re;
}
inline ll query(int k,int l,int r)
{
if(st.x<=l && r<=st.y) return get(rt[k],1,m);
ll re=0;
if(st.x<=mid) re=query(ls,l,mid);
if(st.y>mid) re=gcd(query(rs,mid+1,r),re);
return re;
}
inline void modify(int k,int l,int r,ll val)
{
if(l==r) {w[k]+=val;return;}
if(des.y<=mid) modify(lc,l,mid,val);
else modify(rc,mid+1,r,val);
pushup(k);
}
inline void update(int k,int ix,int iy,int l,int r)
{
w[k]=gcd(w[ix],w[iy]);
if(l==r) return;
if(des.y<=mid) update(lc,ch[ix][0],ch[iy][0],l,mid);
else update(rc,ch[ix][1],ch[iy][1],mid+1,r);
}
inline void ad(int k,int l,int r,ll val)
{
if(l==r){modify(rt[k],1,m,val);return;}
if(des.x<=mid) ad(ls,l,mid,val);
else ad(rs,mid+1,r,val);
update(rt[k],rt[ls],rt[rs],1,m);
}
}
using namespace tree;
int main(){
int i,j,op,ix,iy;ll iz;
rd(n);rd(m);rd(ori.x);rd(ori.y);rd(T);
for(i=1;i<=n;++i)
for(j=1;j<=m;++j)
rd(a[i][j]);
for(i=1;i<=n;++i)
for(j=1;j<=m;++j){
b[i][j]=a[i][j];
if(i<ori.x) b[i][j]-=a[i+1][j];
if(i>ori.x) b[i][j]-=a[i-1][j];
if(j<ori.y) b[i][j]-=a[i][j+1];
if(j>ori.y) b[i][j]-=a[i][j-1];
if(i==ori.x || j==ori.y) continue;
b[i][j]+=a[i+(i>ori.x?-1:1)][j+(j>ori.y?-1:1)];
}
build(1,1,n);
while(T--){
rd(op);
if(!op){
rd(st.x);rd(ed.x);rd(st.y);rd(ed.y);
st.x=ori.x-st.x;st.y=ori.x+st.y;
ed.x=ori.y-ed.x;ed.y=ori.y+ed.y;
printf("%lld\n",query(1,1,n));
}else{
tot++;
rd(st.x);rd(st.y);rd(ed.x);rd(ed.y);rd(iz);
ix=st.x;iy=st.y;
if(ix<=ori.x){
if(iy<=ori.y && iy>1 && ix>1)
{des=P(ix-1,iy-1);ad(1,1,n,iz);}
else if(ix>1 && ori.y<iy)
{des=P(ix-1,iy);ad(1,1,n,-iz);}
}else{
if(iy<=ori.y && iy>1)
{des=P(ix,iy-1);ad(1,1,n,-iz);}
else if(iy>ori.y)
{des=P(ix,iy);ad(1,1,n,iz);}
}
ix=st.x;iy=ed.y;
if(ix<=ori.x){
if(iy<ori.y && ix>1)
{des=P(ix-1,iy);ad(1,1,n,-iz);}
else if(iy>=ori.y && ix>1 && iy<m)
{des=P(ix-1,iy+1);ad(1,1,n,iz);}
}else{
if(iy<ori.y)
{des=P(ix,iy);ad(1,1,n,iz);}
else if(iy>=ori.y && iy<m)
{des=P(ix,iy+1);ad(1,1,n,-iz);}
}
ix=ed.x;iy=ed.y;
if(ix<ori.x){
if(iy<ori.y)
{des=P(ix,iy);ad(1,1,n,iz);}
else if(iy>=ori.y && iy<m)
{des=P(ix,iy+1);ad(1,1,n,-iz);}
}else{
if(iy<ori.y && ix<n)
{des=P(ix+1,iy);ad(1,1,n,-iz);}
else if(iy>=ori.y && ix<n && iy<m)
{des=P(ix+1,iy+1);ad(1,1,n,iz);}
}
ix=ed.x;iy=st.y;
if(ix<ori.x){
if(iy<=ori.y && iy>1)
{des=P(ix,iy-1);ad(1,1,n,-iz);}
else if(iy>ori.y)
{des=P(ix,iy);ad(1,1,n,iz);}
}else{
if(iy<=ori.y && ix<n && iy>1)
{des=P(ix+1,iy-1);ad(1,1,n,iz);}
else if(iy>ori.y && ix<n)
{des=P(ix+1,iy);ad(1,1,n,-iz);}
}
if(st.x<=ori.x && ed.x>=ori.x){
if(st.y>ori.y)
{des=P(ori.x,st.y);ad(1,1,n,iz);}
else if(st.y>1)
{des=P(ori.x,st.y-1);ad(1,1,n,-iz);}
if(ed.y<ori.y)
{des=P(ori.x,ed.y);ad(1,1,n,iz);}
else if(ed.y<m)
{des=P(ori.x,ed.y+1);ad(1,1,n,-iz);}
}
if(st.y<=ori.y && ed.y>=ori.y){
if(st.x>ori.x)
{des=P(st.x,ori.y);ad(1,1,n,iz);}
else if(st.x>1)
{des=P(st.x-1,ori.y);ad(1,1,n,-iz);}
if(ed.x<ori.x)
{des=P(ed.x,ori.y);ad(1,1,n,iz);}
else if(ed.x<n)
{des=P(ed.x+1,ori.y);ad(1,1,n,-iz);}
}
if(st.x<=ori.x && ed.x>=ori.x && st.y<=ori.y && ed.y>=ori.y)
{des=ori;ad(1,1,n,iz);}
}
}
}