题目描述

从前有一个贸易市场,在一位执政官到来之前都是非常繁荣的,自从他来了之后,发布了一系列奇怪的政令,导致贸易市场的衰落。

有 \(n\) 个商贩,从\(0 \sim n - 1\) 编号,每个商贩的商品有一个价格\(a_i\),有两种政令:

\(l, r, c\),对于\(i \in [l, r], a_i \leftarrow a_i + c\)

\(l, r, d\),对于\(i \in [l, r], a_i \leftarrow \lfloor {a_i}/{d} \rfloor\)

现在有一个外乡的旅客想要了解贸易市场的信息,有两种询问方式:

给定 \(l, r\),求\(\min_{i \in [l, r]} a_i\)

给定 \(l, r\),求\(\sum_{i\in [l, r]} a_i\)

输入格式

第一行为两个空格隔开的整数 \(n, q\) 分别表示商贩个数和政令 \(+\) 询问个数。

第二行包含 \(n\) 个由空格隔开的整数\(a_0 \sim a_{n - 1}\)

接下来 \(q\) 行,每行表示一个操作,第一个数表示操作编号\(1 \sim 4\),接下来的输入和问题描述一致。

输出格式

对于每个 \(3\)、\(4\) 操作,输出询问答案。

样例

样例输入

10 10

-5 -4 -3 -2 -1 0 1 2 3 4

1 0 4 1

1 5 9 1

2 0 9 3

3 0 9

4 0 9

3 0 1

4 2 3

3 4 5

4 6 7

3 8 9

样例输出

-2

-2

-2

-2

0

1

1

数据范围与提示

对于 \(30\%\) 的数据,$n, q \leq 10 ^ 3 $;

对于 \(60\%\) 的数据,保证数据随机;

对于 \(100\%\) 的数据,\(1 \leq n, q \leq 10 ^ 5, 0 \leq l \leq r \leq n - 1, c \in [-10 ^ {4}, 10 ^ 4], d \in [2, 10 ^ 9]\)

分析

对于区间加、区间求和、区间求最小值的操作,像正常的线段树那样维护即可

对于区间除的操作,因为题目中要求向下取整,所以不能直接给整体除一个数

但是我们可以把除法转化为减法,把除以一个数变成减去一个数

这样,当一个区间内减去的数相同时,我们就可以给整体打一个标记

判断区间减去的数是否相同只需要判断区间最大值和区间最小值减去的值是否相同

如果不相同就一直下放,直到相同为止

这样的话我们再记录一个最大值就可以解决了

时间复杂度:\(O(可过)\)

代码

#include <cstdio>
#include <algorithm>
#include <cmath>
#define rg register
inline int read() {
rg int x = 0, fh = 1;
rg char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
fh = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * fh;
}
const int maxn = 1e5 + 5;
int a[maxn], n, q;
struct trr {
int l, r, laz, mmin, mmax, siz;
long long sum;
} tr[maxn << 2];
void push_up(int da) {
tr[da].mmax = std::max(tr[da << 1].mmax, tr[da << 1 | 1].mmax);
tr[da].mmin = std::min(tr[da << 1].mmin, tr[da << 1 | 1].mmin);
tr[da].sum = tr[da << 1].sum + tr[da << 1 | 1].sum;
}
void push_down(int da) {
if (tr[da].laz) {
tr[da << 1].laz += tr[da].laz;
tr[da << 1 | 1].laz += tr[da].laz;
tr[da << 1].sum += 1LL * tr[da << 1].siz * tr[da].laz;
tr[da << 1 | 1].sum += 1LL * tr[da << 1 | 1].siz * tr[da].laz;
tr[da << 1].mmax += tr[da].laz;
tr[da << 1 | 1].mmax += tr[da].laz;
tr[da << 1].mmin += tr[da].laz;
tr[da << 1 | 1].mmin += tr[da].laz;
tr[da].laz = 0;
}
}
void build(int da, int l, int r) {
tr[da].l = l, tr[da].r = r, tr[da].siz = r - l + 1;
if (tr[da].l == tr[da].r) {
tr[da].mmin = tr[da].mmax = a[l];
tr[da].sum = a[l];
return;
}
rg int mids = (tr[da].l + tr[da].r) >> 1;
build(da << 1, l, mids);
build(da << 1 | 1, mids + 1, r);
push_up(da);
}
void ad(int da, int l, int r, int val) {
if (tr[da].l >= l && tr[da].r <= r) {
tr[da].laz += val;
tr[da].sum += 1LL * val * tr[da].siz;
tr[da].mmin += val;
tr[da].mmax += val;
return;
}
push_down(da);
rg int mids = (tr[da].l + tr[da].r) >> 1;
if (l <= mids)
ad(da << 1, l, r, val);
if (r > mids)
ad(da << 1 | 1, l, r, val);
push_up(da);
}
int cxmin(int da, int l, int r) {
if (tr[da].l >= l && tr[da].r <= r) {
return tr[da].mmin;
}
push_down(da);
rg int mids = (tr[da].l + tr[da].r) >> 1, nans = 2147483647;
if (l <= mids)
nans = std::min(nans, cxmin(da << 1, l, r));
if (r > mids)
nans = std::min(nans, cxmin(da << 1 | 1, l, r));
return nans;
}
long long cxsum(int da, int l, int r) {
if (tr[da].l >= l && tr[da].r <= r) {
return tr[da].sum;
}
push_down(da);
rg int mids = (tr[da].l + tr[da].r) >> 1;
rg long long nans = 0;
if (l <= mids)
nans += cxsum(da << 1, l, r);
if (r > mids)
nans += cxsum(da << 1 | 1, l, r);
return nans;
}
void cf(int da, int l, int r, int val) {
if (tr[da].l >= l && tr[da].r <= r) {
rg int now1 = floor((double)tr[da].mmin / val) - tr[da].mmin;
rg int now2 = floor((double)tr[da].mmax / val) - tr[da].mmax;
if (tr[da].l == tr[da].r) {
tr[da].mmin = floor((double)tr[da].mmin / val);
tr[da].sum = tr[da].mmax = tr[da].mmin;
} else if (now1 == now2) {
tr[da].mmin += now1;
tr[da].mmax += now1;
tr[da].laz += now1;
tr[da].sum += 1LL * tr[da].siz * now1;
} else {
push_down(da);
cf(da << 1, l, r, val);
cf(da << 1 | 1, l, r, val);
push_up(da);
}
return;
}
push_down(da);
rg int mids = (tr[da].l + tr[da].r) >> 1;
if (l <= mids)
cf(da << 1, l, r, val);
if (r > mids)
cf(da << 1 | 1, l, r, val);
push_up(da);
}
int main() {
n = read(), q = read();
for (rg int i = 1; i <= n; i++) {
a[i] = read();
}
build(1, 1, n);
rg int aa, bb, cc, dd;
for (rg int i = 1; i <= q; i++) {
aa = read(), bb = read(), cc = read();
bb++, cc++;
if (aa == 1) {
dd = read();
ad(1, bb, cc, dd);
} else if (aa == 2) {
dd = read();
cf(1, bb, cc, dd);
} else if (aa == 3) {
printf("%d\n", cxmin(1, bb, cc));
} else {
printf("%lld\n", cxsum(1, bb, cc));
}
}
return 0;
}

LOJ #6029. 「雅礼集训 2017 Day1」市场 线段树维护区间除法的更多相关文章

  1. loj#6029. 「雅礼集训 2017 Day1」市场(线段树)

    题意 链接 Sol 势能分析. 除法是不能打标记的,所以只能暴力递归.这里我们加一个剪枝:如果区间内最大最小值的改变量都相同的话,就变成区间减. 这样复杂度是\((n + mlogn) logV\)的 ...

  2. #6029. 「雅礼集训 2017 Day1」市场 [线段树]

    考虑到每次除法,然后加法,差距会变小,于是维护加法lazytag即可 #include <cstdio> #include <cmath> #define int long l ...

  3. [LOJ 6029]「雅礼集训 2017 Day1」市场

    [LOJ 6029] 「雅礼集训 2017 Day1」市场 题意 给定一个长度为 \(n\) 的数列(从 \(0\) 开始标号), 要求执行 \(q\) 次操作, 每次操作为如下四种操作之一: 1 l ...

  4. 【loj6029】「雅礼集训 2017 Day1」市场 线段树+均摊分析

    题目描述 给出一个长度为 $n$ 的序列,支持 $m$ 次操作,操作有四种:区间加.区间下取整除.区间求最小值.区间求和. $n\le 100000$ ,每次加的数在 $[-10^4,10^4]$ 之 ...

  5. 「雅礼集训 2017 Day1」市场 (线段树除法,区间最小,区间查询)

    老师说,你们暴力求除法也整不了多少次就归一了,暴力就好了(应该只有log(n)次) 于是暴力啊暴力,结果我归天了. 好吧,在各种题解的摧残下,我终于出了一篇巨好看(chou lou)代码(很多结构体党 ...

  6. loj #6032. 「雅礼集训 2017 Day2」水箱 线段树优化DP转移

    $ \color{#0066ff}{ 题目描述 }$ 给出一个长度为 \(n\) 宽度为 \(1\) ,高度无限的水箱,有 \(n-1\) 个挡板将其分为 \(n\) 个 \(1 - 1\) 的小格, ...

  7. [LOJ 6031]「雅礼集训 2017 Day1」字符串

    [LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...

  8. [LOJ 6030]「雅礼集训 2017 Day1」矩阵

    [LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...

  9. loj6029 「雅礼集训 2017 Day1」市场

    传送门:https://loj.ac/problem/6029 [题解] 考虑如果有一些近似连续的段 比如 2 2 2 3 3 3,考虑在除3意义下,变成0 0 0 1 1 1,相当于整体-2 又:区 ...

随机推荐

  1. 5-kunernetes资源调度

    1.创建一个pod的工作流程 master节点组件 1.apiserver --> etcd 2.scheduler 3.controller-manager node节点有那些组件 1.kub ...

  2. SHOI 2014 【概率充电器】

    加油,两道了,也就还剩那么二十来道吧,慢慢做...... 题目大意: 给你一颗树,树上的每一个节点都有一定的概率p[i]能冲上电,有电的点,可以通过树上的边,一定概率地将电传递到与它相邻的点,同时对于 ...

  3. 访问 LNMP 报 502 Bad Gateway 错误的解决办法

    LNMP : Linux + Nginx + MySQL + PHP Nginx 出现502有很多原因,但大部分原因可以归结为资源数量不够用,也就是说后端 PHP-FPM 处理有问题,Nginx 将正 ...

  4. shell-变量的数值运算与特殊应用expr

    1. expr(evaluate expressions)命令的用法: expr命令一般用于整数值,当也可用于字符串,用来求表达式变量的值,同时expr也是一个手工命令行计算器. 语法:expr ex ...

  5. linux CentOS7 防火墙操作

    1, 查看防火墙状态: firewall-cmd --state systemctl status firewalld.service 2, 开启防火墙: systemctl start firewa ...

  6. Springboot+JPA下实现简易爬虫:豆瓣电视剧数据

    Springboot+JPA下实现简易爬虫:豆瓣电视剧数据 前言:今天听到产品那边讨论一些需求,好像其中一点是用户要求我们爬虫,在网页上抓取一些数据然后存到我们公司数据库中,众所周知,爬虫的实现对于p ...

  7. 协同开发功能——Github团队协作

    最近需要写一个HoloLens开发的简明介绍,其中要测试几个demo.用到github以团队协作,像下面是简单的事件记录. 一.创建项目 1. 2.项目设置 名称 描述description Init ...

  8. apache自带的ab测试失败请求原因

    只要出现 Failed requests 就会多出现一行要求失败的各原因的数据统计,分别有 Connect, Length, 与 Exception 三种,分别代表的意义为:Connect       ...

  9. flink 处理实时数据的三重保障

    flink 处理实时数据的三重保障 window+watermark 来处理乱序数据对于 TumblingEventTimeWindows window 的元数据startTime,endTime 和 ...

  10. 5G-第五代移动通信系统(5th generation mobile/wireless/cellular system)

    通信系统 有意义的信息交流被称为通讯. 自然界:狼嚎.狗叫.虫鸣.鸡叫. 人类社会:说话.眼神.写信.烽火台. 目的:信息的传递. 人类发明电以后,开始使用电来传递信息,特别快. 于是有了电报.电话以 ...