http://www.lydsy.com/JudgeOnline/problem.php?id=2877 (题目链接)

题意

  一个${n*m}$的矩阵,维护两个操作:给任意子矩阵${+val}$;问某一包含点${(X,Y)}$的矩阵内元素的gcd。

Solution

  左转题解,参见PoPoQQQ,写的蛮详细的,像我这种没写过树套树的都会了→_→。

  代码也是模着PoPoQQQ大爷的写的,边界真的好蛋疼。

  对于不能用以任意一点为差分中心的原因,我有一点自己的看法。我们考虑之所以差分后的数组的gcd与原数组的gcd相等是为什么,不是更相减损吗,考虑一维的情况,如果我们本来要求${gcd(a_2,a_3,a_4,a_5)}$,我们以${a_1}$为中心差分的话,那么就成了求解差分数组的${gcd(a_2-a_1,a_3-a_2,a_4-a_3,a_5-a_4)}$,这就不符合更相减损术了,因为里面莫名其妙混进了个${a_1}$。为了避免这种情况,我们以一定包含在询问矩阵内的${(X,Y)}$为中心差分,这就保证了差分后每一个询问矩阵中不包含在矩阵外的原矩阵的元素。也就是说,如果没有${(X,Y)}$一定包含在询问矩阵中这个条件的话,这个题应该是做不了的。

细节

  这里并没有给出${n,m}$的具体范围,所以我们需要使用黑科技读入矩阵。

  LL,边界的分类讨论注意别写错点的坐标。

代码

// bzoj2877
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=500010;
int n,m,Q,X,Y,rt,sz; struct segtree {int l,r,ls,rs,tree;LL val;}tr[maxn<<4];
struct array { //来自PoPoQQQ的黑科技
LL t[maxn];
LL* operator [] (int x) {return &t[(x-1)*m];}
}a; LL gcd(LL a,LL b) {
return b==0 ? a : gcd(b,a%b);
} namespace Col {
void build(int &k,int s,int t,int p) {
k=++sz;tr[k].l=s,tr[k].r=t;
if (s==t) {tr[k].val=a[p][s];return;}
int mid=(s+t)>>1;
build(tr[k].ls,s,mid,p);
build(tr[k].rs,mid+1,t,p);
tr[k].val=gcd(tr[tr[k].ls].val,tr[tr[k].rs].val);
}
void modify(int k,int p,LL val) {
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
if (l==r) {tr[k].val+=val;return;}
if (p<=mid) modify(tr[k].ls,p,val);
else modify(tr[k].rs,p,val);
tr[k].val=gcd(tr[tr[k].ls].val,tr[tr[k].rs].val);
}
LL query(int k,int s,int t) {
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
if (l==s && r==t) return tr[k].val;
if (t<=mid) return query(tr[k].ls,s,t);
else if (s>mid) return query(tr[k].rs,s,t);
else return gcd(query(tr[k].ls,s,mid),query(tr[k].rs,mid+1,t));
}
} namespace Row {
void merge(int &k,int k1,int k2,int s,int t) {
if (!k) k=++sz,tr[k].l=s,tr[k].r=t;
int mid=(s+t)>>1;
if (s==t) {tr[k].val=gcd(tr[k1].val,tr[k2].val);return;}
merge(tr[k].ls,tr[k1].ls,tr[k2].ls,s,mid);
merge(tr[k].rs,tr[k1].rs,tr[k2].rs,mid+1,t);
tr[k].val=gcd(tr[tr[k].ls].val,tr[tr[k].rs].val);
}
void build(int &k,int s,int t) {
k=++sz;tr[k].l=s,tr[k].r=t;
if (s==t) {Col::build(tr[k].tree,1,m,s);return;}
int mid=(s+t)>>1;
build(tr[k].ls,s,mid);
build(tr[k].rs,mid+1,t);
merge(tr[k].tree,tr[tr[k].ls].tree,tr[tr[k].rs].tree,1,m);
}
void modify(int k,int x,int y,LL val) {
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
if (l==r) {Col::modify(tr[k].tree,y,val);return;}
if (x<=mid) modify(tr[k].ls,x,y,val);
else modify(tr[k].rs,x,y,val);
LL lval=Col::query(tr[tr[k].ls].tree,y,y);
LL rval=Col::query(tr[tr[k].rs].tree,y,y);
LL mval=Col::query(tr[k].tree,y,y);
Col::modify(tr[k].tree,y,gcd(lval,rval)-mval);
}
LL query(int k,int x1,int y1,int x2,int y2) {
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
if (l==x1 && r==x2) return Col::query(tr[k].tree,y1,y2);
if (x2<=mid) return query(tr[k].ls,x1,y1,x2,y2);
else if (x1>mid) return query(tr[k].rs,x1,y1,x2,y2);
else return gcd(query(tr[k].ls,x1,y1,mid,y2),query(tr[k].rs,mid+1,y1,x2,y2));
}
}
using namespace Row; int main() {
scanf("%d%d%d%d%d",&n,&m,&X,&Y,&Q);
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<Y;j++) a[i][j]-=a[i][j+1];
for (int j=m;j>Y;j--) a[i][j]-=a[i][j-1];
}
for (int j=1;j<=m;j++) {
for (int i=1;i<X;i++) a[i][j]-=a[i+1][j];
for (int i=n;i>X;i--) a[i][j]-=a[i-1][j];
}
build(rt,1,n);
for (int op,x1,y1,x2,y2,i=1;i<=Q;i++) {
scanf("%d%d%d%d%d",&op,&x1,&y1,&x2,&y2);
if (op==0) {
x1=X-x1;y1=Y-y1;x2=X+x2;y2=Y+y2;
printf("%lld\n",abs(query(rt,x1,y1,x2,y2)));
}
else {
LL val;scanf("%lld",&val);
//左上端点(x1,y1)
if (x1<=X && y1<=Y && x1>1 && y1>1) modify(rt,x1-1,y1-1,val);
else if (x1<=X && y1>Y && x1>1) modify(rt,x1-1,y1,-val);
else if (x1>X && y1<=Y && y1>1) modify(rt,x1,y1-1,-val);
else if (x1>X && y1>Y) modify(rt,x1,y1,val);
//右上端点(x1,y2)
if (x1<=X && y2>=Y && x1>1 && y2<m) modify(rt,x1-1,y2+1,val);
else if (x1<=X && y2<Y && x1>1) modify(rt,x1-1,y2,-val);
else if (x1>X && y2>=Y && y2<m) modify(rt,x1,y2+1,-val);
else if (x1>X && y2<Y) modify(rt,x1,y2,val);
//左下端点(x2,y1)
if (x2>=X && y1<=Y && x2<n && y1>1) modify(rt,x2+1,y1-1,val);
else if (x2<X && y1<=Y && y1>1) modify(rt,x2,y1-1,-val);
else if (x2>=X && y1>Y && x2<n) modify(rt,x2+1,y1,-val);
else if (x2<X && y1>Y) modify(rt,x2,y1,val);
//右下端点(x2,y2)
if (x2>=X && y2>=Y && x2<n && y2<m) modify(rt,x2+1,y2+1,val);
else if (x2>=X && y2<Y && x2<n) modify(rt,x2+1,y2,-val);
else if (x2<X && y2>=Y && y2<m) modify(rt,x2,y2+1,-val);
else if (x2<X && y2<Y) modify(rt,x2,y2,val); if (x1<=X && x2>=X) {
//左端点(X,y1)
if (y1<=Y && y1>1) modify(rt,X,y1-1,-val);
else if (y1>Y) modify(rt,X,y1,val);
//右端点(X,y2)
if (y2>=Y && y2<m) modify(rt,X,y2+1,-val);
else if (y2<Y) modify(rt,X,y2,val);
} if (y1<=Y && y2>=Y) {
//上端点
if (x1<=X && x1>1) modify(rt,x1-1,Y,-val);
else if (x1>X) modify(rt,x1,Y,val);
//下端点
if (x2>=X && x2<n) modify(rt,x2+1,Y,-val);
else if (x2<X) modify(rt,x2,Y,val);
} if (x1<=X && x2>=X && y1<=Y && y2>=Y) modify(rt,X,Y,val);
}
}
return 0;
}

【bzoj2877】 Noi2012—魔幻棋盘的更多相关文章

  1. BZOJ2877 NOI2012魔幻棋盘(二维线段树)

    显然一个序列的gcd=gcd(其差分序列的gcd,序列中第一个数).于是一维情况直接线段树维护差分序列即可. 容易想到将该做法拓展到二维.于是考虑维护二维差分,查询时对差分矩阵求矩形的gcd,再对矩形 ...

  2. [BZOJ2877][NOI2012]魔幻棋盘(二维线段树)

    https://blog.sengxian.com/solutions/bzoj-2877 注意二维线段树的upd()也是一个O(log n)的函数(pushdown()应该也是但没写过). #inc ...

  3. BZOJ2877 [Noi2012]魔幻棋盘

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  4. BZOJ2877:[NOI2012]魔幻棋盘

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

  5. 2877: [Noi2012]魔幻棋盘 - BZOJ

    DescriptionInput 第一行为两个正整数N,M,表示棋盘的大小. 第二行为两个正整数X,Y,表示棋盘守护者的位置. 第三行仅有一个正整数T,表示棋盘守护者将进行次操作. 接下来N行,每行有 ...

  6. NOI2012 魔幻棋盘

    http://www.lydsy.com/JudgeOnline/problem.php?id=2877 二维线段树. 好恶...... B类数据: 棋盘是一维的. 我们有一个结论: $gcd(a_{ ...

  7. 题解 洛谷 P2086 【[NOI2012]魔幻棋盘】

    先考虑只有一维的情况,要求支持区间加和求区间 \(\gcd\),根据 \(\gcd\) 的性质,发现: \[ \gcd(a_1,a_2,a_3,\ldots a_n)=\gcd(a_i,a_2-a_1 ...

  8. 数据结构(二维线段树,差分): NOI2012 魔幻棋盘

    貌似想复杂了…… #include <iostream> #include <cstring> #include <cstdio> #define mid ((l+ ...

  9. 【NOI2012】魔幻棋盘

    Description 将要读二年级的小 Q 买了一款新型益智玩具——魔幻棋盘,它是一个N行M列的网格棋盘,每个格子中均有一个正整数.棋盘守护者在棋盘的第X行Y列(行与列均从1开始编号) 并且始终不会 ...

随机推荐

  1. excel的宏与VBA入门(二)——数据类型与变量

    一.属性与方法 1.属性 上面单击对象,下面即显示对应的属性: 2.方法 双击左上的对象,即可看到相应的方法: 二.数据类型 到 Boolean True 或 False , 到 , ,,, 到 ,, ...

  2. 2017-2018-1 20155331 嵌入式C语言

    2017-2018-1 20155331 嵌入式C语言 作业要求: 在作业本上完成附图作业,要认真看题目要求. 提交作业截图 作弊本学期成绩清零(有雷同的,不管是给别人传答案,还是找别人要答案都清零) ...

  3. OFS环境,删除Resource 时出现错误失败,应该如何继续

    From the Windows failover cluster manager,select the group listener, stop it, and delete it.  Do the ...

  4. libgdx判断矩形重叠碰撞

    有两种方式. 1. 排除法,排除四种不可能重叠的情况就是了. public static boolean IsOverlap( Rectangle rect1, Rectangle rect2 ){ ...

  5. spring使用 RestTemplate 来进行http访问

    https://www.jianshu.com/p/2b03a812d588 https://my.oschina.net/sdlvzg/blog/1800395 异常:org.springframe ...

  6. 搭建 Guacamole 并解决各种坑和创建不了虚拟驱动器导致无法实现文件传输的方法

    系统类型版本:centos7 64位 结果:最终跑通了项目并且实现了虚拟驱动器的文件传输功能,添加了中文支持 反思总结: 先查看官方文档的Q&A,找找有没有类似的错误,然后如果有错误日志或者现 ...

  7. 真机调试傻瓜图文教程(Xcode6.4)

    先准备好99刀,真机调试才带你玩. PS:万能宝十来块钱可以买个资格... Developer Apple上的设置 1.打开https://developer.apple.com/,点击Member ...

  8. Seay源代码审计系统的配置和安装

    2014年7月31日 Seay源代码审计系统2.1 时隔刚好一年之久,源代码审计系统再次更新,这次主要优化审计体验,优化了漏洞规则,算是小幅更新,原来使用者打开程序会提示自动更新. 1.优化原有规则, ...

  9. Loadrunner 面试常见问题

    三大组件: 脚本生成器,录制和调试脚本 . 控制台,设置运行和资源场景 结果分析器,将测试结果数据以不同的图表呈现,便于性能分析 工作原理: 录制:根据不同协议,记录下客户端和服务器二者之间的对话,生 ...

  10. centos上部署mysql

    本文记录整个安装的过程和跳进的坑,大家预祝我能从坑里爬出来吧 当前系统版本 开始我们的安装: 在安装之前查阅了部分资料,大体安装流程 yum -y install mysql yum -y insta ...