这个题目是一个线段树+差分+GCD

推荐一个差分的博客:https://www.cnblogs.com/cjoierljl/p/8728110.html

学会了这个简单差分之后,就可以把这个题目的区间更新转化成单点更新了,emmm...可能还是不太理解,那就说下具体思路吧。

这个题目一看感觉很难,然后就取看题解,这个看了题解之后发现裴蜀定理+线段树。

讲一下为什么是裴蜀定理+线段树,线段树应该没有什么异议,因为这个有区间更新区间查询,而且n,m的数值很大,不用线段树很容易T。

因为你要进行很多次操作,就可以列一个式子:ax1+bx2+cx3....=ans

这个式子,如果你的数论学的很好的话,就可以知道应该用裴蜀定理,这个裴蜀定理可以自己简单学习一下。

根据裴蜀定理这个最小值应该是gcd(a,b,c,d....),所以我们就应该用线段树来求一个区间的gcd。

为什么又要用到差分呢?

因为如果你每次进行区间更新都是每一个点进行更新(只能这样,不然就无法求gcd),这样子的话,你就会发现T了。

所以我们不这么写,从刚刚的那个博客可以看出,这个可以把区间更新转化成单点更新了,就只需要更新区间左端点和区间右端点+1。

所以总结一下,这个题解法就是:

先对序列进行差分,然后用差分数列进行建树,这个要记录一个和sum和gcd val

然后就是查询,这个查询就是先查左端点的sum,然后再查左端点到右端点之间的差分的val(这个是根据裴蜀定理得出的)

然后就是更新,这个更新是只要对左端点和右端点+1进行更新就可以了。

之前是写之前的思路,接下来说说写的过程种碰到的bug,写在代码里了。

其实和普通线段树是差不多的,但是就是会有很多小bug没注意到。

线段树的bug还是很难找的。

写一下我对于差分的理解:
如果你碰到你要更新一个区间,给这个区间上的每一个数都加上一个x,让你求n次操作之后求一个区间总和。
又有时间限制,不可以一个一个的去加,这个时候就可以用上差分了。
就是先将这个数列进行差分得到一个差分数列,然后就是对于这个区间的第一位+x,
最后一位的后面一位-x。
这样子操作n次之后再用前缀和求出原来的数列,最后原来的数列再运算即可。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + ;
struct node
{
int l, r;
int sum, val;
}tree[maxn*];
int a[maxn]; int gcd(int a,int b)
{
return b == ? a : gcd(b, a%b);
} void push_up(int id)
{
tree[id].sum = tree[id << ].sum + tree[id << | ].sum;
tree[id].val = gcd(tree[id << ].val, tree[id << | ].val);
} void build(int id,int l,int r)//建树
{
tree[id].l = l;
tree[id].r = r;
if(tree[id].l==tree[id].r)
{
tree[id].sum = tree[id].val = a[l];
return;
}
int mid = (l + r) >> ;
build(id << , l, mid);
build(id << | , mid + , r);
push_up(id);
} int query_sum(int id,int l,int r)//求到第区间第一个的真实值
{
if(l<=tree[id].l&&r>=tree[id].r)
{
return tree[id].sum;
}
int mid = (tree[id].l + tree[id].r)>>, ans = ;
if (l <= mid) ans += query_sum(id << , l, r);
if(r>mid) ans += query_sum(id << | , l, r);
return ans;
} int query_val(int id,int l,int r)//求区间除开第一个的差分gcd
{
if(l<=tree[id].l&&r>=tree[id].r)
{
return tree[id].val;
}
int mid = (tree[id].l + tree[id].r) >> , ans = ;
if (l <= mid) ans = gcd(ans, query_val(id << , l, r));
if (r > mid) ans = gcd(ans, query_val(id << | , l, r));
return ans;
} void update(int id,int p,int x)
{
if (p > tree[id].r) return;
if(tree[id].l==tree[id].r)
{
tree[id].sum += x;
tree[id].val += x;
return;
}
int mid = (tree[id].l + tree[id].r) >> ;
if (p <= mid) update(id << , p, x);
else update(id << | , p, x);
push_up(id);
} int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++) scanf("%d", &a[i]);
for (int i = n; i >= ; i--) a[i] = a[i] - a[i - ];//要从后往前,注意差分是每一个真实值和这个真实值之前的真实值进行差分
build(, , n);
for (int i = ; i <= m; i++)
{
int p, l, r;
scanf("%d%d%d", &p, &l, &r);
if (l > r) swap(l, r);//这个其实交换不交换都差不多
if (p == )
{
int exa1 = query_sum(, , l);//去查找第i个数的真实值
int exa2 = query_val(, l + , r);//i到r之间的gcd
int ans = abs(gcd(exa1,exa2));//因为是进行差分了,所以gcd之后也有可能有负值
printf("%d\n", ans);
}
else
{
int x;
scanf("%d", &x);
update(, l, x);//差分的更新
update(, r + , -x);
}
}
return ;
}

D - 小Z的加油店 线段树+差分+GCD的更多相关文章

  1. [BZOJ5028]小Z的加油店

    [BZOJ5028]小Z的加油店 题目大意: 一个长度为\(n(n\le10^5)\)的数列,\(m(m\le10^5)\)次操作,支持区间加和区间\(\gcd\). 思路: 线段树维护差分,\(\g ...

  2. 【BZOJ】5028: 小Z的加油店

    [算法]数学+线段树/树状数组 [题解] 首先三个操作可以理解为更相减损术或者辗转相除法(待证明),所以就是求区间gcd. 这题的问题在线段树维护gcd只能支持修改成一个数,不支持加一个数. 套路:g ...

  3. 5028: 小Z的加油店(线段树)

    NOI2012魔幻棋盘弱化版 gcd(a,b,c,d,e)=gcd(a,b-a,c-b,d-c,e-d) 然后就可以把区间修改变成差分后的点修了. 用BIT维护原序列,线段树维护区间gcd,支持点修区 ...

  4. bzoj5028小Z的加油店(线段树+差分)

    题意:维护支持以下两种操作的序列:1 l r询问a[l...r]的gcd,2 l r x把a[l...r]全部+x 题解:一道经典题.根据gcd(a,b)=gcd(a-b,b)以及区间加可知,这题可以 ...

  5. 【bzoj5028】小Z的加油店 扩展裴蜀定理+差分+线段树

    题目描述 给出 $n$ 个瓶子和无限的水,每个瓶子有一定的容量.每次你可以将一个瓶子装满水,或将A瓶子内的水倒入B瓶子中直到A倒空或B倒满.$m$ 次操作,每次给 $[l,r]$ 内的瓶子容量增加 $ ...

  6. bzoj 5028: 小Z的加油店——带修改的区间gcd

    Description 小Z经营一家加油店.小Z加油的方式非常奇怪.他有一排瓶子,每个瓶子有一个容量vi.每次别人来加油,他会让 别人选连续一段的瓶子.他可以用这些瓶子装汽油,但他只有三种操作: 1. ...

  7. BZOJ 5028 小Z的加油店

    [题解] 本题要求求出区间内的各个元素通过加减之后能够得出的最小的数,那么根据裴蜀定理可知答案就是区间内各个元素的最大公约数. 那么本题题意化简成了维护一个序列,支持区间加上某个数以及查询区间元素的最 ...

  8. 牛客小白月赛16 H小阳的贝壳 (线段树+差分数组)

    链接:https://ac.nowcoder.com/acm/contest/949/H来源:牛客网 题目描述 小阳手中一共有 n 个贝壳,每个贝壳都有颜色,且初始第 i 个贝壳的颜色为 colico ...

  9. 【BZOJ4031】小Z的房间(矩阵树定理)

    [BZOJ4031]小Z的房间(矩阵树定理) 题面 BZOJ 洛谷 Description 你突然有了一个大房子,房子里面有一些房间.事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子 ...

随机推荐

  1. shell命令(一)

    什么是shell? Shell是一个应用程序,它连接了用户和Linux内核,让用户能够更加高效.安全.低成本地使用Linux内核,这就是Shell的本质. shell与Linux系统关系图 shell ...

  2. webWMS开发过程记录(二)- WMS是什么

    (参考:WMS-百度百科) 简介 WMS是仓库管理系统(Warehouse Management System)的缩写,是一款标准化.智能化过程导向管理的仓库管理软件仓库管理系统,是通过出入库业务.仓 ...

  3. 选择IT行业的自我心得,希望能帮助到各位!(一)

    我记得当时我还在读书的时候,也是卡在高三在后面,纠结我该怎么选择专业,一边顶着高考的压力又担心这担心那的,前怕狼后怕虎,一直犹犹豫豫,知道有一天我就听到谁谁谁的哥哥学IT老牛逼了,一个月多少多少钱,买 ...

  4. python爬取《龙岭迷窟》的数据,看看质量剧情还原度到底怎么样

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:简单 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行 ...

  5. L24 word2vec

    词嵌入基础 我们在"循环神经网络的从零开始实现"一节中使用 one-hot 向量表示单词,虽然它们构造起来很容易,但通常并不是一个好选择.一个主要的原因是,one-hot 词向量无 ...

  6. Java日期时间API系列30-----Jdk8中java.time包中的新的日期时间API类,减少时间精度方法性能比较和使用。

    实际使用中,经常需要使用不同精确度的Date,比如保留到天 2020-04-23 00:00:00,保留到小时,保留到分钟,保留到秒等,常见的方法是通过格式化到指定精确度(比如:yyyy-MM-dd) ...

  7. bytectf2019 boring_code的知识学习&&无参数函数执行&&上海市大学生CTF_boring_code+

    参赛感悟 第三次还是第二次参加这种CTF大赛了,感悟和学习也是蛮多的,越发感觉跟大佬的差距明显,但是还是要努力啊,都大三了,也希望出点成绩.比赛中一道WEB都没做出来,唯一有点思路的只有EZCMS,通 ...

  8. 《Spring In Action》阅读笔记之装配bean

    Spring主要装配机制 1.在XML中进行显式配置 2.在Java中进行显式配置 3.隐式的的bean发现机制和自动装配 自动化装配bean Spring从两个角度来实现自动化装配 1.组件扫描:S ...

  9. Springboot:JSR303数据校验(五)

    @Validated //开启JSR303数据校验注解 校验规则如下: [一]空检查 @Null 验证对象是否为null @NotNull 验证对象是否不为null, 无法查检长度为0的字符串 @No ...

  10. sql查询慢 查找

    SELECT creation_time N'语句编译时间' ,last_execution_time N'上次执行时间' ,total_physical_reads N'物理读取总次数' ,tota ...