区间加值,区间gcd, 牛客949H
牛客小白月赛16H 小阳的贝壳
题意
维护一个数组,支持以下操作:
1: 区间加值
2: 询问区间相邻数差的绝对值的最大值
3: 询问区间gcd
题解
设原数组为\(a\), 用线段树维护\(b[i] = a[i] - a[i - 1]\),
线段树维护三个值:min, max, gcd
对于操作1:
L 位置加上x, R + 1位置减去x
对于操作2:
查询区间(L + 1, R) 的 min, max, 取绝对值大者
对于操作3:
考虑gcd的性质
\(gcd(a, b, c, d, ...) = gcd(a, b - a, c - b, d - c, ...)\)
查询区间(L + 1, R) 的 gcd, 就是\(gcd(b - a, c - b, d - c, ...)\)
然后用另一个东西维护原来的a数列
可以用另一颗线段树lazy标记维护
我用的是树状数组差分,将区间更新和单点查询转化为单点更新和前缀和查询
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int mx[N << 2], mn[N << 2], g[N << 2], c[N], a[N], b[N];
int n, m, op, l, r, x;
void add(int pos, int val) {
for(; pos <= n; pos += pos & -pos)
c[pos] += val;
}
int ask(int pos) {
int ans = 0;
for(; pos; pos -= pos & -pos)
ans += c[pos];
return ans;
}
void pushup(int rt) {
mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
mn[rt] = min(mn[rt << 1], mn[rt << 1 | 1]);
g[rt] = __gcd(g[rt << 1], g[rt << 1 | 1]);
}
void build(int rt, int l, int r) {
if(l == r) {
mx[rt] = mn[rt] = g[rt] = b[l];
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
pushup(rt);
}
void update(int rt, int l, int r, int pos, int val) {
if(l == r) {
mx[rt] += val;
mn[rt] += val;
g[rt] += val;
return;
}
int mid = l + r >> 1;
if(pos <= mid)
update(rt << 1, l, mid, pos, val);
else
update(rt << 1 | 1, mid + 1, r, pos, val);
pushup(rt);
}
int querymax(int rt, int l, int r, int L, int R) {
if(L <= l && r <= R) {
return max(abs(mn[rt]), abs(mx[rt]));
}
int mid = l + r >> 1, ans = 0;
if(L <= mid)
ans = max(ans, querymax(rt << 1, l, mid, L, R));
if(R > mid)
ans = max(ans, querymax(rt << 1 | 1, mid + 1, r, L, R));
return ans;
}
int querygcd(int rt, int l, int r, int L, int R) {
if(L <= l && r <= R) {
return g[rt];
}
int mid = l + r >> 1, ans = 0;
if(L <= mid)
ans = __gcd(ans, querygcd(rt << 1, l, mid, L, R));
if(R > mid)
ans = __gcd(ans, querygcd(rt << 1 | 1, mid + 1, r, L, R));
return abs(ans);
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
add(i, a[i] - a[i - 1]);
b[i] = a[i] - a[i - 1];
}
build(1, 1, n);
while(m--) {
scanf("%d%d%d", &op, &l, &r);
if(op == 1) {
scanf("%d", &x);
add(l, x);
update(1, 1, n, l, x);
if(r != n) {
add(r + 1, -x);
update(1, 1, n, r + 1, -x);
}
}
else if(op == 2) {
if(l == r)
puts("0");
else
printf("%d\n", querymax(1, 1, n, l + 1, r));
}
else {
int a = ask(l), b;
if(l == r)
b = 0;
else
b = querygcd(1, 1, n, l + 1, r);
printf("%d\n", __gcd(a, b));
}
}
return 0;
}
区间加值,区间gcd, 牛客949H的更多相关文章
- 二叉树中和为某一值的路径 牛客网 程序员面试金典 C++ Python
二叉树中和为某一值的路径 牛客网 程序员面试金典 题目描述 输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一 ...
- HDU 3577 Fast Arrangement ( 线段树 成段更新 区间最值 区间最大覆盖次数 )
线段树成段更新+区间最值. 注意某人的乘车区间是[a, b-1],因为他在b站就下车了. #include <cstdio> #include <cstring> #inclu ...
- cf834D(dp+线段树区间最值,区间更新)
题目链接: http://codeforces.com/contest/834/problem/D 题意: 每个数字代表一种颜色, 一个区间的美丽度为其中颜色的种数, 给出一个有 n 个元素的数组, ...
- HihoCoder1333 :平衡树(splay+lazy)(区间加值,区间删除)
描述 小Ho:好麻烦啊~~~~~ 小Hi:小Ho你在干嘛呢? 小Ho:我在干活啊!前几天老师让我帮忙管理一下团队的人员,但是感觉好难啊. 小Hi:说来听听? 小Ho:事情是这样的.我们有一个运动同好会 ...
- POJ 3468 A Simple Problem with Integers(线段树功能:区间加减区间求和)
题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS Memory Limit ...
- 线段树 区间加 gcd 差分 小阳的贝壳
小阳的贝壳 如果线段树要维护区间gcd 这个很简单,但是如果有了区间加,维护gcd 就比较麻烦了. 这个首先可以证明的是 gcd(x,y,z)=gcd(x,y-x,z-y) 这个可以推到 n 个 ...
- HDU 5828 Rikka with Sequence(线段树区间加开根求和)
Problem DescriptionAs we know, Rikka is poor at math. Yuta is worrying about this situation, so he g ...
- 【BZOJ】1798: [Ahoi2009]Seq 维护序列seq 线段树多标记(区间加+区间乘)
[题意]给定序列,支持区间加和区间乘,查询区间和取模.n<=10^5. [算法]线段树 [题解]线段树多重标记要考虑标记与标记之间的相互影响. 对于sum*b+a,+c直接加上即可. *c后就是 ...
- 线段树_区间加乘(洛谷P3373模板)
题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字 ...
随机推荐
- ES6数组对象新增方法
1. Array.from() Array.from方法用于将两类对象转为真正的数组:类数组的对象( array-like object )和可遍历( iterable )的对象(包括 ES6 新增的 ...
- js 实现页面局部(或图片)放大功能(vue)
方法: adjustStart1 (e) { e.preventDefault() let event = e.touches if (event.length === 2) { this.style ...
- 并查集 (poj 1611 The Suspects)
原题链接:http://poj.org/problem?id=1611 简单记录下并查集的模板 #include <cstdio> #include <iostream> #i ...
- PAT甲级——A1082 Read Number in Chinese
Given an integer with no more than 9 digits, you are supposed to read it in the traditional Chinese ...
- fastjson过滤字段
1.注解(字段上添加) @JSONField(serialize=false) 2.过滤器 PropertyFilter propertyFilter = new PropertyFilter() { ...
- NEO4J的安装配置及使用总结
#工具:使用neo4j desktop版本# 一,下载工具 可以到官方网站上下载桌面版或者community版本的,下载地址:https://neo4j.com/, 安装好. 二.配置环境变量 本文参 ...
- CheckBox自定义样式
效果: xmal代码: <Style x:Key="CheckBoxStyle" TargetType="{x:Type CheckBox}"> & ...
- VC文件操作
VC文件操作 重命名文件: 注意: 该操作对文件夹一样有效! CFileFind Finder; CString sOldPath = _T("D:\\tt.txt"); CStr ...
- Leetcode938. Range Sum of BST二叉搜索树的范围和
给定二叉搜索树的根结点 root,返回 L 和 R(含)之间的所有结点的值的和. 二叉搜索树保证具有唯一的值. 示例 1: 输入:root = [10,5,15,3,7,null,18], L = 7 ...
- STL容器-deque-双端队列
注明:全部来自转载,供自己学习与复习使用 deque双向开口可进可出的容器 我们知道连续内存的容器不能随意扩充,因为这样容易扩充别人那去 deque却可以,它创造了内存连续的假象. 其实deque由一 ...