题意:给你一个序列,需要支持以下操作: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. android 开发,视频群聊引发短信异常

    说到 NDK 开发,其实是为了有些时候为了项目需求需要调用底层的一些 C/C++ 的一些东西:另外就是为了效率更加高些. 但是很多时候能不用就不用:这个是啥原因?个人感觉有些时候是觉得麻烦,首先要配置 ...

  2. UOJ37. 【清华集训2014】主旋律

    http://uoj.ac/problem/37 题解 题目是让我们求出有多少个边集可以使这张图强连通. 先补集转化一下,求这张图不强连通的方案数. 我们考虑这样的图缩完点之后的情况,既然不强连通,那 ...

  3. SpringBoot项目属性配置-第二章

    SpringBoot入门 1. 相信很多人选择Spring Boot主要是考虑到它既能兼顾Spring的强大功能,还能实现快速开发的便捷.我们在Spring Boot使用过程中,最直观的感受就是没有了 ...

  4. 手把手教你学Vue-3(路由)

    1.路由的作用 1.当我们有多个页面的时候 ,我们需要使用路由,将组件(components)映射到路由(routes),然后告诉 vue-router 在哪里渲染它们. 简单的路由 const ro ...

  5. 三十五、robotframework中怎么将100转化成100.00

    1.将100转化成100.00

  6. JS-Array.prototype 中的方法的坑

    fill() 今天刷 HackerRank 的题遇到需要创建链表数组(一维数组的每一项是个链表)的题. 众所周知 JS 中的数组可以当链表用,我就用如下代码进行创建 let seqs = (new A ...

  7. python上下文管理,with语句

    今天在网上看到一段代码,其中使用了with seam:初见不解其意,遂查询资料. 代码: #! /usr/bin/env python # -*- coding:utf-8 -*- import ti ...

  8. ubuntu 安装 rocketmq

    1.安装 rocketmq首先要有java以及maven环境,这里略过,可参考 https://www.cnblogs.com/xiaobaoTribe/p/11315011.html  安装JDK ...

  9. 解决Nginx反向代理不会自动对特殊字符进行编码的问题 如gitblit中的~波浪线

    问题起因是利用Nginx做反向代理的时候,需要访问如下链接http://192.168.14.141/iserver/services/3D-0524hd/rest/realspace/datas/0 ...

  10. Postman—上个接口返回数据作为下个接口入参

    //将数据解析成json格式 var data=JSON.parse(responseBody); //获取totalRentPrice值 var totalRentPrice=jsonData.da ...