bzoj2877 [Noi2012]魔幻棋盘 二维线段树
2017-07-02 20:17
363 查看
题目大意:
维护一个矩阵支持两个操作:
0、查询子矩形gcd。
1、子矩形整体加一个值。
所有的询问都会一定包含同一个点。
题目分析:
PoPoQQQ讲解的非常好啊这个……
二维线段树可以资磁子矩形查询,但是它不资磁子矩形修改啊orz
由于gcd(a,b)=gcd(a-b,b),所以我们可以考虑差分。
但是上面这个式子使用是有前提的,就是把一些数差分之后,其中必须有一个数时原数才行,恰好所有询问都包含同一个点,那就把这个点作为中心来差分,至于如何二维差分这个问题,就是先把每一行以y为中心差分一下,再把每一列以x为中心差分一下,就行了。
然后修改从区间修改变成了单点修改。
然后分成21种情况讨论一下要修改的点是哪些就可以了。
其实这个题思路到没有多难,就是讨论起来太恶心了orz……
代码如下:
维护一个矩阵支持两个操作:
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; }
相关文章推荐
- BZOJ 2877 NOI2012 魔幻棋盘 二维线段树
- [BZOJ2877][Noi2012]魔幻棋盘 && 二维线段树+差分
- bzoj2877 [Noi2012]魔幻棋盘 [二维线段树]
- 2877: [Noi2012]魔幻棋盘 - BZOJ
- 【bzoj2877】 Noi2012—魔幻棋盘
- 数据结构(二维线段树,差分): NOI2012 魔幻棋盘
- BZOJ2877 [Noi2012]魔幻棋盘
- bzoj 2877: [Noi2012]魔幻棋盘
- 【二维线段树(二维区间GCD)】[NOI2012]魔幻棋盘
- BZOJ2875: [Noi2012]随机数生成器 矩阵乘法+快速乘
- bzoj 2733: [HNOI2012]永无乡 -- 线段树
- BZOJ 2875 [Noi2012] 随机数生成器 题解与分析
- bzoj2875 [Noi2012]随机数生成器 [矩阵+快乘]
- [bzoj2434][ac自动机][线段树合并][Noi2011]阿狸的打字机
- [线段树优化 DP] BZOJ 3242 [Noi2013]快餐店
- [BZOJ4059][Cerc2012]Non-boring sequences(扫描线+线段树||暴力分治)
- BZOJ 3022 [Balkan2012]The Best Teams(扫描线+线段树)
- BZOJ4785 ZJOI2017树状数组(概率+二维线段树)
- 【BZOJ】【2879】【NOI2012】美食节
- BZOJ2876 [Noi2012]骑行川藏