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 又:区 ...
随机推荐
- mycat 全局表
全局表的作用 在分片的情况下,当业务表因为规模而进行分片以后,业务表与这些附属的字典表之间的关联,就成了比较棘手的问题,考虑到字典表具有以下几个特性: 变动不频繁 数据量总体变化不大 数据规模不大,很 ...
- Vue 全宇宙最浪 VSCode 配置、插件
别人的那一堆配置.插件我就不写了- 首先进入官网下载并安装. 基本配置 在编译器 文件 >> 首选项 >> 设置,可以拷贝相面的选项后搜索相关配置 设置制表符等于空格数为 2: ...
- Nuxt+Vue聊天室|nuxt仿微信App界面|nuxt.js聊天实例
一.项目简述 nuxt-chatroom 基于Nuxt.js+Vue.js+Vuex+Vant+VPopup等技术构建开发的仿微信|探探App界面社交聊天室项目.实现了卡片式翻牌滑动.消息发送/emo ...
- 灵魂拷问:你真的理解System.out.println()执行原理吗?
原创/朱季谦 灵魂拷问,这位独秀同学,你会这道题吗? 请说说,"System.out.println()"原理...... 这应该是刚开始学习Java时用到最多一段代码,迄今为止 ...
- vagrantfile-参考示例
Vagrantfile 文件 bt为你需要新建的box名字 Vagrant.configure("2") do |config| config.vm.box = &qu ...
- kibana-安装-通过docker
拉取镜像 docker pull kibana:7.9.1 创建用户自定义网络 docker network create esnet 运行Kibana docker run --name ...
- php-fpm 高并发 参数调整 转
工作中经常会遇到会给客户配置服务器,其中有的客户还会有并发量要求,其中也会必须要用负载均衡承载压力的.增加服务器数量肯定能有效的提升服务器承载能力,但只有根据目前已有配置设置好单台服务器才能更好的发挥 ...
- centos8平台安装zookeeper3.6集群
一,规划三台zk服务器构成集群 ip:172.18.1.1 机器名:zk1 对应myid: 1 ip:172.18.1.2 机器名:zk2 对应myid: 2 ip:172.18.1.3 机器名:zk ...
- 通透,23 个问题 TCP 疑难杂症全解析
每个时代,都不会亏待会学习的人. 在进入今天主题之前我先抛几个问题,这篇文章一共提出 23 个问题. TCP 握手一定是三次?TCP 挥手一定是四次? 为什么要有快速重传,超时重传不够用?为什么要有 ...
- Flink + 强化学习 搭建实时推荐系统
如今的推荐系统,对于实时性的要求越来越高,实时推荐的流程大致可以概括为这样: 推荐系统对于用户的请求产生推荐,用户对推荐结果作出反馈 (购买/点击/离开等等),推荐系统再根据用户反馈作出新的推荐.这个 ...