「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希望你能帮助他写 一个程序来模 ...
随机推荐
- Java - 集合 - Map
Map 1.Map实现类:HashMap.Hashtable.LinkedHashMap.TreeMap HashMap 新增元素/获取元素 1 void contextLoads() { 2 //声 ...
- 整体单改,单局部改,整体局部改,ListSerializer类
复习 """ 1.ModelSerializer序列化类 models.py class BaseModel(models.Model): is_delete = mod ...
- [爬坑日记] 安卓模拟器1903蓝屏 没开hyper-v
先说解决方案: 我在升级完1903之后短短几个小时蓝屏了两次 还是不同原因,不由得开始怀疑这个版本的稳定性,随后发现只有启动安卓模拟器的时候必然蓝屏(还有一次蓝屏实在安装驱动的时候) 经过百度得知需要 ...
- 505,display,float,position之间的关系(有疑问)
(display属性设置元素如何显示) 如果display取值为none,那么position和float都不起作用,这种情况下元素不产生框 否则,如果position设置框是绝对定位,float的计 ...
- Docker - 解决docker-machine create下载boot2docker.iso时慢的问题
解决步骤 从https://github.com/boot2docker/boot2docker/releases下载iso到~/.docker/machine/cache/里 docker-mach ...
- Coursera-吴恩达机器学习课程笔记-Week1
参考资料: 吴恩达教授机器学习课程 机器学习课程中文笔记 Week 1 一. 引言 机器学习模型可分为监督学习Superviese learning(每个数据集给出了正确的值)和无监督学习Unsupe ...
- vue 实现简单的富文本编辑
安装:npm install vue-quill-editor --save 安装Vue-Quill-Editor需要依赖: npm install quill --save 在入口文件main.js ...
- 【C语言】创建一个函数,判断某一正整数是否为素数,并调用这个函数找出1000以内所有素数
#include <stdio.h> int fun(int x) { int n; ;n<=x-;n++) ) break; if(n>=x) ; else ; } main ...
- iOS 开发之函数式编程思想(Functional Programming)
函数式编程(Functional Programming), 函数式编程强调的函数:1.不依赖外部状态:2.不改变外部状态. 函数式编程可解决线程安全问题,每一个函数都是线程安全的. 时间状态:变量一 ...
- VS中消除ANSI API警告
最近在VS上写网络程序遇到许多问题,因为VS中将许多ANSI中的API都重写了,那些API大多有漏洞或不能支持现在的一些编程需求了,所以在VS中使用会因为警告而不能用. 但一些老API用着比较方便,了 ...