Petrozavodsk Winter-2018. AtCoder Contest. Problem I. ADD, DIV, MAX 吉司机线段树
题意:给你一个序列,需要支持以下操作:1:区间内的所有数加上某个值。2:区间内的所有数除以某个数(向下取整)。3:询问某个区间内的最大值。
思路(从未见过的套路):维护区间最大值和区间最小值,执行2操作时,继续向下寻找子区间,如果区间满足:min - (min / x) == max - (max / x)时,给这个区间内的所有数减去min - (min / x)就可以了。为什么这样做呢?因为向下取整操作变化速度远快于加法,在经过很多次操作后其实序列中的数区域相等,复杂度需要用势能分析之类的,均摊复杂度应该是O(n * (log(n) ^ 2))。
代码:
#include <bits/stdc++.h>
#define LL long long
#define ls (o << 1)
#define rs (o << 1 | 1)
using namespace std;
const int maxn = 200010;
struct Seg {
LL add, mx, mi;
};
Seg tr[maxn * 4];
LL a[maxn]; void pushup(int o) {
tr[o].mx = max(tr[ls].mx, tr[rs].mx);
tr[o].mi = min(tr[ls].mi, tr[rs].mi);
} void pushdown(int o) {
if(tr[o].add != 0) {
tr[ls].add += tr[o].add;
tr[ls].mi += tr[o].add;
tr[ls].mx += tr[o].add;
tr[rs].add += tr[o].add;
tr[rs].mi += tr[o].add;
tr[rs].mx += tr[o].add;
tr[o].add = 0;
}
} void dfs(int o, int l, int r, LL val) {
if(tr[o].mi - (tr[o].mi / val) == tr[o].mx - (tr[o].mx / val)) {
LL tmp = tr[o].mi - (tr[o].mi / val);
tr[o].add -= tmp;
tr[o].mi -= tmp;
tr[o].mx -= tmp;
return;
}
int mid = (l + r) >> 1;
pushdown(o);
dfs(ls, l, mid, val);
dfs(rs, mid + 1, r, val);
pushup(o);
} void build(int o, int l, int r) {
if(l == r) {
tr[o].add = 0;
tr[o].mx = tr[o].mi = a[l];
return;
}
int mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(o);
} void update(int o, int l, int r, int ql, int qr, LL val, bool flag) {
if(l >= ql && r <= qr) {
if(flag == 0) {
tr[o].mi += val;
tr[o].mx += val;
tr[o].add += val;
} else {
dfs(o, l, r, val);
}
return;
}
pushdown(o);
int mid = (l + r) >> 1;
if(ql <= mid) update(ls, l, mid, ql, qr, val, flag);
if(qr > mid) update(rs, mid + 1, r, ql, qr, val, flag);
pushup(o);
} LL query(int o, int l, int r, int ql, int qr) {
if(l >= ql && r <= qr) {
return tr[o].mx;
}
int mid = (l + r) >> 1;
LL ans = 0;
pushdown(o);
if(ql <= mid) ans = max(ans, query(ls, l, mid, ql, qr));
if(qr > mid) ans = max(ans, query(rs, mid + 1, r, ql, qr));
return ans;
} int main() {
int op, l, r, x, n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
build(1, 1, n);
for (int i = 1; i <= m; i++) {
scanf("%d", &op);
if(op == 0) {
scanf("%d%d%d", &l, &r, &x);
l++, r++;
update(1, 1, n, l, r, x, 0);
} else if(op == 1) {
scanf("%d%d%d", &l, &r, &x);
l++, r++;
if(x != 1)
update(1, 1, n, l, r, x, 1);
} else {
scanf("%d%d%d", &l, &r, &x);
l++, r++;
printf("%lld\n", query(1, 1, n, l, r));
}
}
}
Petrozavodsk Winter-2018. AtCoder Contest. Problem I. ADD, DIV, MAX 吉司机线段树的更多相关文章
- 2014-2015 Petrozavodsk Winter Training Camp, Contest.58 (Makoto rng_58 Soejima contest)
2014-2015 Petrozavodsk Winter Training Camp, Contest.58 (Makoto rng_58 Soejima contest) Problem A. M ...
- AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图
AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图 链接 AtCoder 大意 在数轴上放上n个点,点i可能的位置有\(x_i\)或者\(y_i\ ...
- 2018.07.30 cogs2632. [HZOI 2016] 数列操作d(线段树)
传送门 线段树基本操作 区间加等差数列,维护区间和. 对于每个区间维护等差数列首项和公差,易证这两个东西都是可合并的,然后使用小学奥数的知识就可以切掉这题. 代码: #include<bits/ ...
- 2018.07.25 bzoj3878: [Ahoi2014&Jsoi2014]奇怪的计算器(线段树)
传送门 线段树综合. 让我想起一道叫做siano" role="presentation" style="position: relative;"&g ...
- BNU 28887——A Simple Tree Problem——————【将多子树转化成线段树+区间更新】
A Simple Tree Problem Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on ZJU. O ...
- POJ3468A Simple Problem with Integers(区间加数求和 + 线段树)
题目链接 题意:两种操作:一是指定区间的数全都加上一个数,二是统计指定区间的和 参考斌神的代码 #include <iostream> #include <cstring> # ...
- 2018.08.04 cogs2633. [HZOI 2016]数列操作e(线段树)
传送门 支持区间加w(i−ql+1)2" role="presentation" style="position: relative;">w(i ...
- 2018.12.23 bzoj2865&&1396: 字符串识别(后缀自动机+线段树)
传送门 卡空间差评! 题意简述:给一个字串,对于每个位置求出经过这个位置且只在字串中出现一次的子串的长度的最小值. 解法:先建出samsamsam,显然只有当sizep=1size_p=1sizep ...
- 2018.11.01 loj#2319. 「NOIP2017」列队(线段树)
传送门 唉突然回忆起去年去noipnoipnoip提高组试水然后省二滚粗的悲惨经历... 往事不堪回首. 所以说考场上真的有debuffdebuffdebuff啊!!!虽然当时我也不会权值线段树 这道 ...
随机推荐
- JSP异常处理
JSP异常处理 当编写JSP程序的时候,程序员可能会遗漏一些BUG,这些BUG可能会出现在程序的任何地方.JSP代码中通常有以下几类异常: 检查型异常:检查型异常就是一个典型的用户错误或者一个程序员无 ...
- Spring Cloud教程(十一)环境变化和刷新范围
应用程序将收听EnvironmentChangeEvent,并以几种标准方式进行更改(用户可以以常规方式添加ApplicationListeners附加ApplicationListeners).当观 ...
- HDU6715 算术(莫比乌斯反演)
HDU6715 算术 莫比乌斯反演的变形. 对 \(\mu(lcm(i,j))\) 变换,易得 \(\mu(lcm(i,j)) = \mu(i)\cdot\mu(j)\cdot \mu(gcd(i,j ...
- Linux内核调试方法总结之内核通知链
Linux内核通知链notifier 1.内核通知链表简介(引用网络资料) 大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣.为了满足这个需求,也即是让某个子系统在 ...
- 004-unity3d MonoBehaviour脚本方法简介
一.MonoBehaviour 1.公共方法 CancelInvoke Cancels all Invoke calls on this MonoBehaviour. Invoke Invokes t ...
- Java 关键字列表
字 描述 abstract 抽象方法,抽象类的修饰符 assert 断言条件是否满足 boolean 布尔数据类型 break 跳出循环或者label代码段 byte 8-bit 有符号数据类型 ca ...
- 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_06 Set集合_1_HashSet集合介绍
特点:不允许有重复的记录,无序的集合 set不允许重复.接口中没有索引.所以方法和Collection中的方法是一样的,没有带索引的方法 因为Set的方法和Collection都是一样的.所以这里不再 ...
- 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_08 Map集合_3_Map接口中的常用方法
这个方法比较特殊,它的返回值是V他也就是Vlaue get remove containsKey: put value没有重复的所以v1返回的是null key值有重复,所以会返回被替换的值,范冰冰1 ...
- jt获取鼠标指针的位置
屏幕 screenX和screenY属性表示鼠标在整个显示屏的位置,从屏幕(而不是浏览器)的左上角开始计算的. 页面 pageX和pageY属性表示鼠标指针在这个页面的位置.页面的顶部可能在可见区域之 ...
- 45 MySQL自增id
45 MySQL自增id 表定义自增id 说到自增id,前面提到mysql的自增id不连续,当表定义的自增值达到上限后的逻辑是:再申请下一个id时,得到的值保持不变 ; insert into t v ...