LOJ #6029. 「雅礼集训 2017 Day1」市场 线段树维护区间除法
题目描述
从前有一个贸易市场,在一位执政官到来之前都是非常繁荣的,自从他来了之后,发布了一系列奇怪的政令,导致贸易市场的衰落。
有 \(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」市场 线段树维护区间除法的更多相关文章
- loj#6029. 「雅礼集训 2017 Day1」市场(线段树)
题意 链接 Sol 势能分析. 除法是不能打标记的,所以只能暴力递归.这里我们加一个剪枝:如果区间内最大最小值的改变量都相同的话,就变成区间减. 这样复杂度是\((n + mlogn) logV\)的 ...
- #6029. 「雅礼集训 2017 Day1」市场 [线段树]
考虑到每次除法,然后加法,差距会变小,于是维护加法lazytag即可 #include <cstdio> #include <cmath> #define int long l ...
- [LOJ 6029]「雅礼集训 2017 Day1」市场
[LOJ 6029] 「雅礼集训 2017 Day1」市场 题意 给定一个长度为 \(n\) 的数列(从 \(0\) 开始标号), 要求执行 \(q\) 次操作, 每次操作为如下四种操作之一: 1 l ...
- 【loj6029】「雅礼集训 2017 Day1」市场 线段树+均摊分析
题目描述 给出一个长度为 $n$ 的序列,支持 $m$ 次操作,操作有四种:区间加.区间下取整除.区间求最小值.区间求和. $n\le 100000$ ,每次加的数在 $[-10^4,10^4]$ 之 ...
- 「雅礼集训 2017 Day1」市场 (线段树除法,区间最小,区间查询)
老师说,你们暴力求除法也整不了多少次就归一了,暴力就好了(应该只有log(n)次) 于是暴力啊暴力,结果我归天了. 好吧,在各种题解的摧残下,我终于出了一篇巨好看(chou lou)代码(很多结构体党 ...
- loj #6032. 「雅礼集训 2017 Day2」水箱 线段树优化DP转移
$ \color{#0066ff}{ 题目描述 }$ 给出一个长度为 \(n\) 宽度为 \(1\) ,高度无限的水箱,有 \(n-1\) 个挡板将其分为 \(n\) 个 \(1 - 1\) 的小格, ...
- [LOJ 6031]「雅礼集训 2017 Day1」字符串
[LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...
- [LOJ 6030]「雅礼集训 2017 Day1」矩阵
[LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...
- loj6029 「雅礼集训 2017 Day1」市场
传送门:https://loj.ac/problem/6029 [题解] 考虑如果有一些近似连续的段 比如 2 2 2 3 3 3,考虑在除3意义下,变成0 0 0 1 1 1,相当于整体-2 又:区 ...
随机推荐
- 用< 100行代码向EPUB或Web服务器添加视频回放
下载source - 32.3 KB 下载latest version from GituHub 介绍 在我 在关于CodeProject的前一篇文章中,我展示了一个简单的EPUB查看器 Androi ...
- idea 2020.1 Mybatis log plugin破解插件
下载 链接: https://pan.baidu.com/s/1FTgtJiyzxxaNxWLyX4OgZw 密码: w7w8 idea安装本地插件
- .Net Core 读取,导入 excel数据 officeopenxml
/// <summary> /// 导出Excel /// </summary> /// <param name="path">路径</p ...
- Linux输入子系统 转载
NQian 记录成长~ 首页 新随笔 联系 订阅 管理 随笔 - 305 文章 - 0 评论 - 254 12.Linux之输入子系统分析(详解) 在此节之前,我们学的都是简单的字符驱动,涉及 ...
- 在Linux命令行内的大小写转换
在编辑文本时大小写常常是需要注意的地方,大小写的转换是很枯燥而繁琐的工作,所幸,Linux 提供了很多能让这份工作变得容易的命令.接下来让我们看看都有哪些完成大小写转换的命令. tr 命令 tr (t ...
- 多测师讲解unittest介绍及自动化测试实现流程_高级讲师肖sir
unittest框架介绍 unittest框架是python中一个标准的库中的一个模块,该模块包括许多的类如 test case类.test suit类.texttest runner类.textte ...
- day05 Pyhton学习
1字典 字符串"" 列表[,] 元祖(,) 字典{:,} 集合{,} 2.增加 dic={} dic['name'] = '周润发' dic.setdefault() 如果dict ...
- swoft生成控制器
[root@localhost swoft]# swoftcli gen:controller -h [ERROR] Command 'controller' is not exist in grou ...
- faker使用
laravel中faker的方法总结 展开 laravel faker用法总结 安装 composer require fzaninotto/faker 一.基础方法: 随机数:randomD ...
- laravel或者lumen门面和服务提供者使用
关于laravel门面和服务提供者使用的一点见解,门面之词,不足之处,还请多多指教. 在laravel中,我们可能需要用到自己添加的类时,可以建立一个文件夹专门存放类文件,也可以使用lara ...