「AHOI2014/JSOI2014」奇怪的计算器
「AHOI2014/JSOI2014」奇怪的计算器
传送门
我拿到这题首先是懵b的,因为感觉没有任何性质。。。
后来经过同机房dalao的指导发现可以把所有的 \(X\) 放到一起排序,然后我们可以发现每次操作都不会改变这个排完序之后的序列的单调性(始终单调不降),也就是说如果其中有一次操作使得数列中的某些数越界了,那么肯定是一个前缀或一个后缀,分别对应向下和向上越界。
然后我们就可以用线段树来搞,每次操作直接用线段树区间修改实现(具体细节待会讲),判断越界的话,我们就存一下区间的最小值和最大值,根据序列单调不降的性质,最小值就是区间左端点的值,最大值就是区间右端点的值,那么我们就可以在线段树上二分+区间赋值来实现批量处理越界的数。
那么接下来就讲一讲区间修改的一种巧妙实现方式:
其实很简单,我们把每次区间修改都写成 \(s_i \leftarrow s_i \times k_1 + a_i \times k_2 + k_3\) 的形式。
那么我们就可以通过调整参数 \(k_1, k_2, k_3\) 的值来很方便地实现区间加法、区间乘法、区间加上 \(a \times x\)、区间赋值的操作了。
参考代码:
#include <algorithm>
#include <cstdio>
#define rg register
#define int long long
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while ('0' > c || c > '9') f |= c == '-', c = getchar();
while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
}
const int _ = 1e5 + 5;
int n, m, L, R, ans[_]; pair < int, int > a[_];
struct ask { int opt, x; } p[_];
struct node { int mn, mx, tag1, tag2, tag3; } t[_ << 2];
inline int lc(int p) { return p << 1; }
inline int rc(int p) { return p << 1 | 1; }
inline void pushup(int p) { t[p].mn = t[lc(p)].mn, t[p].mx = t[rc(p)].mx; }
inline void f(int p, int l, int r, int tag1, int tag2, int tag3) {
t[p].tag1 = t[p].tag1 * tag1;
t[p].tag2 = t[p].tag2 * tag1 + tag2;
t[p].tag3 = t[p].tag3 * tag1 + tag3;
t[p].mn = t[p].mn * tag1 + a[l].first * tag2 + tag3;
t[p].mx = t[p].mx * tag1 + a[r].first * tag2 + tag3;
}
inline void pushdown(int p, int l, int r, int mid) {
f(lc(p), l, mid, t[p].tag1, t[p].tag2, t[p].tag3);
f(rc(p), mid + 1, r, t[p].tag1, t[p].tag2, t[p].tag3);
t[p].tag1 = 1, t[p].tag2 = t[p].tag3 = 0;
}
inline void build(int p = 1, int l = 1, int r = m) {
t[p].tag1 = 1, t[p].tag2 = t[p].tag3 = 0;
if (l == r) { t[p].mn = t[p].mx = a[l].first; return ; }
int mid = (l + r) >> 1;
build(lc(p), l, mid), build(rc(p), mid + 1, r), pushup(p);
}
inline void update_mn(int p = 1, int l = 1, int r = m) {
if (l == r) { f(p, l, r, 0, 0, L); return ; }
int mid = (l + r) >> 1;
pushdown(p, l, r, mid);
if (t[rc(p)].mn < L) f(lc(p), l, mid, 0, 0, L), update_mn(rc(p), mid + 1, r);
else update_mn(lc(p), l, mid);
pushup(p);
}
inline void update_mx(int p = 1, int l = 1, int r = m) {
if (l == r) { f(p, l, r, 0, 0, R); return ; }
int mid = (l + r) >> 1;
pushdown(p, l, r, mid);
if (t[lc(p)].mx > R) f(rc(p), mid + 1, r, 0, 0, R), update_mx(lc(p), l, mid);
else update_mx(rc(p), mid + 1, r);
pushup(p);
}
inline void query(int p = 1, int l = 1, int r = m) {
if (l == r) { ans[a[l].second] = t[p].mn; return ; }
int mid = (l + r) >> 1;
pushdown(p, l, r, mid);
query(lc(p), l, mid), query(rc(p), mid + 1, r);
}
inline int cg(char c) {
if (c == '+') return 1; if (c == '-') return 2; if (c == '*') return 3; if (c == '@') return 4;
}
signed main() {
#ifndef ONLINE_JUDGE
file("cpp");
#endif
read(n), read(L), read(R);
char s[5];
for (rg int x, i = 1; i <= n; ++i) scanf("%s", s), read(x), p[i] = (ask) { cg(s[0]), x };
read(m);
for (rg int x, i = 1; i <= m; ++i) read(x), a[i] = make_pair(x, i);
sort(a + 1, a + m + 1), build();
for (rg int i = 1; i <= n; ++i) {
if (p[i].opt == 1) f(1, 1, m, 1, 0, p[i].x);
if (p[i].opt == 2) f(1, 1, m, 1, 0, -p[i].x);
if (p[i].opt == 3) f(1, 1, m, p[i].x, 0, 0);
if (p[i].opt == 4) f(1, 1, m, 1, p[i].x, 0);
if (t[1].mn < L) update_mn();
if (t[1].mx > R) update_mx();
}
query();
for (rg int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
return 0;
}
「AHOI2014/JSOI2014」奇怪的计算器的更多相关文章
- 「AHOI2014/JSOI2014」宅男计划
「AHOI2014/JSOI2014」宅男计划 传送门 我们首先要发现一个性质:存货天数随买食物的次数的变化类似于单峰函数. 具体证明不会啊,好像是二分加三分来证明?但是没有找到明确的严格证明. 感性 ...
- 「AHOI2014/JSOI2014」拼图
「AHOI2014/JSOI2014」拼图 传送门 看到 \(n \times m \le 10^5\) ,考虑根号分治. 对于 \(n < m\) 的情况,我们可以枚举最终矩形的上下边界 \( ...
- 「AHOI2014/JSOI2014」骑士游戏
「AHOI2014/JSOI2014」骑士游戏 传送门 考虑 \(\text{DP}\). 设 \(dp_i\) 表示灭种(雾)一只编号为 \(i\) 的怪物的代价. 那么转移显然是: \[dp_i ...
- 「AHOI2014/JSOI2014」支线剧情
「AHOI2014/JSOI2014」支线剧情 传送门 上下界网络流. 以 \(1\) 号节点为源点 \(s\) ,新建一个汇点 \(t\),如果 \(u\) 能到 \(v\),那么连边 \(u \t ...
- #3144. 「APIO 2019」奇怪装置
#3144. 「APIO 2019」奇怪装置 题目描述 考古学家发现古代文明留下了一种奇怪的装置.该装置包含两个屏幕,分别显示两个整数 \(x\) 和 \(y\). 经过研究,科学家对该装置得出了一个 ...
- 「UNR#1」奇怪的线段树
「UNR#1」奇怪的线段树 一道好题,感觉解法非常自然. 首先我们只需要考虑一次染色最下面被包含的那些区间,因为把无解判掉以后只要染了一个节点,它的祖先也一定被染了.然后发现一次染色最下面的那些区间一 ...
- 【LOJ #3144】「APIO 2019」奇怪装置
题意: 定义将一个\(t\)如下转换成一个二元组: \[ f(t) = \begin{cases} x = (t + \left\lfloor \frac{t}{B} \right \rfloor) ...
- 「APIO 2019」奇怪装置
题目 考虑推柿子 最开始的想法是如果两个\(t\)在\(mod\ B\)意义下相等,那么只需要比较一下\((t+\left \lfloor \frac{t}{B}\rfloor \right)mod\ ...
- BZOJ3878: [Ahoi2014&Jsoi2014]奇怪的计算器
BZOJ3878: [Ahoi2014&Jsoi2014]奇怪的计算器 Description [故事背景] JYY有个奇怪的计算器,有一天这个计算器坏了,JYY希望你能帮助他写 一个程序来模 ...
随机推荐
- mybatis--Spring整合mybatis
今天学习了mybatis整合Spring开发,做了一个mybatis+spring的小实例 (1)首先,创建数据库my,并在数据库my中创建表user create database my; use ...
- Ubuntu中获取和使用uiautomatorviewer
图省事的办法是直接在网上找个android platform tools的某个版本下载下来 比如这个网站里面的:Android SDK工具——Platform-tools 个人比较倾向于先下载andr ...
- Spring - Spring 常用注解
概述 简单整理一些 Spring 的注解 这个算是一个 水一波 类型的整理 内容不全 分类可能有的地方不会太符合逻辑 而且时间也不太充裕 先把自己想写的写下来, 然后随缘整理吧 约定 版本 Sprin ...
- 【Vue实例生命周期】
目录 实例创建之前执行--beforeCreate 实例创建之后执行--created 挂载之前执行--beforeMount 挂载之后执行--mounted 数据更新之前执行--beforeUpda ...
- 安装rpm包时提示错误:依赖检测失败的解决方法
安装rpm包时提示错误:依赖检测失败 解决方法: 命令末尾加上--nodeps --force
- ENS中文文档系列之三 [ ENS常见问题 ]
原文地址:https://ensuser.com/docs/frequently-asked-questions.html更多最新信息,请前往 ENS 中文服务站点:ENSUser 关于 ENS 注册 ...
- 台电X16pro刷机记录
Android: 如果要刷安卓,需要使用win7系统电脑,且需要安装java环境,同时按住 音量减+电源键进入刷机模式(DNX BOOT MODE..),这时在PhoneFlashTool_5.3.2 ...
- jenkins介绍及部署tomcat环境、部署Maven项目及密码忘记修改
安装配置jenkins: jenkins安装方式一:war包 1.先安装tomcat将jenkins,war直接放到webapps目录下 2.通过java-jar jenkins.war --http ...
- 「JSOI2015」salesman
「JSOI2015」salesman 传送门 显然我们为了使收益最大化就直接从子树中选大的就好了. 到达次数的限制就是限制了可以选的子树的数量,因为每次回溯上来都会减一次到达次数. 多种方案的判断就是 ...
- 计算机二级-C语言-对结构体数据进行求平均值。对结构体数据进行比较处理。
//函数fun的功能是:计算形参x所指数组中N个数的平均值(规定所有数均为正数),作为函数返回,并将大于平均值的数放在形参y所指数组中,在主函数中输出. //重难点:对结构体数据进行求平均值. #in ...