题意:给你一个序列,需要支持以下操作: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 吉司机线段树的更多相关文章

  1. 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 ...

  2. AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图

    AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图 链接 AtCoder 大意 在数轴上放上n个点,点i可能的位置有\(x_i\)或者\(y_i\ ...

  3. 2018.07.30 cogs2632. [HZOI 2016] 数列操作d(线段树)

    传送门 线段树基本操作 区间加等差数列,维护区间和. 对于每个区间维护等差数列首项和公差,易证这两个东西都是可合并的,然后使用小学奥数的知识就可以切掉这题. 代码: #include<bits/ ...

  4. 2018.07.25 bzoj3878: [Ahoi2014&Jsoi2014]奇怪的计算器(线段树)

    传送门 线段树综合. 让我想起一道叫做siano" role="presentation" style="position: relative;"&g ...

  5. BNU 28887——A Simple Tree Problem——————【将多子树转化成线段树+区间更新】

    A Simple Tree Problem Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on ZJU. O ...

  6. POJ3468A Simple Problem with Integers(区间加数求和 + 线段树)

    题目链接 题意:两种操作:一是指定区间的数全都加上一个数,二是统计指定区间的和 参考斌神的代码 #include <iostream> #include <cstring> # ...

  7. 2018.08.04 cogs2633. [HZOI 2016]数列操作e(线段树)

    传送门 支持区间加w(i−ql+1)2" role="presentation" style="position: relative;">w(i ...

  8. 2018.12.23 bzoj2865&&1396: 字符串识别(后缀自动机+线段树)

    传送门 卡空间差评! 题意简述:给一个字串,对于每个位置求出经过这个位置且只在字串中出现一次的子串的长度的最小值. 解法:先建出samsamsam,显然只有当sizep=1size_p=1sizep​ ...

  9. 2018.11.01 loj#2319. 「NOIP2017」列队(线段树)

    传送门 唉突然回忆起去年去noipnoipnoip提高组试水然后省二滚粗的悲惨经历... 往事不堪回首. 所以说考场上真的有debuffdebuffdebuff啊!!!虽然当时我也不会权值线段树 这道 ...

随机推荐

  1. Qt中图元对象的多重集成

    在继承自定义QGraphicsItem图元对象时,有时需要用到信号/槽机制,由于QGraphicsItem非QObject的子类 所以需要多重继承QObject,有一点需要特别注意:就是继承的顺序,一 ...

  2. Java数据结构与算法(1):线性表

    线性表是一种简单的数据类型,它是具有相同类型的n个数据元素组成的有限序列.形如如A0,A1,...,An-1.大小为0的表为空表,称Ai后继Ai-1,并称Ai-1前驱Ai. printList打印出表 ...

  3. 安装python是提示 0x80072f7d 错误的解决办法

    最简单的方法: Internet 选项-> 高级里面 勾选使用TLS1.1和使用TLS1.2即可.实际测试是ok的

  4. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_09 序列化流_6_练习_序列化集合

  5. 四种方法给Vmware虚拟机清理瘦身

    随着VMware虚拟机使用时间的增长,其所占用的空间也越来越大,本文来说说怎么给VMware虚拟机占用的空间进行瘦身. **方法一:VMware自带的清理磁盘 **这个方法是VMware自带,具有普适 ...

  6. tensorflow和keras的安装

    1 卸载tensorflow方法,在终端输入:  把protobuf删除了才能卸载干净. sudo pip uninstall protobuf sudo pip uninstall tensorfl ...

  7. SpringMvc @ModelAttribute 的用法

    参考:Spring 3.x 企业应用开发实战   第15章:SpringMvc  页码:532 ModelAttribute 从字面上解释就是模型的属性. 对于MVC框架来说是模型数据是最重要的,因为 ...

  8. git_03_git可视化工具github Desktop使用教程

    前言 github desktop是github的桌面客户端,支持Windows和Mac OS版本.使用简单,可以查看.切换和创建分支,以及提交.合并或部署代码. 下载 由于电脑限制,这里以mac o ...

  9. Cassandra commands

      Common commands:   describe keyspaces // 列出所有db use your_db; // 进去db describe tables; // 列出所有table ...

  10. html5 WebSocket的Js实例教程

    详细解读一个简单+ ,附带完整的javascript websocket实例源码,以及实例代码效果演示页面,并对本实例的核心代码进行了深入解读. 从WebSocket通讯三个阶段(打开握手.数据传递. ...