UOJ#164:【清华集训2015】V
浅谈区间最值操作与历史最值问题:https://www.cnblogs.com/AKMer/p/10225100.html
题目传送门:http://uoj.ac/problem/164
论文题。论文做法如下:
首先我们定义一种标记\((a,b)\),表示给这个区间先加上\(a\)再跟\(b\)取\(max\),不难发现题目里提到的三种操作分别都可以用这样的标记来代替:
1、区间加\(v\):\((v,-inf)\)
2、区间减\(v\):\((-v,0)\)
3、区间覆盖:\((-inf,v)\)
考虑合并两个标记\((a,b),(c,d)\),那么就会变成\((a+c,max(b+c,d))\)。
现在考虑历史标记最大值,对于一个标记,我们可以将它看成是一个分段函数。第一段的函数是\(y=b\),第二段的函数是\(y=x+a\)。那么历史最大标记则可以用\((max(a,c),max(b,d))\)来表示。如下图,红色的部分就是历史标记最大值:
时间复杂度:\(O(nlogn)\)
空间复杂度:\(O(n)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll inf=1e18;
const int maxn=5e5+5;
int n,m;
int a[maxn];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct segment_tree {
struct tag {
ll add,mx;
void init() {
add=0,mx=-inf;
}
tag() {}
tag(ll _add,ll _mx) {
add=_add,mx=_mx;
}
tag operator+(const tag &a)const {
return tag(max(-inf,add+a.add),max(mx+a.add,a.mx));
}
tag operator*(const tag &a)const {
return tag(max(add,a.add),max(mx,a.mx));
}
};
struct tree_node {
ll hismx,mx;
tag his,now;
}tree[maxn<<2];
void update(int p) {
tree[p].mx=max(tree[p<<1].mx,tree[p<<1|1].mx);
tree[p].hismx=max(tree[p<<1].hismx,tree[p<<1|1].hismx);
}
void build(int p,int l,int r) {
tree[p].his.init(),tree[p].now.init();
if(l==r) {tree[p].hismx=tree[p].mx=a[l];return;}
int mid=(l+r)>>1;
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
update(p);
}
void make_tag(int p,tag now,tag his) {
tree[p].his=tree[p].his*(tree[p].now+his);
tree[p].now=tree[p].now+now;
ll res=max(tree[p].mx+his.add,his.mx);
tree[p].hismx=max(tree[p].hismx,res);
tree[p].mx=max(tree[p].mx+now.add,now.mx);
}
void push_down(int p) {
make_tag(p<<1,tree[p].now,tree[p].his);
make_tag(p<<1|1,tree[p].now,tree[p].his);
tree[p].now.init(),tree[p].his.init();
}
void change(int p,int l,int r,int L,int R,ll v,ll mx) {
if(L<=l&&r<=R) {make_tag(p,tag(v,mx),tag(v,mx));return;}
int mid=(l+r)>>1;push_down(p);
if(L<=mid)change(p<<1,l,mid,L,R,v,mx);
if(R>mid)change(p<<1|1,mid+1,r,L,R,v,mx);
update(p);
}
ll query(int p,int l,int r,int pos,int opt) {
if(l==r) return opt==4?tree[p].mx:tree[p].hismx;
int mid=(l+r)>>1;push_down(p);
if(pos<=mid)return query(p<<1,l,mid,pos,opt);
else return query(p<<1|1,mid+1,r,pos,opt);
}
}T;
int main() {
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read();
T.build(1,1,n);
for(int i=1;i<=m;i++) {
int opt=read(),l=0,r=0,v=0,pos=0;
if(opt>3)pos=read();
else l=read(),r=read(),v=read();
if(opt==1)T.change(1,1,n,l,r,v,-inf);
if(opt==2)T.change(1,1,n,l,r,-v,0);
if(opt==3)T.change(1,1,n,l,r,-inf,v);
if(opt>3)printf("%lld\n",T.query(1,1,n,pos,opt));
}
return 0;
}
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\) ...
- 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\}\) 同时这种标记也是 ...
- @uoj - 164@ 【清华集训2015】V
目录 @description@ @solution@ @accepted code@ @details@ @description@ Picks博士观察完金星凌日后,设计了一个复杂的电阻器.为了简化 ...
随机推荐
- windowsphone8.1学习笔记之位图编程
说位图,先把image控件简单过下,Image的Source设置 <Image Name="img" Source="可以是网络图片的Uri.应用文件的Uri或者安 ...
- [luogu3413]萌数
[luogu3413]萌数 luogu 考虑数位dp 怎么判断一个数是不是萌数? 只要知道其中某一位和它的前一位相等或者和前一位的前一位相等,那么它就是一个萌数 什么样的数不是萌数? 对于它的每一位都 ...
- anaconda + opencv3
直接运行 pip install opencv-python 或者 pip install opencv-contrib-python 参照如下网页 https://blog.csdn.net/sin ...
- python实例1:创建一个登陆模块
实现功能: 1.用户输入账户密码 2.验证账户是否存在于黑名单,如果存在于黑名单,则执行1,否则往下执行 3.验证用户名和密码. 3.1.如果验证成功,则打印欢迎信息并退出程序: 3.2.如果用户名存 ...
- ZOJ - 1505 Solitaire 【双向BFS】
题目链接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1505 题意 一个8 * 8 的棋盘上面有四个棋子 棋子可以上下左 ...
- 导出数据到表格PHP
导出数据到表格 public function excel(){ $filename = '导出表格'; $header = ['编号','名称']; $index = ['id','name']; ...
- MySQL的进程状态
通过show processlist查看MySQL的进程状态,在State列上面的状态有如下这些: Analyzing线程对MyISAM 表的统计信息做分析(例如, ANALYZE TABLE ).c ...
- java网络爬虫爬虫小栗子
简要介绍: 使用java开发的爬虫小栗子,存储到由zookeeper协调的hbase中 主要过程是模拟Post请求和get请求,html解析,hbase存储 源码:https://github.com ...
- UNIDBgrid里动态添加clientevents实现回车替换TAB
//GRID里回车替换TABfunction cellkeydown(sender, td, cellIndex, record, tr, rowIndex, e, eOpts){ if (e.get ...
- linux rpm包的编译
有些软件包的特性是编译者选定的,如果编译未选定此特性,将无法使用.rpm包的版本落后于源码包. 因此需要定制安装,也就是手动编译安装. 编译需要编译环境. 编译的过程如下: 1.下载源码 2.执行 t ...