CPU监控 线段树裸题
LINK:bzoj3064 此题甚好码了20min停下来思考的时候才发现不对的地方有点坑...
还真不好写来着 可这的确是线段树的裸题...我觉得我写应该没有什么大问题 不过思路非常的紊乱 如果是自己写的话 所以为了自己能写出来 整理思路就是这篇博客了。
Q X Y:询问从X到Y这段时间内CPU最高使用率
A X Y:询问从X到Y这段时间内之前列出的事件使CPU达到过的最高使用率
P X Y Z:列出一个事件这个事件使得从X到Y这段时间内CPU使用率增加Z
C X Y Z:列出一个事件这个事件使得从X到Y这段时间内CPU使用率变为Z
4个询问 观察如果没有第二个询问的话那么这将是一个线段树维护两个标记且维护区间最大值的操作 很好写。
能否标记永久化?学了就应该思考一下能否标记永久化 好像有点繁杂两个标记互相干扰 不过应该没有什么大问题 但是加上区间最值就不太好写了 所以对于多个标记且互相影响且维护历史最值应该是做不了的 建议pushdown更好一点。
综上 线段树 的lazy tag 和标记永久化都是选自哪一种好写写哪一个,这里推荐写lazy tag代码复杂度不算太高。
考虑如何维护历史最值 这个z可能是负数 如果简单的开一个标记mx表示历史最值的话对于一次区间 的修改 考虑一件事情pushdown未传递之时一个区间覆盖的标记打过来直接add标记被覆盖掉么 那么历史最值可就会出错 其子树内部的最值标记是应该被更新掉的。
现在没有被更新 所以这一点上来看是不太正确的 当然也有另一种情况 区间覆盖标记覆盖原本的标记 这样的话历史最值也会出现一些大问题。如何解决 针对上述情况我想了一个再覆盖标记的时候 先把被覆盖的标记进行下传然后再覆盖标记 让下传的标记先虽然对目前的值是没有什么大影响的但是对历史最值是有可能更新的所以需要这样做 再down中我突然意识到了一个比较严肃的问题关于add标记的合并问题 我们显然每次不能down到儿子那样复杂的会异常的大每次操作接近4n的复杂度比普通的数组模拟复杂度更高。
add标记合并也会带来影响 原本的add比较大现在合并了变小了 可是上一次的add显然更可能更新历史最值这样历史最值还是一个错误的东西。还要考虑怎么再down的时候维护这个标记。我们设定一个下传时候的addmax 再来一个tagmax 钦定下传然后再标准下传我觉得这样很稳复杂度的话 nlogn 好像是多了近乎2/3的常数。
大概是这样的一个毒瘤的东西吧 写完才知道正确与否理性的看是正确的。答案再32位有符号整数内 int 2^31-1好像只有31位靠 非得开long long 增加一倍的大常数 看看能过不能吧...
有点崩溃 代码难度有点高 不知道怎么写 按照上面的思路还有一些细节要处理 啊 我是真的难受 服了这毒瘤线段树 好好的维护什么区间历史最值 真是服了...
又杠了30min 还是感觉 这不是人写的东西 pushdown 和down down里面我觉得还需要下传东西 这样的话下传覆盖儿子也得下传覆盖 故我这思路不太可取还是看看dalao怎么写的吧 我崩溃了200+的代码 总有点纰漏之处。
应该是我对这个标记有点什么误解 被我搞麻烦了 正确的题解是吉如一老师提出的标记合并法解决的。内心无比崩溃。
粘一下 吉老师的题解:
刚接触这一类问题时,这个例题的难度可能较高,所以我们先忽略区间赋值操作。
考虑使用传统的懒标记来解决,首先如果只是询问区间最大值,只面要使用区间加减这一个懒标记(用 Add 表示)就能解决。
现在考虑询问区间历史最大值的最大值。我们定义一种新的懒标记:历史最大的加减标记(用 Pre 表示)。这个标记的定义是:从上一次把这个节点的标记下传的时刻到当前时刻这一时间段中,这个节点中的 Add 标记值到达过的最大值。
现在考虑把第 i 个节点的标记下传到它的儿子 l ,不难发现标记是可以合并的:Prel=max(Prel,Addl+Prei),Addl=Addl+Addi;Prel=max(Prel,Addl+Prei),Addl=Addl+Addi 。至于区间历史最大值信息的更新也与标记的合并类似,只面要将当前的区间最大值加上 Prei 然后与原来的历史最大值进行比较即可。
现在回到原题,我们观察在修改操作过程中,被影响到的节点的变化:如果一个节点没有发生标记下传,那么最开始它一直被区间加减操作所影响,这时我们可以用上面描述的Pre标记来记录,直到某一时刻,这个节点被区间覆盖标记影响A,那么这时这个节点中的所有数都变得完全相同,再之后的所有区间加减修改,对这个节点来说,与区间覆盖操作并没有不同。
因此每一个节点受到的标记可以分成两个部分:第一个部分是区间加减,第二个部分是区间覆盖。因此我们可以用 (x,y) 来表示历史最值标记,它的定义是当前区间在第一阶段时最大的加减标记是 xx ,在第二个阶段时最大的覆盖标记是 yy 。显然这个标记是可以进行合并与更新的。
到此我们就使用最传统的懒标记方法解决了这个问题,时间复杂度 O(mlogn) 。
其实我没怎么看懂 但是这题是 神题经过我的不断思索 决定抄一遍...(学会了一个标记法...
//#include<bits/stdc++.h>
#include<iostream>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<cctype>
#include<utility>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<deque>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
#define INF 1000000000000ll
#define ll long long
#define db double
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define l(p) t[p].l
#define r(p) t[p].r
#define sum(p) t[p].sum
#define mx(p) t[p].mx
#define zz p<<1
#define yy p<<1|1
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline ll read()
{
ll x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
const ll MAXN=;
ll n,m;
char ch;
struct wy
{
ll l,r;
ll mx;//历史最值
ll sum;//当前最值
}t[MAXN<<];
struct data
{
ll x,y;
data(ll a=,ll b=-INF){x=a;y=b;}
data operator +(const data &a){return data(max(-INF,x+a.x),max(y+a.x,a.y));}
data operator *(const data &a){return data(max(x,a.x),max(y,a.y));}
}ntag[MAXN<<],ptag[MAXN<<];
inline void pushup(ll p)
{
mx(p)=max(mx(zz),mx(yy));
sum(p)=max(sum(zz),sum(yy));
}
inline void pushdown(ll p)
{
ptag[zz]=ptag[zz]*(ntag[zz]+ptag[p]);
ntag[zz]=ntag[zz]+ntag[p];
mx(zz)=max(mx(zz),max(sum(zz)+ptag[p].x,ptag[p].y));
sum(zz)=max(sum(zz)+ntag[p].x,ntag[p].y);
ptag[yy]=ptag[yy]*(ntag[yy]+ptag[p]);
ntag[yy]=ntag[yy]+ntag[p];
mx(yy)=max(mx(yy),max(sum(yy)+ptag[p].x,ptag[p].y));
sum(yy)=max(sum(yy)+ntag[p].x,ntag[p].y);
ptag[p]=ntag[p]=data();
}
inline void build(ll p,ll l,ll r)
{
l(p)=l;r(p)=r;
if(l==r)
{
mx(p)=read();sum(p)=mx(p);
return;
}
ll mid=(l+r)>>;
build(zz,l,mid);
build(yy,mid+,r);
pushup(p);
}
inline void change(ll p,ll l,ll r,data a)
{
if(l<=l(p)&&r>=r(p))
{
ntag[p]=ntag[p]+a;
ptag[p]=ptag[p]*ntag[p];
sum(p)=max(sum(p)+a.x,a.y);
mx(p)=max(mx(p),sum(p));
return;
}
ll mid=(l(p)+r(p))>>;
pushdown(p);
if(l<=mid)change(zz,l,r,a);
if(r>mid)change(yy,l,r,a);
pushup(p);
}
inline ll ask(ll p,ll l,ll r,ll flag)
{
if(l<=l(p)&&r>=r(p))return flag?mx(p):sum(p);
pushdown(p);
ll mid=(l(p)+r(p))>>,ans=-INF,w=-INF;
if(l<=mid)ans=ask(zz,l,r,flag);
if(r>mid)w=ask(yy,l,r,flag);
return max(ans,w);
}
signed main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
n=read();
build(,,n);
m=read();
for(ll i=;i<=m;++i)
{
ll x,y,z;
ch=getc();
while(ch!='Q'&&ch!='A'&&ch!='P'&&ch!='C')ch=getc();
x=read();y=read();
if(ch=='Q')printf("%lld\n",ask(,x,y,));
if(ch=='A')printf("%lld\n",ask(,x,y,));
if(ch=='P')z=read(),change(,x,y,data(z,-INF));
if(ch=='C')z=read(),change(,x,y,data(-INF,z));
}
return ;
}
CPU监控 线段树裸题的更多相关文章
- POJ 3468 线段树裸题
这些天一直在看线段树,因为临近期末,所以看得断断续续,弄得有些知识点没能理解得很透切,但我也知道不能钻牛角尖,所以配合着刷题来加深理解. 然后,这是线段树裸题,而且是最简单的区间增加与查询,我参考了A ...
- 【bzoj3064】Tyvj 1518 CPU监控 线段树维护历史最值
题目描述 给你一个序列,支持4种操作:1.查询区间最大值:2.查询区间历史最大值:3.区间加:4.区间赋值. 输入 第一行一个正整数T,表示Bob需要监视CPU的总时间. 然后第二行给出T个数表示在你 ...
- BZOJ1067&P2471 [SCOI2007]降雨量[线段树裸题+细节注意]
dlntqlwsl 很裸的一道线段树题,被硬生生刷成了紫题..可能因为细节问题吧,我也栽了一次WA50分.不过这个隐藏条件真的对本菜鸡来说不易发现啊. 未知的年份连续的就看成一个就好了,把年份都离散化 ...
- 【LOJ6029】「雅礼集训 2017 Day1」市场(线段树裸题)
点此看题面 大致题意: 维护序列,支持区间加法,区间除法(向下取整),区间求\(min\)和区间求和. 线段树维护区间除法 区间加法.区间求\(min\)和区间求和都是线段树基本操作,因此略过不提. ...
- BZOJ.3064.CPU监控(线段树 历史最值)
题目链接 \(Description\) 有一个长为n的序列Ai,要求支持查询[l,r]的最值.历史最值,区间加/重设 \(Solution\) 线段树,每个点再维护一个历史(从0到现在)最大值.历史 ...
- HDU1166 线段树裸题 区间求和
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- HDU 4893 线段树裸题
Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Oth ...
- cdoj 1324 卿学姐与公主 线段树裸题
卿学姐与公主 Time Limit: 2000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Submit St ...
- BZOJ3064 Tyvj 1518 CPU监控 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3064 题意概括 一个序列,要你支持以下操作: 1. 区间询问最大值 2. 区间询问历史最大值 3. ...
随机推荐
- 转载---最简单的JavaScript模板引擎
转载自:http://www.cnblogs.com/dolphinX/p/3489269.html,http://blog.jobbole.com/56689/
- List集合-01.ArrayList
1.ArrayList 1.1 实现了Access接口 实现标记接口Access有以下特点: 目的是允许通用算法提供良好的性能 当遍历方式不同,速度不同时,通常需要继承这个接口 1.2 ArrayLi ...
- python—模块optparse的用法
1.什么是optparse: 在工作中我们经常要制定运行脚本的一些参数,因为有些东西是随着我么需求要改变的,所以在为们写程序的时候就一定不能把写死,这样我们就要设置参数 optparse用于处理命令行 ...
- linux环境下安装 openOffice4并启动服务
一.背景故事 openOffice是用来做office文档在线预览功能,把office文档转换成pdf交给前端显示. 之前系统开发过程一直没有将springboot服务怼上服务器,所以只安装了wind ...
- day06 可变不可变类型
1.可变不可变类型 可变类型 定义:值改变,id不变,改的是原值 不可变类型 定义:值改变,id也变了,证明是产生了新的值没有改变原值 验证 x = 10 print(id(x)) x = 11 pr ...
- nuxt的使用中碰到的问题
使用npm run generate生成静态页面部署 如果不是部署在域名的根目录下,则需要在nuxt.config.js中添加 // nuxt.config.js export default { r ...
- python 网络爬虫报错“UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position”解决方案
Python3.x爬虫, 发现报错“UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1:invalid sta ...
- 机器学习实战基础(十四):sklearn中的数据预处理和特征工程(七)特征选择 之 Filter过滤法(一) 方差过滤
Filter过滤法 过滤方法通常用作预处理步骤,特征选择完全独立于任何机器学习算法.它是根据各种统计检验中的分数以及相关性的各项指标来选择特征 1 方差过滤 1.1 VarianceThreshold ...
- 精通java并发-wait,notify和notifyAll的总结(含案例)
目前CSDN,博客园,简书同步发表中,更多精彩欢迎访问我的gitee pages wait,notify和notifyAll 总结 在调用wait方法时,线程必须要持有被调用对象的锁,当调用wait方 ...
- less基础
less less的含义: less是一种动态样式语言,属于css预处理器的范畴,它扩展了css语言,增加了变量.Mixin.函数等特性,使css更易维护和扩展. 此外,less既可以在客户端上运行, ...