先考虑只有一维的情况,要求支持区间加和求区间 \(\gcd\),根据 \(\gcd\) 的性质,发现:

\[ \gcd(a_1,a_2,a_3,\ldots a_n)=\gcd(a_i,a_2-a_1,a_3-a_2,\ldots a_n-a_{n-1})
\]

其中 \(a_i\) 为原序列 \(a\) 中的任意一个元素,其与序列 \(a\) 的差分序列的 \(\gcd\) 即为原序列的 \(\gcd\)。根据该性质,对于一维的情况,就可以通过线段树单点修改维护差分序列,区间查询 \(\gcd\) 来实现了。对于 \(a_i\),根据修改维护其当前值即可。

然后考虑二维的情况,比如对于这样的一个 \(4 \times 4\) 的矩形:

\[\begin{aligned}
a_{1,1}\quad a_{1,2}\quad a_{1,3}\quad a_{1,4} \\
a_{2,1}\quad a_{2,2}\quad a_{2,3}\quad a_{2,4} \\
a_{3,1}\quad a_{3,2}\quad a_{3,3}\quad a_{3,4} \\
a_{4,1}\quad a_{4,2}\quad a_{4,3}\quad a_{4,4}
\end{aligned}
\]

设棋盘守护者的位置为 \((x,y)\),先对每一行进行差分,得:

\[\begin{aligned}
a_{1,y}\quad a_{1,2}-a_{1,1}\quad a_{1,3}-a_{1,2}\quad a_{1,4}-a_{1,3} \\
a_{2,y}\quad a_{2,2}-a_{2,1}\quad a_{2,3}-a_{2,2}\quad a_{2,4}-a_{2,3} \\
a_{3,y}\quad a_{3,2}-a_{3,1}\quad a_{3,3}-a_{3,2}\quad a_{3,4}-a_{3,3} \\
a_{4,y}\quad a_{4,2}-a_{4,1}\quad a_{4,3}-a_{4,2}\quad a_{4,4}-a_{4,3}
\end{aligned}
\]

对每一行来维护差分序列,根据每一行的 \(\gcd\),就能求得整个矩形的 \(\gcd\)。发现这样实现复杂度依然无法接受,于是对每一列也进行差分,也就是进行二维差分,得:

\[\begin{aligned}
&a_{x,y}\qquad\qquad\qquad\quad a_{x,2}-a_{x,1}\qquad\qquad\qquad\quad a_{x,3}-a_{x,2}\qquad\qquad\qquad\quad a_{x,4}-a_{x,3} \\\\
&a_{2,y}-a_{1,y}\qquad a_{2,2}-a_{2,1}-a_{1,2}+a_{1,1}\qquad a_{2,3}-a_{2,2}-a_{1,3}+a_{1,2}\qquad a_{2,4}-a_{2,3}-a_{1,4}+a_{1,3} \\\\
&a_{3,y}-a_{2,y}\qquad a_{3,2}-a_{3,1}-a_{2,2}+a_{2,1}\qquad a_{3,3}-a_{3,2}-a_{2,3}+a_{2,2}\qquad a_{3,4}-a_{3,3}-a_{2,4}+a_{2,3} \\\\
&a_{4,y}-a_{3,y}\qquad a_{4,2}-a_{4,1}-a_{3,2}+a_{3,1}\qquad a_{4,3}-a_{4,2}-a_{3,3}+a_{3,2}\qquad a_{4,4}-a_{4,3}-a_{3,4}+a_{3,3}
\end{aligned}
\]

发现二维差分后的这个矩形的 \(\gcd\) 即为原矩形的 \(\gcd\)。然后考虑维护,对于第一行和第一列,去掉位置 \((1,1)\) 的 \(a_{x,y}\) 后剩下的序列,其为一维上的问题,用两个一维线段树维护即可。对于去掉第一行和第一列的剩下的矩形,用二维线段树维护即可。两者都是只用支持单点修改和区间查询。对于 \(a_{x,y}\),根据修改维护其当前值即可。

二维线段树可以用树套树或者四分树来实现,因为树套树的空间不好处理,并且题目中也说明了查询是随机的,所以我这里用四分树来实现二维线段树了。

\(code:\)

#include<bits/stdc++.h>
#define maxn 2000010
#define maxm 32000010
#define a(i,j) a[(i-1)*m+j]
#define b(i,j) b[(i-1)*m+j]
#define ls (cur<<1)
#define rs (cur<<1|1)
#define mid ((l+r)>>1)
#define midx ((u+d)>>1)
#define midy ((l+r)>>1)
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,m,sx,sy,q,root,rt=1,tree_cnt;
int uls[maxm],urs[maxm],dls[maxm],drs[maxm];
ll w;
ll a[maxn],b[maxn],val[maxm];
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):abs(a);
}
void build(int u,int d,int l,int r,int &cur)
{
if(u>d||l>r) return;
if(!cur) cur=++tree_cnt;
if(u==d&&l==r)
{
val[cur]=b(u,l);
return;
}
build(u,midx,l,midy,uls[cur]),build(u,midx,midy+1,r,urs[cur]);
build(midx+1,d,l,midy,dls[cur]),build(midx+1,d,midy+1,r,drs[cur]);
val[cur]=gcd(gcd(val[uls[cur]],val[urs[cur]]),gcd(val[dls[cur]],val[drs[cur]]));
}
void modify(int u,int d,int l,int r,int x,int y,ll v,int cur)
{
if(l==r&&u==d)
{
val[cur]+=v;
return;
}
if(x<=midx)
{
if(y<=midy) modify(u,midx,l,midy,x,y,v,uls[cur]);
else modify(u,midx,mid+1,r,x,y,v,urs[cur]);
}
else
{
if(y<=midy) modify(midx+1,d,l,midy,x,y,v,dls[cur]);
else modify(midx+1,d,midy+1,r,x,y,v,drs[cur]);
}
val[cur]=gcd(gcd(val[uls[cur]],val[urs[cur]]),gcd(val[dls[cur]],val[drs[cur]]));
}
ll query(int U,int D,int L,int R,int u,int d,int l,int r,int cur)
{
if(U>D||L>R) return 0;
if(U<=u&&D>=d&&L<=l&&R>=r) return val[cur];
ll v=0;
if(U<=midx)
{
if(L<=midy) v=gcd(v,query(U,D,L,R,u,midx,l,midy,uls[cur]));
if(R>midy) v=gcd(v,query(U,D,L,R,u,midx,midy+1,r,urs[cur]));
}
if(D>midx)
{
if(L<=midy) v=gcd(v,query(U,D,L,R,midx+1,d,l,midy,dls[cur]));
if(R>midy) v=gcd(v,query(U,D,L,R,midx+1,d,midy+1,r,drs[cur]));
}
return v;
}
struct Segment_Tree
{
ll a[maxn],val[maxn];
void build(int l,int r,int cur)
{
if(l==r)
{
val[cur]=a[l];
return;
}
build(l,mid,ls),build(mid+1,r,rs);
val[cur]=gcd(val[ls],val[rs]);
}
void modify(int l,int r,int pos,ll v,int cur)
{
if(l==r)
{
val[cur]+=v;
return;
}
if(pos<=mid) modify(l,mid,pos,v,ls);
else modify(mid+1,r,pos,v,rs);
val[cur]=gcd(val[ls],val[rs]);
}
ll query(int L,int R,int l,int r,int cur)
{
if(L>R) return 0;
if(L<=l&&R>=r) return val[cur];
ll v=0;
if(L<=mid) v=gcd(v,query(L,R,l,mid,ls));
if(R>mid) v=gcd(v,query(L,R,mid+1,r,rs));
return v;
}
}T1,T2;
int main()
{
read(n),read(m),read(sx),read(sy),read(q);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
read(a(i,j));
for(int i=1;i<n;++i)
for(int j=1;j<m;++j)
b(i,j)=a(i+1,j+1)-a(i,j+1)-a(i+1,j)+a(i,j);
for(int i=1;i<n;++i) T1.a[i]=a(i+1,sy)-a(i,sy);
for(int i=1;i<m;++i) T2.a[i]=a(sx,i+1)-a(sx,i);
w=a(sx,sy),build(0,n,0,m,root),T1.build(0,n,root),T2.build(0,m,root);
while(q--)
{
int u,d,l,r,opt;
ll v;
read(opt),read(u),read(l),read(d),read(r);
if(!opt)
{
u=sx-u,l=sy-l,d=sx+d,r=sy+r;
v=gcd(w,query(u,d-1,l,r-1,0,n,0,m,root));
v=gcd(v,gcd(T1.query(u,d-1,0,n,rt),T2.query(l,r-1,0,m,rt)));
printf("%lld\n",v);
}
else
{
read(v);
if(sx>=u&&sx<=d&&sy>=l&&sy<=r) w+=v;
if(sy>=l&&sy<=r) T1.modify(0,n,u-1,v,rt),T1.modify(0,n,d,-v,rt);
if(sx>=u&&sx<=d) T2.modify(0,m,l-1,v,rt),T2.modify(0,m,r,-v,rt);
modify(0,n,0,m,u-1,l-1,v,root),modify(0,n,0,m,d,r,v,root);
modify(0,n,0,m,u-1,r,-v,root),modify(0,n,0,m,d,l-1,-v,root);
}
}
return 0;
}

题解 洛谷 P2086 【[NOI2012]魔幻棋盘】的更多相关文章

  1. BZOJ2877:[NOI2012]魔幻棋盘

    浅谈树状数组与主席树:https://www.cnblogs.com/AKMer/p/9946944.html 题目传送门:https://lydsy.com/JudgeOnline/problem. ...

  2. 题解 洛谷P5018【对称二叉树】(noip2018T4)

    \(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...

  3. 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...

  4. 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)

    题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...

  5. 题解-洛谷P4229 某位歌姬的故事

    题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...

  6. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

  7. 题解-洛谷P4859 已经没有什么好害怕的了

    洛谷P4859 已经没有什么好害怕的了 给定 \(n\) 和 \(k\),\(n\) 个糖果能量 \(a_i\) 和 \(n\) 个药片能量 \(b_i\),每个 \(a_i\) 和 \(b_i\) ...

  8. 题解-洛谷P5217 贫穷

    洛谷P5217 贫穷 给定长度为 \(n\) 的初始文本 \(s\),有 \(m\) 个如下操作: \(\texttt{I x c}\),在第 \(x\) 个字母后面插入一个 \(c\). \(\te ...

  9. 洛谷 P1169||bzoj1057 [ZJOI2007]棋盘制作

    洛谷P1169 bzoj1057 这个题目跟最大全0子矩阵是类似的.正方形的话,只要把任意极大子正方形(”极大“定义见后面的”论文“)当成把某个极大子矩形去掉一块变成正方形即可,容易解决. 解法1:看 ...

随机推荐

  1. 搜索引擎ElasticSearch入门

    前言 最近项目上需要用到搜索引擎,由于之前自己没有了解过,所以整理了一下搜索引擎的相关概念知识. 正文 想查数据就免不了搜索,搜索就离不开搜索引擎,百度.谷歌都是一个非常庞大复杂的搜索引擎,他们几乎索 ...

  2. jQuery实现全选、反选、删除

    <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content ...

  3. C# MVC LayUI实现下拉框二级联动

    一.layui.use 1.LayUI的官方使用文档:https://www.layui.com/doc/ 2.layui的内置模块不是默认就加载好的,必须要执行启动模块的这种方法后模块才会加载: 3 ...

  4. AbstractQueuedSynchronizer和ReentranLock基本原理

    先把我主要学习参考的文章放上来先,这篇文章讲的挺好的,分析比较到位,最好是先看完这篇文章,在接下去看我写的.不然你会一脸懵逼,不过等你看完这篇文章,可能我的文章对你也用途不大了 深入分析Abstrac ...

  5. Spring Redis开启事务支持错误用法导致服务不可用

      1.事故背景 在APP访问服务器接口时需要从redis中获取token进行校验,服务器上线后发现一开始可以正常访问,但只要短时间内请求量增长服务则无法响应 2.排查流程 (1)使用top指令查看C ...

  6. 《Java核心技术(卷1)》笔记:第8章 泛型程序设计

    (P 327)"菱形"语法: ArrayList<String> files = new ArrayList<>(); // Java 9 扩展了菱形语法的 ...

  7. Centos7安装部署openstack--nova计算服务

    一.概述 使用OpenStack计算服务来托管和管理云计算系统.OpenStack计算服务是基础设施即服务(IaaS)系统的主要部分,模块主要由Python实现. OpenStack计算组件请求Ope ...

  8. .Net Core 集成ExceptionLess分布式日志框架之本地化部署

    前言 公司目前使用的项目中关于日志记录这块,之前一直都是使用的Log4net 存放于后台文件中的,对于异常错误啊,或者需要查看一些详情错误的时候感觉很不方便,要到服务器上去打开日志文件检索错误,降低了 ...

  9. Linux中more和less的区别

    more的源码量大约2000行: less的源码量大约27000行: more历史比less久: less功能比more多: 其实本质没啥太大区别,都是为了查看文件方便. (完)

  10. " 橘松 " 的自我介绍

    昵称:(OrangeCsong)橘松(在其他平台也是这个名字) 年龄:95后(摩羯座) 性别:boy 性格:性格还阔以,不轻易发脾气,沉稳.喜欢独立思考. 爱好:运动(工作了,运动时间太少),基金理财 ...