您的位置:首页 > 其它

【二维线段树(二维区间GCD)】[NOI2012]魔幻棋盘

2016-07-09 13:35 363 查看

题目描述


将要读二年级的小Q买了一款新型益智玩具——魔幻棋盘,它是一个N行M列的网格棋盘,每个格子中均有一个正整数。棋盘守护者在棋盘的第X行第Y列(行与列均从 1 开始编号)并且始终不会移动。棋盘守护者会进行两种操作: (a)询问:他会以自己所在位置为基础,向四周随机扩展出一块大小不定的矩形区域,向你询问这一区域内所有数的最大公约数是多少。 (b)修改:他会随意挑选棋盘上的一块矩形区域,将这一区域内的所有数同时加上一个给定的整数。 游戏说明书上附有这样一句话“聪明的小朋友,当你连续答对 19930324 次询问后会得到一个惊喜噢!”。小Q十分想得到这个惊喜,于是每天都在玩这个玩具。但由于他粗心大意,经常算错数,难以达到这个目标。于是他来向你寻求帮助,希望你帮他写一个程序来回答棋盘守护者的询问,并保证 100% 的正确率。 为了简化问题,你的程序只需要完成棋盘守护者的T次操作,并且问题保证任何时刻棋盘上的数字均为不超过 2^62-1 的正整数。 " title="">


第一行为两个正整数N, M,表示棋盘的大小。 第二行为两个正整数 X,Y,表示棋盘守护者的位置。 第三行仅有一个正整数T,表示棋盘守护者将进行T次操作。 接下来N行,每行有M个正整数,用来描述初始时棋盘上每个位置的数。 接下来T行,按操作的时间顺序给出T次操作。每行描述一次操作,以一个数字0或1开头: 若以数字0开头,表示此操作为询问,随后会有四个非负整数 X1,Y1,X2,Y2表示询问的区域是以棋盘守护者的位置为基础向上扩展X1行,向下扩展 X2行,向左扩展 Y1列,向右扩展 Y2列得到的矩形区域(详见样例)。 若以数字1开头,表示此操作为修改,随后会有四个正整数 X1,Y1,X2,Y2和一个整数C,表示修改区域的上、下边界分别为第X1,X2行,左,右边界分别为第y1,y2列(详见样例),在此矩形区域内的所有数统一加上 c(注意 c 可能为负数)。

输出

对于每次询问操作,每行输出一个数,表示该区域内所有数的最大公约数。 " title="">

分析

这是经典的区间gcd(最大公约数)问题。

差分GCD

gcd(a,b)gcd(a,b,c)=gcd(a,b−ka)=gcd(gcd(a,b),c)=gcd(gcd(a,b−a),c)=gcd(gcd(a,b−a),c−k(gcd(a,b−a)))=gcd(gcd(a,b−a),c−b)

所以区间[l,r]的最大公约数等于其差分和第一个数的最大公约数,假设a为原数组,di=ai−ai−1,所以

gcd(al,al+1,al+2,…,ar)=gcd(gcd(dl+1,dl+2,…,dr),al)

一维区间GCD

维护区间信息首选线段树,但是区间gcd显然没有办法打懒标记,因为下传的时候显然不知道如何修改gcd信息,所以不能有区间修改。但是原数组的区间修改对应差分数组的单点修改,所以我们用一棵线段树维护差分数组区间gcd,然后再用一个数据结构(线段树、差分数组的树状数组……)维护原数组即可。

二维区间GCD

我们沿着一维区间gcd继续思考。

假设a,b,c,d的相对位置是acbd

gcd(a,b,c,d)=gcd(gcd(gcd(a,b),c),d)=gcd(gcd(gcd(a,b−a),c−a),d−k(gcd(gcd(a,b−a),c−a)))=gcd(gcd(gcd(a,b−a),c−a),d−b−c+a)

二维区间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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: