思路:科学的题面:
请你写一个数据结构支持以下功能:
1:区间[l,r]加x
2:区间[l,r]减x并和0取max
3:区间覆盖
4:单点询问
5:单点历史最大值询问
线段树维护分段函数
标记就是一个二元组(a,b)表示标记生效后x=max(x+a,b)
1操作就是打(x,0)的标记
2就是(-x,0)
3就是(-inf,v)
我们手推一下就可以发现这个标记是满足结合律和封闭性的
然后两个标记怎么合并呢?
g(f(x))=max(x+max(fa+ga,-inf),max(fb+ga,gb))(打f标记的时间在前,打g标记在后)
中间和-inf取max是为了不使多个-inf加爆了
对于历史最大值,我们要记录的是历史最大标记而不是直接在每个点记录历史最大值
为什么是这样的?
假设我们进行一次区间赋为inf的操作,接着有全部赋为0,标记还没来得及下传更新历史最大值就被后一个标记cha了
所以每个点记录历史最大值是错的
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define PI pair<long long,long long>
#define mp(a,b) make_pair(a,b)
#define fi first
#define se second
typedef long long ll;
const int maxn=500010;
const ll inf=4557430888798830399ll;
using namespace std;
int n,m,a[maxn];
PI max(PI a,PI b){return mp(max(a.fi,b.fi),max(a.se,b.se));}
PI operator +(PI f,PI g){return mp(max(f.fi+g.fi,-inf),max(f.se+g.fi,g.se));}
struct Tsegment{
#define ls (p<<1)
#define rs ((p<<1)|1)
#define mid ((l+r)>>1)
PI now[maxn<<2],ever[maxn<<2];
void add(int p,int ch){
ever[ch]=max(ever[ch],now[ch]+ever[p]);
now[ch]=now[ch]+now[p];
}
void down(int p){
add(p,ls),add(p,rs);
now[p]=ever[p]=mp(0,0);
}
void build(int p,int l,int r){
if (l==r){now[p]=ever[p]=mp(a[l],0);return;}
build(ls,l,mid),build(rs,mid+1,r);
}
void modify(int p,int l,int r,int a,int b,PI v){
//printf("p=%d l=%d r=%d a=%d b=%d\n",p,l,r,a,b);
if (l==a&&r==b){
now[p]=now[p]+v;
ever[p]=max(ever[p],now[p]);
return;
}
down(p);
if (b<=mid) modify(ls,l,mid,a,b,v);
else if (a>mid) modify(rs,mid+1,r,a,b,v);
else modify(ls,l,mid,a,mid,v),modify(rs,mid+1,r,mid+1,b,v);
}
ll query(int p,int l,int r,int x,int op){
if (l==r){
if (op) return max(ever[p].fi,ever[p].se);
else return max(now[p].fi,now[p].se);
}
down(p);
if (x<=mid) return query(ls,l,mid,x,op);
else return query(rs,mid+1,r,x,op);
}
void cover(int l,int r,int v){modify(1,1,n,l,r,mp(-inf,v));}
void inc(int l,int r,int v){modify(1,1,n,l,r,mp(v,0));}
ll query(int x,int op){return query(1,1,n,x,op);}
}T;
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
T.build(1,1,n);
for (int i=1,l,r,x,op;i<=m;i++){
scanf("%d",&op);
if (op==1) scanf("%d%d%d",&l,&r,&x),T.inc(l,r,x);
else if (op==2) scanf("%d%d%d",&l,&r,&x),T.inc(l,r,-x);
else if (op==3) scanf("%d%d%d",&l,&r,&x),T.cover(l,r,x);
else if (op==4) scanf("%d",&x),printf("%lld\n",T.query(x,0));
else if (op==5) scanf("%d",&x),printf("%lld\n",T.query(x,1));
else if (op==6){
for (int i=1;i<=n;i++)
printf("%lld ",T.query(i,0));puts("");
}
else if (op==7){
for (int i=1;i<=n;i++)
printf("%lld ",T.query(i,1));puts("");
}
}
return 0;
}
/*
5 6
1 2 3 4 5
2 1 3 2 //0 0 1 4 5
4 1 //0
1 1 4 1 //1 1 2 5 6
5 3 //3
3 1 5 4 //4 4 4 4 4
4 2 //4
*/