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. 20155333 《网络对抗》 Exp6 信息搜集与漏洞扫描

    20155333 <网络对抗> Exp6 信息搜集与漏洞扫描 基础问题 哪些组织负责DNS,IP的管理? 全球根服务器均由美国政府授权的ICANN统一管理,负责全球的域名根服务器.DNS和 ...

  2. task1

    centos定时任务 清空特定目录文件 https://www.jb51.net/article/151066.htm 这次linux下不生成日志文件主要是因为日志框架冲突问题,我解决问题的思路错了 ...

  3. 设计模式 笔记 状态模式 State

    //---------------------------15/04/28---------------------------- //State  状态模式----对象行为型模式 /* 1:意图: ...

  4. SpringBoot日记——MQ消息队列整合(二)

    基于第一篇文章搭建好环境以后,我们这篇文章继续介绍如何在springboot中使用RabbitMQ. 1).单播:添加好pom文件和自定义配置后,来看: @Autowired RabbitTempla ...

  5. VirtualBox虚拟机怎么导入已经存在的vdi文件

    VirtualBox虚拟机怎么导入已经存在的vdi文件 第一章 1.原因 早上一不小心将virtualBox 卸载了,(不知道怎么了, 里面得虚拟机全部都没有了,但是vdi文件还在) 2.解决办法 直 ...

  6. 阿里云ECS服务器源配置

    前段时间领取了阿里云ECS免费试用6个月的福利,此处记录一下服务器源配置过程和服务器用户创建过程. 一.CentOS源配置 1.备份 mv /etc/yum.repos.d/CentOS-Base.r ...

  7. Catlike学习笔记(1.3)-使用Unity画更复杂的3D函数图像

    第三篇来了-今天去参加了 Unite 2018 Berlin,感觉就是....非常困...回来以后稍微睡了下清醒了觉得是时候认真学习下了,不过讲的很多东西都是还没有发布或者只有 Preview 的版本 ...

  8. 1. Python3 环境搭建

    Python3 环境搭建 开门见山,其他关于Python发展史.语言类型.优缺点等等 可以自己去百度百度,这里就不多说了.其实基本想要学这门语言的时候,你已经了解差不多了!!! Python的运行环境 ...

  9. 从两个设计模式到前端MVC-洪宇

    引言 本文将从策略模式和观察者模式两个设计模式讲起,接着过渡到一个经典的复合模式- MVC架构,进而介绍MVC在Web上的适应-Model2架构.之后,我们将视野扩展到前端MVC,看一看前端MVC经典 ...

  10. 冲刺Two之站立会议5

    昨天对视频音频的内容查询收集了相关资料,今天就主要对此进行了加工.先是使两台PC进行通信,不断进行测试.改进:测试.改进.最后初见成效,但还是没有达到我们最初的标准.