浅谈区间最值操作与历史最值问题: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. 如何实现模拟器(CHIP-8 interpreter) 绝佳杰作.

    转自 http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/ How to write an ...

  2. 【Emit】关于System.MethodAccessException解决方案

        最近学习Emit,在使用Emit动态生成对象时碰到一些"蛋疼"的问题,如下: 1.安全透明方法"XXX.XX()"尝试访问安全关键方法"YYY ...

  3. VS2017生成类库选择Release失效的问题

    VS的生成可以选择Debug模式或者Release模式,但是我发现在配置里面选择Release无效. 后来发现应该 在 生成->配置管理器  里面设置.

  4. python基础19 -------面向对象终结篇(介绍python对象中各种内置命令)

    一.isinstance()和issubclass()命令 1.isinstance(对象,类型) 用来判定该对象是不是此类型或者说是该对象是不是此类的对象,返回结果为True和False,如图所示. ...

  5. Java中byte转换int时与0xff进行与运算的原因

    http://w.baike.com/LGAdcWgJBBQxRAHUf.html 转帖 java中byte转换int时为何与0xff进行与运算 在剖析该问题前请看如下代码 public static ...

  6. 【leetcode刷题笔记】Longest Substring Without Repeating Characters

    Given a string, find the length of the longest substring without repeating characters. For example, ...

  7. msm8909+android5.1分区及烧录的镜像文件介绍【转】

    本文转载自: EMMC的分区及其保存的文件 Partition label filename 说明 PrimaryGPT gpt_main0.bin modem NON-HLOS.bin sbl1 s ...

  8. codeforces 54A

    题意:收到礼物的规则为每个假日必收到一份礼物,每K天里至少收到一份礼物,求出N天中收到的礼物的最小数量. 思路:将N天根据假日所在天数分为一段段,当假日与假日之间间隔天数hol[i]>-hol[ ...

  9. Luogu-4166 [SCOI2007]最大土地面积

    求平面内四边形的最大面积 显然四个端点都应该在凸包上,就先求凸包,然后\(n^2\)枚举四边形对角线,对于一个点\(i\),顺序枚举\(j\),同时用旋转卡壳的方法去找离对角线最远的两个点.总时间复杂 ...

  10. linux swap的添加等等

    1. 先说下 swap的卸载 fdisk -l 或者  free -m 看下 swap挂载的是磁盘,还是 文件生成的 如果是系统创建时就分配好的swap,就使用  swapoff /dev/*** 进 ...