您的位置:首页 > 其它

bzoj2877 [Noi2012]魔幻棋盘 二维线段树

2017-07-02 20:17 363 查看
题目大意:

维护一个矩阵支持两个操作:

0、查询子矩形gcd。

1、子矩形整体加一个值。

所有的询问都会一定包含同一个点。

题目分析:

PoPoQQQ讲解的非常好啊这个……

二维线段树可以资磁子矩形查询,但是它不资磁子矩形修改啊orz

由于gcd(a,b)=gcd(a-b,b),所以我们可以考虑差分。

但是上面这个式子使用是有前提的,就是把一些数差分之后,其中必须有一个数时原数才行,恰好所有询问都包含同一个点,那就把这个点作为中心来差分,至于如何二维差分这个问题,就是先把每一行以y为中心差分一下,再把每一列以x为中心差分一下,就行了。

然后修改从区间修改变成了单点修改。

然后分成21种情况讨论一下要修改的点是哪些就可以了。

其实这个题思路到没有多难,就是讨论起来太恶心了orz……

代码如下:

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <ctime>
#define N 520000
using namespace std;
typedef long long LL;
inline LL Abs(LL x) { return x<0?-x:x; }
LL gcd(LL a,LL b) { return b?gcd(b,a%b):a; }
int n,m,sx,sy,T;
class Array{
private:
LL memory
;
public:
LL* operator [] (int c)
{
return &memory[(c-1)*m];
}
}a;
struct segy{
segy *ls,*rs;
LL val;
void* operator new (size_t size);
};
void* segy :: operator new (size_t size)
{
static segy *C=NULL,*mempool=NULL;
if(C==mempool)
{
mempool=(C=new segy[1<<15])+(1<<15);
memset(C,0,sizeof(segy)*(1<<15));
}
return C++;
}
void build_tree(segy *&c,int l,int r,int x)
{
c=new segy;
if(l==r)
{
c->val=x?a[x][l]:0;
return;
}
int mid=l+r>>1;
build_tree(c->ls,l,mid,x);
build_tree(c->rs,mid+1,r,x);
c->val=x?gcd(c->ls->val,c->rs->val):0;
}
void update(segy *&c,int l,int r,int x,LL y)
{
if(l==r)
{
c->val+=y;
return;
}
int mid=l+r>>1;
if(x<=mid) update(c->ls,l,mid,x,y);
else update(c->rs,mid+1,r,x,y);
c->val=gcd(c->ls->val,c->rs->val);
}
LL query(segy *c,int l,int r,int x,int y)
{
if(x<=l && y>=r) return c->val;
int mid=l+r>>1;
if(y<=mid) return query(c->ls,l,mid,x,y);
if(x>mid) return query(c->rs,mid+1,r,x,y);
return gcd(query(c->ls,l,mid,x,y),query(c->rs,mid+1,r,x,y));
}
void Merge(segy *&c,segy *x,segy *y,int l,int r)
{
c->val=gcd(x->val,y->val);
if(l==r) return;
int mid=l+r>>1;
Merge(c->ls,x->ls,y->ls,l,mid);
Merge(c->rs,x->rs,y->rs,mid+1,r);
}
void Merge(segy *&c,segy *x,segy *y,int l,int r,int z)
{
c->val=gcd(x->val,y->val);
if(l==r) return;
int mid=l+r>>1;
if(z<=mid) Merge(c->ls,x->ls,y->ls,l,mid,z);
else Merge(c->rs,x->rs,y->rs,mid+1,r,z);
}
struct segx{
segx *ls,*rs;
segy *tree;
void* operator new (size_t size);
}*root;
void* segx :: operator new(size_t size)
{
static segx *C=NULL,*mempool=NULL;
if(C==mempool)
{
mempool=(C=new segx[1<<15])+(1<<15);
memset(C,0,sizeof(segx)*(1<<15));
}
return C++;
}
void build_tree(segx *&c,int l,int r)
{
c=new segx;
build_tree(c->tree,1,m,l==r?l:0);
if(l==r) return;
int mid=l+r>>1;
build_tree(c->ls,l,mid);
build_tree(c->rs,mid+1,r);
Merge(c->tree,c->ls->tree,c->rs->tree,1,m);
}
void update(segx *c,int l,int r,int x,int y,LL z)
{
if(l==r)
{
update(c->tree,1,m,y,z);
return;
}
int mid=l+r>>1;
if(x<=mid) update(c->ls,l,mid,x,y,z);
else update(c->rs,mid+1,r,x,y,z);
Merge(c->tree,c->ls->tree,c->rs->tree,1,m,y);
}
LL query(segx *c,int l,int r,int x1,int x2,int y1,int y2)
{
if(x1<=l && x2>=r) return query(c->tree,1,m,y1,y2);
int mid=l+r>>1;
if(x2<=mid) return query(c->ls,l,mid,x1,x2,y1,y2);
if(x1>mid) return query(c->rs,mid+1,r,x1,x2,y1,y2);
return gcd(query(c->ls,l,mid,x1,x2,y1,y2),query(c->rs,mid+1,r,x1,x2,y1,y2));
}
inline void update(int x,int y,LL z) { if(x>=1 && x<=n && y>=1 && y<=m) update(root,1,n,x,y,z); }
int main()
{
scanf("%d%d",&n,&m);
scanf("%d%d",&sx,&sy);
scanf("%d",&T);
int X1,X2,Y1,Y2,opt;
LL c;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%lld",&a[i][j]);
for(int i=1;i<=n;i++)
{
for(int j=1;j<sy;j++) a[i][j]=a[i][j]-a[i][j+1];
for(int j=m;j>sy;j--) a[i][j]=a[i][j]-a[i][j-1];
}
for(int j=1;j<=m;j++)
{
for(int i=1;i<sx;i++) a[i][j]=a[i][j]-a[i+1][j];
for(int i=n;i>sx;i--) a[i][j]=a[i][j]-a[i-1][j];
}
build_tree(root,1,n);
for(int i=1;i<=T;i++)
{
scanf("%d%d%d%d%d",&opt,&X1,&Y1,&X2,&Y2);
if(opt)
{
scanf("%lld",&c);
if(X1<=sx && Y1<=sy && X2>=sx && Y2>=sy) update(sx,sy,c);
if(Y1<=sy && Y2>=sy)
{
if(X1<=sx) update(X1-1,sy,-c);
else update(X1,sy,c);
if(X2>=sx) update(X2+1,sy,-c);
else update(X2,sy,c);
}
if(X1<=sx && X2>=sx)
{
if(Y1<=sy) update(sx,Y1-1,-c);
else update(sx,Y1,c);
if(Y2>=sy) update(sx,Y2+1,-c);
else update(sx,Y2,c);
}
if(X1<=sx && Y1<=sy) update(X1-1,Y1-1,c);
else if(X1<=sx && Y1>sy) update(X1-1,Y1,-c);
else if(X1>sx && Y1<=sy) update(X1,Y1-1,-c);
else update(X1,Y1,c);
if(X1<=sx && Y2<sy) update(X1-1,Y2,-c);
else if(X1<=sx && Y2>=sy) update(X1-1,Y2+1,c);
else if(X1>sx && Y2<sy) update(X1,Y2,c);
else update(X1,Y2+1,-c);
if(X2<sx && Y1<=sy) update(X2,Y1-1,-c);
else if(X2<sx && Y1>sy) update(X2,Y1,c);
else if(X2>=sx && Y1<=sy) update(X2+1,Y1-1,c);
else update(X2+1,Y1,-c);
if(X2<sx && Y2<sy) update(X2,Y2,c);
else if(X2<sx && Y2>=sy) update(X2,Y2+1,-c);
else if(X2>=sx && Y2<sy) update(X2+1,Y2,-c);
else update(X2+1,Y2+1,c);
}
else printf("%lld\n",Abs(query(root,1,n,sx-X1,sx+X2,sy-Y1,sy+Y2)));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: