【bzoj2877】 Noi2012—魔幻棋盘
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—魔幻棋盘的更多相关文章
- BZOJ2877 NOI2012魔幻棋盘(二维线段树)
显然一个序列的gcd=gcd(其差分序列的gcd,序列中第一个数).于是一维情况直接线段树维护差分序列即可. 容易想到将该做法拓展到二维.于是考虑维护二维差分,查询时对差分矩阵求矩形的gcd,再对矩形 ...
- [BZOJ2877][NOI2012]魔幻棋盘(二维线段树)
https://blog.sengxian.com/solutions/bzoj-2877 注意二维线段树的upd()也是一个O(log n)的函数(pushdown()应该也是但没写过). #inc ...
- BZOJ2877 [Noi2012]魔幻棋盘
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- BZOJ2877:[NOI2012]魔幻棋盘
浅谈树状数组与主席树:https://www.cnblogs.com/AKMer/p/9946944.html 题目传送门:https://lydsy.com/JudgeOnline/problem. ...
- 2877: [Noi2012]魔幻棋盘 - BZOJ
DescriptionInput 第一行为两个正整数N,M,表示棋盘的大小. 第二行为两个正整数X,Y,表示棋盘守护者的位置. 第三行仅有一个正整数T,表示棋盘守护者将进行次操作. 接下来N行,每行有 ...
- NOI2012 魔幻棋盘
http://www.lydsy.com/JudgeOnline/problem.php?id=2877 二维线段树. 好恶...... B类数据: 棋盘是一维的. 我们有一个结论: $gcd(a_{ ...
- 题解 洛谷 P2086 【[NOI2012]魔幻棋盘】
先考虑只有一维的情况,要求支持区间加和求区间 \(\gcd\),根据 \(\gcd\) 的性质,发现: \[ \gcd(a_1,a_2,a_3,\ldots a_n)=\gcd(a_i,a_2-a_1 ...
- 数据结构(二维线段树,差分): NOI2012 魔幻棋盘
貌似想复杂了…… #include <iostream> #include <cstring> #include <cstdio> #define mid ((l+ ...
- 【NOI2012】魔幻棋盘
Description 将要读二年级的小 Q 买了一款新型益智玩具——魔幻棋盘,它是一个N行M列的网格棋盘,每个格子中均有一个正整数.棋盘守护者在棋盘的第X行Y列(行与列均从1开始编号) 并且始终不会 ...
随机推荐
- 数据结构与算法之Stack(栈)的应用——用stack实现一个计算器-/bin/calc.dart
计算器的bin/calc.dart 可执行代码: import 'dart:io'; import 'package:data_struct/stack/sample/calculator.dart' ...
- kettle学习笔记(八)——kettle查询步骤与连接步骤
一.概述 查询步骤: 用来查询数据源里的数据并合并到主数据流中 . 连接步骤: 结果集通过关键字进行连接 .(与前面的UNION不同) 二.查询步骤 1.流查询 流查询示例:(注意上文中的流查询的限制 ...
- 20155233 刘高乐 Exp9 Web安全基础
WebGoat 输入java -jar webgoat-container-7.1-exec.jar 在浏览器输入localhost:8080/WebGoat,进入WebGoat开始实验 Cross- ...
- sprintboot 和swagger2整合生成文档
1.创建springboot 工程 2.引入maven依赖 <dependency> <groupId>io.springfox</groupId> <art ...
- HW 2017 12 17可禾大佬神题
好不容易搞来的题目,不写一写怎么行呢. 不过难度真心不高(一小时K掉),都是老题+暴力题,没有欧洲玄学. 再说一句,这试卷是叶可禾出的吧. T1 好老的题目,看到有多组数据我还怕了,以为有更流弊的算法 ...
- 2PC/3PC到底是啥
讨论 提到2PC/3PC首先想到的是它是一致性协议,而且经常把它和Paxos协议放在一起比较,并且经常看到这样的说法"世上只有一种一致性算法,那就是Paxos",2PC/3PC并不 ...
- Mysql_临时表
CREATE TEMPORARY TABLE test_info ( test_name ) NOT NULL, test_totail ,) NOT NULL DEFAULT 0.00, test_ ...
- linux AB web 性能测试工具
ab(选项)(参数) 选项 -A:指定连接服务器的基本的认证凭据: -c:指定一次向服务器发出请求数: -C:添加cookie: -g:将测试结果输出为“gnuolot”文件: -h:显示帮助信息: ...
- python 游戏(猜数字)
1. 构造猜数字核心函数 import random def guess_core(guess_min,guess_max,guess_counrt): '''猜数字核心判断函数 :param gue ...
- Linux第一章读书笔记
一.Linux历史 Unix强大的根本原因: 1.简洁,仅仅提供几百个系统调用并且有一个非常明确的设计目的 2.文件对待所有东西,通过一套相同的系统调用接口来进行对数据和设备的操作 3.由于用C语言编 ...