bzoj3064/洛谷P4314 CPU监控【线段树】
好,长草博客被催更了【?】
我感觉这题完全可以当作线段树3
线段树2考加法和乘法标记的下放顺序,这道题更丧心病狂【?】
很多人可能跟我一样,刚看到这道题秒出思路:打一个当前最大值一个历史最大值不就完事了吗
实际上这样做会死得很惨。节点保留的信息可能来不及下传就被父节点更新掉,导致一部分信息被覆盖而丢失,这样就有可能查不到正确的历史最大值。比如历史最大值是由add更新的,但是set覆盖下来把add变成了0。
为了保留这些信息,我们需要记录历史修改标记的最大值。标记hset(history-set)记录从上一次pushdown到现在set标记的最大值,hadd(history-add)记录从上一次pushdown到现在add标记达到过的最大值(不是add每次增加的最大值)。hset和hadd不是用来更新自身的hmax值的,而是用来在pushdown的时候下放,更新儿子的pushdown。仔细想一下就可以知道,当前节点保留的hset,hadd,与儿子存的各种当前信息(max,add,set)结合,都是儿子曾经能够达到的状态,更新合法且一定能更新出儿子准确的历史最大值。
因为pushdown的时候也要下放hset和hadd,所以只记录每次pushdown到现在的值。具体的下放顺序我写在代码注释里了。
#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
char c[];
long long a[];
const long long inf=;//初始化用
struct node{
int l,r;
long long hmax,max,hadd,hset,add,set;//哪个代表什么很显然吧XD
}b[];
void build(int p,int l,int r){
b[p].l=l,b[p].r=r;
if(l==r){
b[p].hmax=b[p].max=a[l];
return;
}
int mid=(l+r)/;
b[p*].hset=b[p*].set=b[p*].hmax=b[p*].max=-inf;//初始化左右儿子,1的我写在主函数里了
b[p*+].hset=b[p*+].set=b[p*+].hmax=b[p*+].max=-inf;
build(p*,l,mid);
build(p*+,mid+,r);
b[p].max=max(b[p*].max,b[p*+].max);
b[p].hmax=max(b[p*].max,b[p*+].max);
}
void pushdown(int p){//核心操作,按顺序分类讨论
//写标记的习惯一般是,当前节点有标记=当前节点已经被更新好所有信息(hmax,max),
//保有可以下传而不对自己造成影响的修改标记(add,hadd,set,hset)
//pushdown的时候,让左右儿子也达到这个要求,自己清空所有修改标记,
//这样自己在成为修改函数最终目标的时候就可以直接更新所有信息。
b[p*].hmax=max(b[p*].hmax,max(b[p].hset,b[p].hadd+b[p*].max));//先用儿子在这次pushdown之前就保留的信息更新历史最大值
if(b[p*].set!=-inf)b[p*].hset=max(b[p*].hset,b[p*].set+b[p].hadd);//下放当前节点的hadd。儿子保有的set一定是在自身的hadd之前被打上的
else b[p*].hadd=max(b[p*].hadd,b[p].hadd+b[p*].add);//同理,儿子的add也是在自身的hadd之前被打上的
b[p*].hset=max(b[p*].hset,b[p].hset);//下放hset
if(b[p].add){//下放add
if(b[p*].set!=-inf)b[p*].set+=b[p].add;//如果儿子有set,就把add累计到set上
else b[p*].add+=b[p].add;
b[p*].max+=b[p].add;
}
if(b[p].set!=-inf){//下放set,直接覆盖
b[p*].max=b[p*].set=b[p].set;
b[p*].add=;//清零儿子的add,因为被直接覆盖掉了
}
b[p*].hset=max(b[p*].hset,b[p*].set);//用儿子更新过以后的信息来更新hset和hadd
b[p*].hadd=max(b[p*].hadd,b[p*].add); b[p*+].hmax=max(b[p*+].hmax,max(b[p].hset,b[p].hadd+b[p*+].max));//复制一遍
if(b[p*+].set!=-inf)b[p*+].hset=max(b[p*+].hset,b[p*+].set+b[p].hadd);
else b[p*+].hadd=max(b[p*+].hadd,b[p].hadd+b[p*+].add);
b[p*+].hset=max(b[p*+].hset,b[p].hset);
if(b[p].add){
if(b[p*+].set!=-inf)b[p*+].set+=b[p].add;
else b[p*+].add+=b[p].add;
b[p*+].max+=b[p].add;
}
if(b[p].set!=-inf){
b[p*+].max=b[p*+].set=b[p].set;
b[p*+].add=;
}
b[p*+].hset=max(b[p*+].hset,b[p*+].set);
b[p*+].hadd=max(b[p*+].hadd,b[p*+].add);
b[p].set=b[p].hset=-inf;
b[p].add=b[p].hadd=;
}
long long ask1(int p,int l,int r){//询问当前最大值,常规操作
if(b[p].l!=b[p].r)pushdown(p);
if(l<=b[p].l&&b[p].r<=r){
return b[p].max;
}
int mid=(b[p].l+b[p].r)/;
long long val=-inf;
if(l<=mid)val=max(val,ask1(p*,l,r));
if(r>mid)val=max(val,ask1(p*+,l,r));
b[p].max=max(b[p*].max,b[p*+].max);
b[p].hmax=max(b[p*].hmax,b[p*+].hmax);
return val;
}
long long ask2(int p,int l,int r){//询问历史最大值,常规操作
if(b[p].l!=b[p].r)pushdown(p);
if(l<=b[p].l&&b[p].r<=r){
return b[p].hmax;
}
int mid=(b[p].l+b[p].r)/;
long long val=-inf;
if(l<=mid)val=max(val,ask2(p*,l,r));
if(r>mid)val=max(val,ask2(p*+,l,r));
b[p].max=max(b[p*].max,b[p*+].max);
b[p].hmax=max(b[p*].hmax,b[p*+].hmax);
return val;
}
void change1(int p,int l,int r,long long val){//add
if(b[p].l!=b[p].r)pushdown(p);//到达之前就pushdown
if(l<=b[p].l&&b[p].r<=r){
b[p].add+=val;//因为已经pushdown过了,所以这里直接更新所有信息
b[p].hadd+=val;
b[p].max+=val;
b[p].hmax=max(b[p].hmax,b[p].max);
return;
}
int mid=(b[p].l+b[p].r)/;
if(l<=mid)change1(p*,l,r,val);
if(r>mid)change1(p*+,l,r,val);
b[p].max=max(b[p*].max,b[p*+].max);
b[p].hmax=max(b[p*].hmax,b[p*+].hmax);
}
void change2(int p,int l,int r,long long val){//set
if(b[p].l!=b[p].r)pushdown(p);//到达之前pushdown
if(l<=b[p].l&&b[p].r<=r){
b[p].max=b[p].hset=b[p].set=val;//同样,因为已经pushdown过了,直接更新所有信息
b[p].hmax=max(b[p].hmax,b[p].max);
return;
}
int mid=(b[p].l+b[p].r)/;
if(l<=mid)change2(p*,l,r,val);
if(r>mid)change2(p*+,l,r,val);
b[p].max=max(b[p*].max,b[p*+].max);
b[p].hmax=max(b[p*].hmax,b[p*+].hmax);
}
int main()//主函数都是常规操作
{
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%lld",&a[i]);
b[].hset=b[].set=b[].hmax=b[].max=-inf;
build(,,n);
scanf("%d",&m);
while(m--){
scanf("%s",c);
int x,y;
long long z;
if(c[]=='Q'){
scanf("%d%d",&x,&y);
printf("%lld\n",ask1(,x,y));
}
else if(c[]=='A'){
scanf("%d%d",&x,&y);
printf("%lld\n",ask2(,x,y));
}
else if(c[]=='P'){
scanf("%d%d%lld",&x,&y,&z);
change1(,x,y,z);
}
else{
scanf("%d%d%lld",&x,&y,&z);
change2(,x,y,z);
}
}
return ;
}
这道题真的非常有价值,希望看到的同学都不要放弃,努力写一下。就算是参考着题解写的也十分有意义_(:з」∠)_。
思路参考了洛谷题解区枫林晚的做法。
bzoj3064/洛谷P4314 CPU监控【线段树】的更多相关文章
- 洛谷题解P4314CPU监控--线段树
题目链接 https://www.luogu.org/problemnew/show/P4314 https://www.lydsy.com/JudgeOnline/problem.php?id=30 ...
- 【bzoj3064】Tyvj 1518 CPU监控 线段树维护历史最值
题目描述 给你一个序列,支持4种操作:1.查询区间最大值:2.查询区间历史最大值:3.区间加:4.区间赋值. 输入 第一行一个正整数T,表示Bob需要监视CPU的总时间. 然后第二行给出T个数表示在你 ...
- 【BZOJ】1012: [JSOI2008]最大数maxnumber /【洛谷】1198(线段树)
Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插 ...
- 洛谷P3372/poj3468(线段树lazy_tag)(询问区间和,支持区间修改)
洛谷P3372 //线段树 询问区间和,支持区间修改 #include <cstdio> using namespace std; struct treetype { int l,r; l ...
- CPU监控 线段树裸题
LINK:bzoj3064 此题甚好码了20min停下来思考的时候才发现不对的地方有点坑... 还真不好写来着 可这的确是线段树的裸题...我觉得我写应该没有什么大问题 不过思路非常的紊乱 如果是自己 ...
- 洛谷P4065 [JXOI2017]颜色(线段树)
题意 题目链接 Sol 线段树板子题都做不出来,真是越来越菜了.. 根据题目描述,一个合法区间等价于在区间内的颜色没有在区间外出现过. 所以我们可以对于每个右端点,统计最长的左端点在哪里,刚开始以为这 ...
- 洛谷P5111 zhtobu3232的线段树
题意:给定线段树,上面若干个节点坏了,求能表示出多少区间. 区间能被表示出当且仅当拆出来的log个节点都是好的. 解:每个区间在最浅的节点处计算答案. 对于每个节点维护从左边过来能有多少区间,从右边过 ...
- BZOJ.3064.CPU监控(线段树 历史最值)
题目链接 \(Description\) 有一个长为n的序列Ai,要求支持查询[l,r]的最值.历史最值,区间加/重设 \(Solution\) 线段树,每个点再维护一个历史(从0到现在)最大值.历史 ...
- 洛谷P3960 列队 NOIp2017 线段树/树状数组/splay
正解:动态开点线段树 解题报告: 传送门! 因为最近学主席树的时候顺便get到了动态开点线段树?刚好想起来很久很久以前就想做结果一直麻油做的这题,,,所以就做下好了QAQ 然后说下,这题有很多种方法, ...
随机推荐
- 0908NOIP模拟测试赛后总结
%%%skyh rank1- 奶风神.kx.有钱人 rank2-210 NC锅.RNB.B哥 rank5-200 我 rank32- 9-13upd:无意中点进了某个博客发现我竟然考场上yy出了树上莫 ...
- angular组件之间的通信
一.组件创建 直接使用 ng g component 的命令创建组件,会自动生成组件所需的文件,方便快捷. // 父组件 ng g component parent // 子组件 ng g compo ...
- mysql localhost可以连输入本机ip地址连接不了
Mysql 默认是没有开启这个权限的(只允许使用 host:localhost,或者 host:127.0.0.1),如果想用 host:192.168.1.* ,来访问mysql ,需要手动开启这个 ...
- JDK源码阅读--String
public final class String implements java.io.Serializable, Comparable<String>, CharSequence St ...
- 报错C1189 #error: "No Target Architecture"
根本原因: 是因为单独包含了一些windows.h已经包含了的头文件如"fileapi.h","WinUser.h",但是却没有包含windows.h 或者先包 ...
- Linux下c开发 之 线程通信
Linux下c开发 之 线程通信 1.Linux“线程” 进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种“多进程单线程”的操作系统.Linux本身 ...
- Django自带的认证系统
Django自带的用户认证 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能,这还真是个麻烦的事情呢. Djang ...
- WhaleCTF之web-本地登录
WhaleCTF之web-本地登录 前往题目 呵呵,基然对ip限制,没事,掏出burp抓包 改包 添加XFF头部 X-Forwarded-For: 127.0.0.1 发一下 不是admin,没有用户 ...
- SpringBoot使用注解方式整合Redis
1.首先导入使用Maven导入jar包 <dependency> <groupId>org.springframework.boot</groupId> <a ...
- Undertow服务器基础分析 - XNIO
阅读更多 我们从名字上就能看出这是一个NIO思想为基础的IO框架,X是指这个框架可以有多种实现,我们可以从代码库 https://github.com/xnio 中发现一个项目xnio-native, ...