【BZOJ3064】CPU监控(线段树)
题面
题解
神仙(zsy)出在了(noip)模拟的题目。(然而(zsy)出的还是这题的升级版)
首先明确一点,这题是一个吉司机线段树。
如果只有区间加法,区间赋值,区间最大值,那么这题很简单。
但是加上了一个区间历史最值,这就很烦了。
于是我们就有了一个神仙做法,
定义一个表示((a,b))表示区间内所有数先(+a)再和(b)取(max),即(x=max(x+a,b))
那么这样一来,区间加法转化成((a,-infty)),区间赋值变成了((-infty,b))
考虑如何合并标记,现在有两个标记((a,b),(x,y)),将后者合并到前者上去。
那么可以将标记转化成((a+x,max(b+x,y))),原因就是注意一下(max)和加法的先后顺序。
对于两个标记如何合并(max),是((max(a,x),max(b,y)))。原因就是我们可以把这个标记看做是一个分段函数,那么这个合并就比较显然了。
回到题目。
这题到底在干什么呢?
首先对于维护当前值,这个东西是非常显然的。
考虑如何维护一个历史最值,我们对于每个点额外维护一个历史最值的标记,每次覆盖的时候不会覆盖掉历史最值的标记,只会用(max)操作更新历史最值标记。
这样子似乎就可以做了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 100100
#define lson (now<<1)
#define rson (now<<1|1)
#define inf 1050000000
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Data
{
int a,b;
void clear(){a=0;b=-inf;}
int calc(int x){return max(a+x,b);}
}mxt[MAX<<2],tag[MAX<<2];
int mx[MAX<<2],nw[MAX<<2];
Data max(Data a,Data b){return (Data){max(a.a,b.a),max(a.b,b.b)};}
Data operator+(Data a,Data b){return (Data){max(-inf,a.a+b.a),max(a.b+b.a,b.b)};}
void pushup(int now)
{
nw[now]=max(nw[lson],nw[rson]);
mx[now]=max(mx[lson],mx[rson]);
}
void puttag(int now,Data a,Data b)
{
mxt[now]=max(mxt[now],tag[now]+b);
tag[now]=tag[now]+a;
mx[now]=max(mx[now],b.calc(nw[now]));
nw[now]=a.calc(nw[now]);
}
void pushdown(int now)
{
puttag(lson,tag[now],mxt[now]);
puttag(rson,tag[now],mxt[now]);
mxt[now].clear();tag[now].clear();
}
void Build(int now,int l,int r)
{
tag[now].clear();mxt[now].clear();
if(l==r){nw[now]=mx[now]=read();return;}
int mid=(l+r)>>1;
Build(lson,l,mid);Build(rson,mid+1,r);
pushup(now);
}
void Modify(int now,int l,int r,int L,int R,Data a)
{
if(L<=l&&r<=R){puttag(now,a,a);return;}
int mid=(l+r)>>1;pushdown(now);
if(L<=mid)Modify(lson,l,mid,L,R,a);
if(R>mid)Modify(rson,mid+1,r,L,R,a);
pushup(now);
}
int Query(int now,int l,int r,int L,int R,int opt)
{
if(L==l&&r==R)return opt?mx[now]:nw[now];
int mid=(l+r)>>1;pushdown(now);
if(R<=mid)return Query(lson,l,mid,L,R,opt);
if(L>mid)return Query(rson,mid+1,r,L,R,opt);
return max(Query(lson,l,mid,L,mid,opt),Query(rson,mid+1,r,mid+1,R,opt));
}
int n,m;
char ch[20];
int main()
{
n=read();Build(1,1,n);m=read();
while(m--)
{
scanf("%s",ch);
int l=read(),r=read();Data a=(Data){-inf,-inf};
if(ch[0]=='Q')printf("%d
",Query(1,1,n,l,r,0));
else if(ch[0]=='A')printf("%d
",Query(1,1,n,l,r,1));
else if(ch[0]=='P')a.a=read(),Modify(1,1,n,l,r,a);
else a.b=read(),Modify(1,1,n,l,r,a);
}
return 0;
}