浅谈区间最值操作与历史最值问题: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的更多相关文章

  1. UOJ #164 [清华集训2015]V (线段树)

    题目链接 http://uoj.ac/problem/164 题解 神仙线段树题. 首先赋值操作可以等价于减掉正无穷再加上\(x\). 假设某个位置从前到后的操作序列是: \(x_1,x_2,..., ...

  2. 清华集训2015 V

    #164. [清华集训2015]V http://uoj.ac/problem/164 统计 描述 提交 自定义测试 Picks博士观察完金星凌日后,设计了一个复杂的电阻器.为了简化题目,题目中的常数 ...

  3. 【uoj#164】[清华集训2015]V 线段树维护历史最值

    题目描述 给你一个长度为 $n$ 的序列,支持五种操作: $1\ l\ r\ x$ :将 $[l,r]$ 内的数加上 $x$ :$2\ l\ r\ x$ :将 $[l,r]$ 内的数减去 $x$ ,并 ...

  4. 「清华集训2015」V

    「清华集训2015」V 题目大意: 你有一个序列,你需要支持区间加一个数并对 \(0\) 取 \(\max\),区间赋值,查询单点的值以及单点历史最大值. 解题思路: 观察发现,每一种修改操作都可以用 ...

  5. [UOJ#274][清华集训2016]温暖会指引我们前行

    [UOJ#274][清华集训2016]温暖会指引我们前行 试题描述 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一 ...

  6. UOJ #164. 【清华集训2015】V | 线段树

    题目链接 UOJ #164 题解 首先,这道题有三种询问:区间加.区间减(减完对\(0\)取\(\max\)).区间修改. 可以用一种标记来表示--标记\((a, b)\)表示把原来的值加上\(a\) ...

  7. 2018.07.28 uoj#164. 【清华集训2015】V(线段树)

    传送门 线段树好题. 要求支持的操作: 1.区间变成max(xi−a,0)" role="presentation" style="position: rela ...

  8. UOJ #164 【清华集训2015】 V

    题目链接:V 这道题由于是单点询问,所以异常好写. 注意到每种修改操作都可以用一个标记\((a,b)\)表示.标记\((a,b)\)的意义就是\(x= \max\{x+a,b\}\) 同时这种标记也是 ...

  9. @uoj - 164@ 【清华集训2015】V

    目录 @description@ @solution@ @accepted code@ @details@ @description@ Picks博士观察完金星凌日后,设计了一个复杂的电阻器.为了简化 ...

随机推荐

  1. windowsphone8.1学习笔记之位图编程

    说位图,先把image控件简单过下,Image的Source设置 <Image Name="img" Source="可以是网络图片的Uri.应用文件的Uri或者安 ...

  2. [luogu3413]萌数

    [luogu3413]萌数 luogu 考虑数位dp 怎么判断一个数是不是萌数? 只要知道其中某一位和它的前一位相等或者和前一位的前一位相等,那么它就是一个萌数 什么样的数不是萌数? 对于它的每一位都 ...

  3. anaconda + opencv3

    直接运行 pip install opencv-python 或者 pip install opencv-contrib-python 参照如下网页 https://blog.csdn.net/sin ...

  4. python实例1:创建一个登陆模块

    实现功能: 1.用户输入账户密码 2.验证账户是否存在于黑名单,如果存在于黑名单,则执行1,否则往下执行 3.验证用户名和密码. 3.1.如果验证成功,则打印欢迎信息并退出程序: 3.2.如果用户名存 ...

  5. ZOJ - 1505 Solitaire 【双向BFS】

    题目链接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1505 题意 一个8 * 8 的棋盘上面有四个棋子 棋子可以上下左 ...

  6. 导出数据到表格PHP

    导出数据到表格 public function excel(){ $filename = '导出表格'; $header = ['编号','名称']; $index = ['id','name']; ...

  7. MySQL的进程状态

    通过show processlist查看MySQL的进程状态,在State列上面的状态有如下这些: Analyzing线程对MyISAM 表的统计信息做分析(例如, ANALYZE TABLE ).c ...

  8. java网络爬虫爬虫小栗子

    简要介绍: 使用java开发的爬虫小栗子,存储到由zookeeper协调的hbase中 主要过程是模拟Post请求和get请求,html解析,hbase存储 源码:https://github.com ...

  9. UNIDBgrid里动态添加clientevents实现回车替换TAB

    //GRID里回车替换TABfunction cellkeydown(sender, td, cellIndex, record, tr, rowIndex, e, eOpts){ if (e.get ...

  10. linux rpm包的编译

    有些软件包的特性是编译者选定的,如果编译未选定此特性,将无法使用.rpm包的版本落后于源码包. 因此需要定制安装,也就是手动编译安装. 编译需要编译环境. 编译的过程如下: 1.下载源码 2.执行 t ...