给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。

2、“Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。

对于每个询问,输出一个整数表示答案。

输入格式

第一行两个整数N,M。

第二行N个整数A[i]。

接下来M行表示M条指令,每条指令的格式如题目描述所示。

输出格式

对于每个询问,输出一个整数表示答案。

每个答案占一行。

数据范围

N≤500000,M≤100000N≤500000,M≤100000

输入样例:

5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 1 5
C 3 3 6
Q 2 4

输出样例:

1
2
4

算法:线段树 + 增量数组(树状数组) + 差分序列

题解:

  性质:

  • gcd(a, b) = gcd(a, b - a)
  • gcd(a, b, c) = gcd(a, b - a, c - b)
  • acd(a1, a2, ... , an) = gcd(a1, a2 - a1, ... , an - an-1)

  利用这条性质来求解此题

  1. 对用询问“Q l r”来说,可以求出结果__gcd(arr[l], query(1, l + 1, r),就是同上面的性质,前面那个arr[l]就是性质里面的第一个数,后面的就是存在了线段树里面差分序列,求出(l + 1, r)区间的最大公约数即可。(其中的arr[l]等于原本数组里面的值加上后面更改的值,更改的值记录再树状数组里面)。
  2. 对于询问“C l r d”来说,只需要修改树状数组里面的值,以及线段树里面的值即可。

注意:题目会爆int,需要用long long。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath> using namespace std; typedef long long ll; const int maxn = 5e5+; struct node {
ll l, r;
ll dat;
}tree[maxn << ]; //维护差分序列的线段树 ll n, m;
ll d[maxn]; //差分数组
ll arr[maxn]; //原始数组
ll T[maxn]; //增量数组(树状数组) ll lowbit(ll x) {
return x & (-x);
} void pushup(ll root) {
tree[root].dat = __gcd(tree[root << ].dat, tree[root << | ].dat);
} void build(ll root, ll l, ll r) {
tree[root].l = l;
tree[root].r = r;
if(l == r) {
tree[root].dat = d[l];
return;
}
ll mid = (l + r) >> ;
build(root << , l, mid);
build(root << | , mid + , r);
pushup(root);
} void add(ll x, ll val) {
while(x <= n) {
T[x] += val;
x += lowbit(x);
}
} ll ask(ll x) {
ll res = ;
while(x > ) {
res += T[x];
x -= lowbit(x);
}
return res;
} void update(ll root, ll pos, ll val) {
ll l = tree[root].l;
ll r = tree[root].r;
if(l == r) {
tree[root].dat += val;
return;
}
ll mid = (l + r) >> ;
if(pos <= mid) {
update(root << , pos, val);
} else {
update(root << | , pos, val);
}
pushup(root);
} ll query(ll root, ll x, ll y) {
ll l = tree[root].l;
ll r = tree[root].r;
if(x <= l && r <= y) {
return tree[root].dat;
}
ll mid = (l + r) >> ;
ll res = ;
if(x <= mid) {
res = __gcd(res, query(root << , x, y));
}
if(y > mid) {
res = __gcd(res, query(root << | , x, y));
}
return abs(res); //注意:这里需要加绝对值,因为可能出现负数
} int main() {
scanf("%lld%lld", &n, &m);
for(ll i = ; i <= n; i++) {
scanf("%lld", &arr[i]);
d[i] = arr[i] - arr[i - ]; //构建差分数组
}
build(, , n);
while(m--) {
char str[];
ll l, r, val;
scanf("%s", str);
if(str[] == 'Q') {
scanf("%lld %lld", &l, &r);
ll now = arr[l] + ask(l); //获取当前位置的值(原始数组 + 增量数组)
printf("%lld\n", __gcd(now, query(, l + , r))); //与后面的部分求最大公约数
} else {
scanf("%lld %lld %lld", &l, &r, &val);
add(l, val);
add(r + , -val);
update(, l, val);
if(r < n) { //判断是否会越界
update(, r + , -val);
} }
}
return ;
}

AcWing:246. 区间最大公约数(线段树 + 增量数组(树状数组) + 差分序列)的更多相关文章

  1. AcWing 246. 区间最大公约数

    246. 区间最大公约数 思路: 首先根据更相减损术,我们得到一个结论: \(gcd(a_l, a_{l+1}, ...,a_r) = gcd(a_l, a_{l+1}-a_l, a_{l+2}-a_ ...

  2. 【bzoj3132】上帝造题的七分钟 二维树状数组区间修改区间查询

    题目描述 “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵. 第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作. ...

  3. [bzoj3155]Preprefix sum(树状数组)

    3155: Preprefix sum Time Limit: 1 Sec  Memory Limit: 512 MBSubmit: 1183  Solved: 546[Submit][Status] ...

  4. Codeforces 980E The Number Games - 贪心 - 树状数组

    题目传送门 传送点I 传送点II 传送点III 题目大意 给定一颗有$n$个点的树,$i$号点的权值是$2^{i}$要求删去$k$个点,使得剩下的点仍然连通,并且总权值和最大,问删去的所有点的编号. ...

  5. 1082 线段树练习 3 && 树状数组区间修改区间查询

    1082 线段树练习 3 题意: 给定序列初值, 要求支持区间修改, 区间查询 Solution 用树状数组, 代码量小, 空间占用小 巧用增量数组, 修改时在 \(l\) 处 $ + val$ , ...

  6. acwing 243. 一个简单的整数问题2 树状数组 线段树

    地址 https://www.acwing.com/problem/content/description/244/ 给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一: 1.“C l ...

  7. HDU 4031 Attack(线段树/树状数组区间更新单点查询+暴力)

    Attack Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Sub ...

  8. NBOJv2 1050 Just Go(线段树/树状数组区间更新单点查询)

    Problem 1050: Just Go Time Limits:  3000 MS   Memory Limits:  65536 KB 64-bit interger IO format:  % ...

  9. POJ 2155 Matrix (二维线段树入门,成段更新,单点查询 / 二维树状数组,区间更新,单点查询)

    题意: 有一个n*n的矩阵,初始化全部为0.有2中操作: 1.给一个子矩阵,将这个子矩阵里面所有的0变成1,1变成0:2.询问某点的值 方法一:二维线段树 参考链接: http://blog.csdn ...

随机推荐

  1. 07 Deque的应用案例-回文检查

    - 回文检测:设计程序,检测一个字符串是否为回文. - 回文:回文是一个字符串,读取首尾相同的字符,例如,radar toot madam. - 分析:该问题的解决方案将使用 deque 来存储字符串 ...

  2. 06 基本数据结构 - 双端队列(Deque)

    一.双端队列(Deque) - 概念:deque(也称为双端队列)是与队列类似的项的有序集合.它有两个端部,首部和尾部,并且项在集合中保持不变. - 特性:deque 特殊之处在于添加和删除项是非限制 ...

  3. python 模块使用

    模块使用 定义:模块就像一个工具包一样,里面有很多工具(函数.类),使用时需要通过import导入. 分类: 标准库:random.sys.os.time 第三方:就是好人已经写好的特定功能的模块,你 ...

  4. VUE 从零开始 学习笔记 一

    最近刚跳到一个新公司 不是很忙 决定系统的学习一下VUE这个前端框架 参考官方API 好了 废话不多说 开始了 首先 说一下吧 现在很火的主流三大前端框架 Vue,Angular.React, 为什么 ...

  5. redis性能指标

    1.当内存使用达到设置的最大阀值时,需要选择一种key的回收策略,可在Redis.conf配置文件中修改“maxmemory-policy”属性值. 若是Redis数据集中的key都设置了过期时间,那 ...

  6. Linux搭建局域网yum源和后期在yum源中更新rpm包方法

    在内网中搭建自己的yum源,可以方便在内网中使用,下面简单介绍搭建局域网yum源的方法和后期更新yum源rpm包的方法. 一.搭建局域网yum源 1.需要在局域网访问,首先需要一个web服务器,比如a ...

  7. SpringBoot核心特性之组件自动装配

    写在前面 spring boot能够根据依赖的jar包自动配置spring boot的应用,例如: 如果类路径中存在DispatcherServlet类,就会自动配置springMvc相关的Bean. ...

  8. cmake编译c++程序

    当在Linux系统下编写程序时候,如果没有类似于visual studio.vs code等IDE(集成开发环境)时,如何编译.运行程序呢?一种方法是编写makefile文件,用makefile文件管 ...

  9. height 自适应问题

    何为高度自适应? 高度自适应就是高度能跟随浏览器窗口的大小改变而改变,典型的运用在一些后台界面中上面一栏高度固定用作菜单栏或导航栏,下面一栏高度自适应用于显示内容.高度自适应不像宽度自适应那样简单,在 ...

  10. 轮子:读取config.ini文件

    python: 把config.ini文件成map返回 def get_conf(conf_file): conf = {} ll=list(map(lambda x: x.replace('&quo ...