@uoj - 164@ 【清华集训2015】V
@description@
Picks博士观察完金星凌日后,设计了一个复杂的电阻器。为了简化题目,题目中的常数与现实世界有所不同。
这个电阻器内有编号为 1∼n 的 n 个独立水箱,水箱呈圆柱形,底面积为 1 \(m^2\),每个水箱在顶部和底部各有一个阀门,可以让水以 1 \(m^3/s\) 的流量通过,每个水箱的上阀门接水龙头,可以无限供应水,下阀门不接东西,可以让水流出。水箱顶部和底部都有一个接口,水的电阻率为 1 Ω⋅m。
水箱的高度足够高,有一个导电浮标浮在水面上,通过导线与水箱顶的接口相连。一开始时第 i 个水箱中有 \(a_i\) \(m^3\) 的水。
Picks博士接下来就需要对这个复杂的电阻器进行调试。他会进行以下五种操作。
1、打开编号在 [l,r] 中的所有水箱的上方阀门 x 秒,然后关上它们的上方阀门。
2、打开编号在 [l,r] 中的所有水箱的下方阀门 x 秒,然后关上它们的下方阀门。
3、将编号在 [l,r] 中的所有水箱的下方阀门与大海通过连通器以一定方式相连,使得这些水箱中都恰拥有 \(x\) \(m^3\) 的水,然后关上它们的下方阀门,撤去连通器。
4、在第 y 个水箱的上下方接口处接上一个电动势为 1 V 的电源,电源没有内阻,Picks博士会测量出通过电源的电流大小,之后撤去该电源。
5、由于水浸泡过的地方会留下明显的水渍而没有被水浸泡过的地方不会有,Picks博士可以据此测量出此时第 y 个水箱的水渍高度,以推断曾经最多有多少水,节约他的建造成本。
现在,他请你来帮他做预实验,你能告诉他每次测量得到的电流大小以及测量得到的最多的水量是多少吗?
@solution@
来翻译一遍题目的操作:
t = 1 : [li, ri] 中的所有 aj 变成 aj + xi。
t = 2 : [li, ri] 中的所有 aj 变成 max(aj - xi, 0)。
t = 3 : [li, ri] 中的所有 aj 变成 xi。
t = 4 : 询问 ayi。
t = 5 : 询问 ayi 在历史上的最大值。
可以发现 1 操作也可写成 max(aj + xi, 0),3 操作也可写成 max(-∞, xi),这样所有修改的形式就统一成 max(x + a, b) 了。
两个修改标记的复合为 max(max(x + a1, b1) + a2, b2) = max(x + max(a1, a2), max(b1 + a2, b2))。
注意到这个复合运算满足结合律(但不满足交换律),所以可以用线段树维护。
如何维护历史最大值?我们尝试对两个修改标记取 max:max(max(x + a1, b1), max(x + a2, b2)) = max(x + max(a1, a2), max(b1, b2)),发现是可行的。
于是我们再在每个结点处维护一个历史最大未下传标记即可。
@accepted code@
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 500000;
const ll INF = 1E16;
ll add(ll x, ll y) {
return x + y > INF ? INF : (x + y < -INF ? -INF : x + y);
}
struct tag{
ll a, b; tag() {}
tag(ll _a, ll _b) : a(_a), b(_b) {}
friend tag add(tag a, tag b) {
return tag(add(a.a, b.a), max(add(a.b, b.a), b.b));
}// max(max(x + a.a, a.b) + b.a, b.b)
friend tag max(tag a, tag b) {
return tag(max(a.a, b.a), max(a.b, b.b));
}// max(max(x + a.a, a.b), max(x + b.a, b.b))
};
int a[MAXN + 5];
struct segtree{
#define lch (x << 1)
#define rch (x << 1 | 1)
int le[4*MAXN + 5], ri[4*MAXN + 5];
tag tg[4*MAXN + 5], mt[4*MAXN + 5];
void build(int x, int l, int r) {
le[x] = l, ri[x] = r, tg[x] = tag(0, 0);
if( l == r ) {
tg[x] = mt[x] = tag(a[l], 0);
return ;
}
int m = (l + r) >> 1;
build(lch, l, m), build(rch, m + 1, r);
}
void maintain(int x, tag nwt, tag mxt) {
mt[x] = max(mt[x], add(tg[x], mxt));
tg[x] = add(tg[x], nwt);
}
void pushdown(int x) {
if( tg[x].a || tg[x].b ) {
maintain(lch, tg[x], mt[x]);
maintain(rch, tg[x], mt[x]);
tg[x] = mt[x] = tag(0, 0);
}
}
void modify(int x, int l, int r, tag t) {
if( l > ri[x] || r < le[x] )
return ;
if( l <= le[x] && ri[x] <= r ) {
maintain(x, t, t);
return ;
}
pushdown(x);
modify(lch, l, r, t), modify(rch, l, r, t);
}
tag query(int x, int p, int type) {
if( le[x] == ri[x] ) return (type == 4 ? tg[x] : mt[x]);
int m = (le[x] + ri[x]) >> 1;
pushdown(x);
if( p <= m ) return query(lch, p, type);
else return query(rch, p, type);
}
}T;
int main() {
int n, m; scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++) scanf("%d", &a[i]);
T.build(1, 1, n);
for(int i=1;i<=m;i++) {
int t; scanf("%d", &t);
if( t <= 3 ) {
int l, r, k; tag p; scanf("%d%d%d", &l, &r, &k);
if( t == 1 ) p = tag(k, 0);
if( t == 2 ) p = tag(-k, 0);
if( t == 3 ) p = tag(-INF, k);
T.modify(1, l, r, p);
}
else {
int y; scanf("%d", &y);
tag p = T.query(1, y, t);
printf("%lld\n", max(p.a, p.b));
}
}
}
/*
t = 1 : [li, ri] + x
t = 2 : max([li, ri] - x, 0)
t = 3 : [li, ri] = x
t = 4 : query ax
t = 5 : query history max{ax}
*/
@details@
听说是吉如一线段树(segment tree beats)的一部分来着,不过不是很清楚。
@uoj - 164@ 【清华集训2015】V的更多相关文章
- UOJ #164 [清华集训2015]V (线段树)
题目链接 http://uoj.ac/problem/164 题解 神仙线段树题. 首先赋值操作可以等价于减掉正无穷再加上\(x\). 假设某个位置从前到后的操作序列是: \(x_1,x_2,..., ...
- 清华集训2015 V
#164. [清华集训2015]V http://uoj.ac/problem/164 统计 描述 提交 自定义测试 Picks博士观察完金星凌日后,设计了一个复杂的电阻器.为了简化题目,题目中的常数 ...
- 【uoj#164】[清华集训2015]V 线段树维护历史最值
题目描述 给你一个长度为 $n$ 的序列,支持五种操作: $1\ l\ r\ x$ :将 $[l,r]$ 内的数加上 $x$ :$2\ l\ r\ x$ :将 $[l,r]$ 内的数减去 $x$ ,并 ...
- 「清华集训2015」V
「清华集训2015」V 题目大意: 你有一个序列,你需要支持区间加一个数并对 \(0\) 取 \(\max\),区间赋值,查询单点的值以及单点历史最大值. 解题思路: 观察发现,每一种修改操作都可以用 ...
- [UOJ#274][清华集训2016]温暖会指引我们前行
[UOJ#274][清华集训2016]温暖会指引我们前行 试题描述 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一 ...
- UOJ #164. 【清华集训2015】V | 线段树
题目链接 UOJ #164 题解 首先,这道题有三种询问:区间加.区间减(减完对\(0\)取\(\max\)).区间修改. 可以用一种标记来表示--标记\((a, b)\)表示把原来的值加上\(a\) ...
- UOJ#164:【清华集训2015】V
浅谈区间最值操作与历史最值问题:https://www.cnblogs.com/AKMer/p/10225100.html 题目传送门:http://uoj.ac/problem/164 论文题.论文 ...
- 2018.07.28 uoj#164. 【清华集训2015】V(线段树)
传送门 线段树好题. 要求支持的操作: 1.区间变成max(xi−a,0)" role="presentation" style="position: rela ...
- UOJ #164 【清华集训2015】 V
题目链接:V 这道题由于是单点询问,所以异常好写. 注意到每种修改操作都可以用一个标记\((a,b)\)表示.标记\((a,b)\)的意义就是\(x= \max\{x+a,b\}\) 同时这种标记也是 ...
随机推荐
- Java开发架构篇:领域驱动设计架构基于SpringCloud搭建微服务
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言介绍 微服务不是泥球小单体,而是具备更加清晰职责边界的完整一体的业务功能服务.领域驱动 ...
- POJ2516
题目链接:http://poj.org/problem?id=2516 解题思路: 最小费用最大流,这个没什么疑问.但此题小难点在于读题,大难点在于建图. 首先,供应量小于需求量的时候直接输出“-1” ...
- C# 使用Word模板导出数据
使用NPOI控件导出数据到Word模板中方式: 效果如下: Word模板: 运行结果: 实现如下: Student.cs using System; using System.Collections. ...
- JNPF低代码开发框架代码生成器设计
1.代码生成器目录下有通用开发模板.单表开发模板.多表开发模板.流程表单模板.移动开发模板等: ①代码生成器录下通用开发模板页面,有搜索.上步.下步.下载代码功能操作: ②输入查询条件表名关键字进行搜 ...
- 校园网络 luogu P2812 (又是强联通)
题目传送门!(luogu) 首先考虑问题一 不难想到,如果有一个学校作为终端机,那么跟其处于同一个强联通中的所有学校就可以不用作为终端机了. 那么,问题一也就迎刃而解了:找到所有入度为0的缩点.因为这 ...
- Linux(二):VMware虚拟机中Ubuntu安装详细过程
Linux(二):VMware虚拟机中Ubuntu安装详细过程 目录 1 准备 2 安装 2.1 虚拟机的建立 2.2 虚拟机安装Ubuntu系统 2.3 虚拟机设置 3 完成 1 准备 1.操作系统 ...
- Java中的集合类型体系(一)
Java中的集合类型体系(一) 提问:为什么需要集合? 通常情况下,程序需要根据运行时才知道创建了多少对象.若非程序运行时,而在开发阶段,我们并不知道创建了多少对象,甚至不知道对象的准确类型,为了满足 ...
- seacms_6.4.5 前台任意代码执行漏洞分析
环境搭建 1.下载安装包 下载地址: 链接:https://pan.baidu.com/s/1uw_VnxnvG4GGEae4TRsGGw 密码:cd48 2.常规安装 漏洞复现 poc1: http ...
- PHP获取临时文件的目录路径
PHP获得临时文件的文件目录相对路径,能够 根据tempnam()和sys_get_temp_dir()函数来完成. 下边我们运用简单的代码实例,给大伙儿介绍PHP获得临时文件的文件目录相对路径的方式 ...
- 【JSP】el、jstl、MVC、三层架构
JSP[Java Server Pages] [概念] java服务器页面 简化的servlet设计 html语法中扩展java 跨平台 JSP全名为Java Server Pages,中文名叫jav ...