线段树 区间加 gcd 差分
小阳的贝壳
如果线段树要维护区间gcd 这个很简单,但是如果有了区间加,维护gcd 就比较麻烦了。
这个首先可以证明的是 gcd(x,y,z)=gcd(x,y-x,z-y) 这个可以推到 n 个
证明过程传送门
这个就和差分扯上关系了 可以看一下差分 差分传送门
上面的这两个博客基本上告诉我们这两个题目怎么写了。
首先我们对于每一个数进行处理,把这个数变成差分的形式,
因为最后的结果我们要 gcd(x,y-x,z-y) 所以我们要求和,还有求gcd ,这个就会有两个查询,一个查询sum,一个查询gcd
你看了差分的博客后你就发现,如果我们要给一段区间整体加上一个值,这个区间更新可以转化成差分的单点更新。
然后就是区间差值最大,这个很好求,因为我们每一个数本来放进去的就是区间的差分,所以这个相当于在求最大值。只是注意边界。
#include <cstdio> #include <cstdlib> #include <cstring> #include <queue> #include <vector> #include <algorithm> #include <string> #include <iostream> #include <map> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 2e5 + 10; int a[maxn]; struct node {int l, r;int max, sum, val; }tree[maxn*4];int gcd(int a,int b) {return b == 0 ? a : gcd(b, a%b); }void push_up(int id) {tree[id].max = max(abs(tree[id << 1].max), abs(tree[id << 1 | 1].max));tree[id].sum = tree[id << 1 | 1].sum + tree[id << 1].sum;tree[id].val = gcd(tree[id << 1].val, tree[id << 1 | 1].val); }void build(int id,int l,int r) {tree[id].l = l;tree[id].r = r;if(l==r){tree[id].sum = tree[id].val = a[l];tree[id].max = abs(a[l]);return;}int mid = (l + r) >> 1;build(id << 1, l, mid);build(id << 1 | 1, mid + 1, r);push_up(id); }int query_sum(int id,int x,int y) {int l = tree[id].l;int r = tree[id].r;if(x<=l&&y>=r){return tree[id].sum;}int ans = 0;int mid = (l + r) >> 1;if (x <= mid) ans += query_sum(id << 1, x, y);if (y > mid) ans += query_sum(id << 1 | 1, x, y);return ans; }int query_val(int id,int x,int y) {int l = tree[id].l;int r = tree[id].r;if(x<=l&&y>=r){return tree[id].val;}int ans = 0;int mid = (l + r) >> 1;if (x <= mid) ans = gcd(ans, query_val(id << 1, x, y));if (y > mid) ans = gcd(ans, query_val(id << 1 | 1, x, y));return ans; }int query_max(int id,int x,int y) {int l = tree[id].l;int r = tree[id].r;if(x<=l&&y>=r){return tree[id].max;}int ans = 0;int mid = (l + r) >> 1;if (x <= mid) ans = max(ans, query_max(id << 1, x, y));if (y > mid) ans = max(ans, query_max(id << 1 | 1, x, y));return ans; }void update(int id,int pos,int x) {int l = tree[id].l;int r = tree[id].r;if(l==r){tree[id].sum += x;tree[id].val += x;tree[id].max = abs(tree[id].val);return;}int mid = (l + r) >> 1;if (pos <= mid) update(id << 1, pos, x);else update(id << 1 | 1, pos, x);push_up(id); }int main() {int n, m;scanf("%d%d", &n, &m);for (int i = 1; i <= n; i++) scanf("%d", &a[i]);for (int i = n; i >= 1; i--) a[i] = a[i] - a[i - 1];build(1, 1, n);while (m--) {int opt, l, r, x;scanf("%d", &opt);if(opt==1){scanf("%d%d%d", &l, &r, &x);if (l > r) swap(l, r);update(1, l, x);if(r+1<=n) update(1, r + 1, -x);}if(opt==2){scanf("%d%d", &l, &r);if (l > r) swap(l, r);int ans = 0;if(l!=r) ans = query_max(1, l + 1, r);printf("%d\n", ans);}if(opt==3){scanf("%d%d", &l, &r);if (l > r) swap(l, r);int ans = 0;int ex1 = query_sum(1, 1, l);int ex2 = query_val(1, l + 1, r);if (l == r) ans = ex1;else ans = abs(gcd(ex1, ex2));printf("%d\n", ans);}// if(opt==4)// {// scanf("%d", &l);// printf("%d\n", query_sum(1, 1, l));// } }return 0; }
gcd 线段树 差分
转载于:https://www.cnblogs.com/EchoZQN/p/11202434.html
线段树 区间加 gcd 差分相关推荐
- 洛谷 P3368 【模板】树状数组 2(线段树区间加单点查找)
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的值 输入格式 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个 ...
- 2021牛客暑期多校训练营7 xay loves monotonicity 线段树区间合并
传送门 文章目录 题意: 思路: 题意: 题面挺绕口的,还是看原题比较好. 大概的意思就是让你从给定的区间中选择一个以左端点为起点的一个上升子序列,让后将这些下标存下来,在bbb中将这些位置拿出来后, ...
- 【bzoj4355】Play with sequence 线段树区间最值操作
题目描述 维护一个长度为N的序列a,现在有三种操作: 1)给出参数U,V,C,将a[U],a[U+1],...,a[V-1],a[V]都赋值为C. 2)给出参数U,V,C,对于区间[U,V]里的每个数 ...
- 【bzoj4695】最假女选手 线段树区间最值操作
题目描述 给定一个长度为 N 序列,编号从 1 到 N .要求支持下面几种操作: 1.给一个区间[L,R] 加上一个数x 2.把一个区间[L,R] 里小于x 的数变成x 3.把一个区间[L,R] ...
- HDU 1698 Just a Hook(线段树区间更新)
题意: 屠夫是Dota中一个令所有英雄闻风丧胆的英雄.他有一个很长的钩子,这个钩子是用铜做的(刚刚开始都是1),现在他想要更改这些钩子,把某个区间的钩子改为金.银或铜. 输入 L, R, X 表示把 ...
- python:线段树区间修改 + 区间查询 模板 + 坑点总结
from functools import reduceclass SegTree:'''支持增量更新,覆盖更新,序列更新,任意RMQ操作基于二叉树实现初始化:O(1)增量更新或覆盖更新的单次操作复杂 ...
- 树链剖分——线段树区间合并bzoj染色
线段树区间合并就挺麻烦了,再套个树链就更加鬼畜,不过除了代码量大就没什么其他的了.. 一些细节:线段树每个结点用结构体保存,pushup等合并函数改成返回一个结构体,这样好写一些 struct Seg ...
- SPOJ GSS3-Can you answer these queries III-分治+线段树区间合并
Can you answer these queries III SPOJ - GSS3 这道题和洛谷的小白逛公园一样的题目. 传送门: 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间 ...
- CF911G Mass Change Queries (线段树区间 合并)
题意: 给出一个数列,有q个操作,每种操作是把区间[l,r]中等于x的数改成y.输出q步操作完的数列. 题解: 100个数,很容易想到要从这里进行突破,对于某次操作我们只需要把这个区间的数x给移动到y ...
最新文章
- boost::log::sinks::file用法的测试程序
- jquey(判断文本框输入的网址链接是否符合规则)
- java 封装表单数据类型_Java基本数据类型与封装类型详解(int和Integer区别)
- mybatis批量插入数据到Oracle中的两种方式
- 无光驱如何修复W7计算机,Win7电脑没有光驱怎么装系统?
- (8)Powershell中变量的定义和使用
- java生日验证_Java验证身份证号码是否有效
- 微信小程序开发常见的错误
- ubuntu手动下载安装软件包
- 显色指数(CRI)计算软件-升级版可视化界面这个人大家自己斟酌人品
- LAIC2022司法人工智能挑战赛 - 司法文本小样本多任务Baseline
- 使用浏览器访问或调试微信公众号(跳过微信认证)
- spring interation学习-01发送jms消息
- windows7自带摄像头拍照摄像软件
- 文件共享——HHFM
- Linux下vsftpd服务的部署
- IC基础知识(六)SV中default input #1 output #1的解释
- 团 队 作 业 ———— 随 堂 小 测
- 写一个Singleton模式的例子
- 推荐几个科研数据相关的下载平台