【二维线段树(二维区间GCD)】[NOI2012]魔幻棋盘
题目描述
分析
这是经典的区间
差分GCD
所以区间
一维区间GCD
维护区间信息首选线段树,但是区间
二维区间GCD
我们沿着一维区间
假设
二维区间
现在,我们有一个想法,是不是用二维线段树维护一个从左上角到右下角的差分数组
我们仔细想一下这个应该怎么做。
每次,我们要求一个二维区间的gcd,假设下图是要求的区间。
显然,白色部分是原数组的一个元素的值,很好维护,红色部分是一个二维差分,每次单点修改即可,但是绿色部分是一个一维差分,要维护的话就必须区间修改(修改一个区间内的一维线段树)。显然,二维线段树不能区间修改,所以这样不可行。
我们发现,有一个点是固定的的,我们就可以这个点为中心维护差分数组。
我们只需要维护八棵独立的线段树(四棵二维,四棵一维)就可以做到每次修改都是单点修改了。
代码
略长
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MAXN 500000
using namespace std;
typedef long long LL;
int n,m,x,y,T;
LL a[MAXN+10];
inline int Get_id(int i,int j){
return (i-1)*m+j;
}
template<class T>
void Read(T &x){
static char c;
bool f(0);
while(c=getchar(),c!=EOF){
if(c=='-')
f=1;
else if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
if(f)
x=-x;
return;
}
}
}
LL gcd(LL a,LL b){
LL t;
while(b){
t=a%b;
a=b;
b=t;
}
return a;
}
namespace SegmentTree1D{
struct node{
LL d;
node *ch[2];
}tree[MAXN*20+10],*tcnt=tree,*root[4];
inline void update(node *p){
p->d=gcd(p->ch[0]->d,p->ch[1]->d);
}
void build(node *&p,int l,int r,int x){
p=++tcnt;
if(l==r){
p->d=a[Get_id(x,l)];
return;
}
int mid((l+r)>>1);
build(p->ch[0],l,mid,x);
build(p->ch[1],mid+1,r,x);
update(p);
}
void build_col(node *&p,int l,int r){
p=++tcnt;
if(l==r){
p->d=a[Get_id(l,y)];
return;
}
int mid((l+r)>>1);
build_col(p->ch[0],l,mid);
build_col(p->ch[1],mid+1,r);
update(p);
}
void build_notleaf(node *&p,node *x,node *y,int l,int r){
p=++tcnt;
if(l==r){
p->d=gcd(x->d,y->d);
return;
}
int mid((l+r)>>1);
build_notleaf(p->ch[0],x->ch[0],y->ch[0],l,mid);
build_notleaf(p->ch[1],x->ch[1],y->ch[1],mid+1,r);
update(p);
}
void insert(node *p,int l,int r,int pos,LL d){
if(l==r){
p->d+=d;
return;
}
int mid((l+r)>>1);
if(pos<=mid)
insert(p->ch[0],l,mid,pos,d);
else
insert(p->ch[1],mid+1,r,pos,d);
update(p);
}
void insert_notleaf(node *p,int l,int r,int pos,LL val){
if(l==r){
p->d=val;
return;
}
int mid((l+r)>>1);
if(pos<=mid)
insert_notleaf(p->ch[0],l,mid,pos,val);
else
insert_notleaf(p->ch[1],mid+1,r,pos,val);
update(p);
}
LL get_gcd(node *p,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr)
return p->d;
if(ll>r||rr<l)
return 0;
int mid((l+r)>>1);
return gcd(get_gcd(p->ch[0],l,mid,ll,rr),get_gcd(p->ch[1],mid+1,r,ll,rr));
}
}
namespace SegmentTree2D{
using namespace SegmentTree1D;
struct node{
SegmentTree1D::node *root;
node *ch[2];
}tree[MAXN*4+10],*tcnt=tree,*root[4];
inline void update(node *p,int al,int ar,int pos){
insert_notleaf(p->root,al,ar,pos,gcd(get_gcd(p->ch[0]->root,al,ar,pos,pos),get_gcd(p->ch[1]->root,al,ar,pos,pos)));
}
inline void build_merge(node *p,int al,int ar){
build_notleaf(p->root,p->ch[0]->root,p->ch[1]->root,al,ar);
}
void build(node *&p,int l,int r,int al,int ar){
p=++tcnt;
if(l==r){
build(p->root,al,ar,l);
return;
}
int mid((l+r)>>1);
build(p->ch[0],l,mid,al,ar);
build(p->ch[1],mid+1,r,al,ar);
build_merge(p,al,ar);
}
void insert(node *p,int l,int r,int al,int ar,int x,int y,LL d){
if(l==r){
insert(p->root,al,ar,y,d);
return;
}
int mid((l+r)>>1);
if(x<=mid)
insert(p->ch[0],l,mid,al,ar,x,y,d);
else
insert(p->ch[1],mid+1,r,al,ar,x,y,d);
update(p,al,ar,y);
}
LL get_gcd(node *p,int l,int r,int al,int ar,int lx,int rx,int ly,int ry){
if(lx<=l&&r<=rx)
return get_gcd(p->root,al,ar,ly,ry);
if(lx>r||rx<l)
return 0;
int mid((l+r)>>1);
return gcd(get_gcd(p->ch[0],l,mid,al,ar,lx,rx,ly,ry),get_gcd(p->ch[1],mid+1,r,al,ar,lx,rx,ly,ry));
}
}
void read(){
Read(n),Read(m),Read(x),Read(y),Read(T);
int i,t=n*m,j;
for(i=1;i<=t;i++)
Read(a[i]);
//左
if(y>1){
for(j=1;j<y-1;j++)
a[Get_id(x,j)]-=a[Get_id(x,j+1)];
SegmentTree1D::build(SegmentTree1D::root[0],1,y-1,x);
}
//右
if(y<m){
for(j=m;j>y+1;j--)
a[Get_id(x,j)]-=a[Get_id(x,j-1)];
SegmentTree1D::build(SegmentTree1D::root[1],y+1,m,x);
}
//上
if(x>1){
for(i=1;i<x-1;i++)
a[Get_id(i,y)]-=a[Get_id(i+1,y)];
SegmentTree1D::build_col(SegmentTree1D::root[2],1,x-1);
}
//下
if(x<n){
for(i=n;i>x+1;i--)
a[Get_id(i,y)]-=a[Get_id(i-1,y)];
SegmentTree1D::build_col(SegmentTree1D::root[3],x+1,n);
}
//左上
if(x>1&&y>1){
for(i=1;i<x-1;i++){
for(j=1;j<y-1;j++)
a[Get_id(i,j)]-=a[Get_id(i+1,j)]+a[Get_id(i,j+1)]-a[Get_id(i+1,j+1)];
a[Get_id(i,y-1)]-=a[Get_id(i+1,y-1)];
}
for(j=1;j<y-1;j++)
a[Get_id(x-1,j)]-=a[Get_id(x-1,j+1)];
SegmentTree2D::build(SegmentTree2D::root[0],1,x-1,1,y-1);
}
//右上
if(x>1&&y<m){
for(i=1;i<x-1;i++){
for(j=m;j>y+1;j--)
a[Get_id(i,j)]-=a[Get_id(i+1,j)]+a[Get_id(i,j-1)]-a[Get_id(i+1,j-1)];
a[Get_id(i,y+1)]-=a[Get_id(i+1,y+1)];
}
for(j=m;j>y+1;j--)
a[Get_id(x-1,j)]-=a[Get_id(x-1,j-1)];
SegmentTree2D::build(SegmentTree2D::root[1],1,x-1,y+1,m);
}
//左下
if(x<n&&y>1){
for(i=n;i>x+1;i--){
for(j=1;j<y-1;j++)
a[Get_id(i,j)]-=a[Get_id(i-1,j)]+a[Get_id(i,j+1)]-a[Get_id(i-1,j+1)];
a[Get_id(i,y-1)]-=a[Get_id(i-1,y-1)];
}
for(j=1;j<y-1;j++)
a[Get_id(x+1,j)]-=a[Get_id(x+1,j+1)];
SegmentTree2D::build(SegmentTree2D::root[2],x+1,n,1,y-1);
}
//右下
if(x<n&&y<m){
for(i=n;i>x+1;i--){
for(j=m;j>y+1;j--)
a[Get_id(i,j)]-=a[Get_id(i-1,j)]+a[Get_id(i,j-1)]-a[Get_id(i-1,j-1)];
a[Get_id(i,y+1)]-=a[Get_id(i-1,y+1)];
}
for(j=m;j>y+1;j--)
a[Get_id(x+1,j)]-=a[Get_id(x+1,j-1)];
SegmentTree2D::build(SegmentTree2D::root[3],x+1,n,y+1,m);
}
}
void solve(){
int p,x1,y1,x2,y2,tx1,ty1,tx2,ty2;
LL ans,d;
while(T--){
Read(p),Read(x1),Read(y1),Read(x2),Read(y2);
if(p){
Read(d);
if(x1<=x&&x2>=x&&y1<=y&&y2>=y)
a[Get_id(x,y)]+=d;
//左上
if(x1<x&&y1<y){
tx2=min(x-1,x2),ty2=min(y-1,y2);
SegmentTree2D::insert(SegmentTree2D::root[0],1,x-1,1,y-1,tx2,ty2,d);
if(x1>1&&y1>1)
SegmentTree2D::insert(SegmentTree2D::root[0],1,x-1,1,y-1,x1-1,y1-1,d);
if(x1>1)
SegmentTree2D::insert(SegmentTree2D::root[0],1,x-1,1,y-1,x1-1,ty2,-d);
if(y1>1)
SegmentTree2D::insert(SegmentTree2D::root[0],1,x-1,1,y-1,tx2,y1-1,-d);
}
//右上
if(x1<x&&y2>y){
tx2=min(x-1,x2),ty1=max(y+1,y1);
SegmentTree2D::insert(SegmentTree2D::root[1],1,x-1,y+1,m,tx2,ty1,d);
if(x1>1&&y2<m)
SegmentTree2D::insert(SegmentTree2D::root[1],1,x-1,y+1,m,x1-1,y2+1,d);
if(x1>1)
SegmentTree2D::insert(SegmentTree2D::root[1],1,x-1,y+1,m,x1-1,ty1,-d);
if(y2<m)
SegmentTree2D::insert(SegmentTree2D::root[1],1,x-1,y+1,m,tx2,y2+1,-d);
}
//左下
if(x2>x&&y1<y){
tx1=max(x1,x+1),ty2=min(y-1,y2);
SegmentTree2D::insert(SegmentTree2D::root[2],x+1,n,1,y-1,tx1,ty2,d);
if(x2<n&&y1>1)
SegmentTree2D::insert(SegmentTree2D::root[2],x+1,n,1,y-1,x2+1,y1-1,d);
if(x2<n)
SegmentTree2D::insert(SegmentTree2D::root[2],x+1,n,1,y-1,x2+1,ty2,-d);
if(y1>1)
SegmentTree2D::insert(SegmentTree2D::root[2],x+1,n,1,y-1,tx1,y1-1,-d);
}
//右下
if(x2>x&&y2>y){
tx1=max(x1,x+1),ty1=max(y1,y+1);
SegmentTree2D::insert(SegmentTree2D::root[3],x+1,n,y+1,m,tx1,ty1,d);
if(x2<n&&y2<m)
SegmentTree2D::insert(SegmentTree2D::root[3],x+1,n,y+1,m,x2+1,y2+1,d);
if(x2<n)
SegmentTree2D::insert(SegmentTree2D::root[3],x+1,n,y+1,m,x2+1,ty1,-d);
if(y2<m)
SegmentTree2D::insert(SegmentTree2D::root[3],x+1,n,y+1,m,tx1,y2+1,-d);
}
if(x1<=x&&x2>=x){
//左
if(y1<y){
ty2=min(y2,y-1);
SegmentTree1D::insert(SegmentTree1D::root[0],1,y-1,ty2,d);
if(y1>1)
SegmentTree1D::insert(SegmentTree1D::root[0],1,y-1,y1-1,-d);
}
//右
if(y2>y){
ty1=max(y1,y+1);
SegmentTree1D::insert(SegmentTree1D::root[1],y+1,m,ty1,d);
if(y2<m)
SegmentTree1D::insert(SegmentTree1D::root[1],y+1,m,y2+1,-d);
}
}
if(y1<=y&&y2>=y){
//上
if(x1<x){
tx2=min(x2,x-1);
SegmentTree1D::insert(SegmentTree1D::root[2],1,x-1,tx2,d);
if(x1>1)
SegmentTree1D::insert(SegmentTree1D::root[2],1,x-1,x1-1,-d);
}
//下
if(x2>x){
tx1=max(x+1,x1);
SegmentTree1D::insert(SegmentTree1D::root[3],x+1,n,tx1,d);
if(x2<n)
SegmentTree1D::insert(SegmentTree1D::root[3],x+1,n,x2+1,-d);
}
}
}
else{
ans=a[Get_id(x,y)];
if(x>1&&y>1)
ans=gcd(SegmentTree2D::get_gcd(SegmentTree2D::root[0],1,x-1,1,y-1,x-x1,x+x2,y-y1,y+y2),ans);
if(x>1&&y<m)
ans=gcd(SegmentTree2D::get_gcd(SegmentTree2D::root[1],1,x-1,y+1,m,x-x1,x+x2,y-y1,y+y2),ans);
if(x<n&&y>1)
ans=gcd(SegmentTree2D::get_gcd(SegmentTree2D::root[2],x+1,n,1,y-1,x-x1,x+x2,y-y1,y+y2),ans);
if(x<n&&y<m)
ans=gcd(SegmentTree2D::get_gcd(SegmentTree2D::root[3],x+1,n,y+1,m,x-x1,x+x2,y-y1,y+y2),ans);
if(y>1)
ans=gcd(SegmentTree1D::get_gcd(SegmentTree1D::root[0],1,y-1,y-y1,y+y2),ans);
if(y<m)
ans=gcd(SegmentTree1D::get_gcd(SegmentTree1D::root[1],y+1,m,y-y1,y+y2),ans);
if(x>1)
ans=gcd(SegmentTree1D::get_gcd(SegmentTree1D::root[2],1,x-1,x-x1,x+x2),ans);
if(x<n)
ans=gcd(SegmentTree1D::get_gcd(SegmentTree1D::root[3],x+1,n,x-x1,x+x2),ans);
printf("%lld\n",abs(ans));
}
}
}
int main()
{
read();
solve();
}