uoj164. 【清华集训2015】V 统计

时间:2021-10-19 10:29:23

坑爹题面:http://uoj.ac/problem/164

正常题面:

对于一个序列支持下列5个操作:

1.区间加x

2.区间减x并与0取max

3.区间覆盖

4.单点查询

5.单点历史最大值查询

题解:

每个区间维护一个标记函数f(x)=max(x+a,b)

那么两个标记 f 和 g 的合并就是g(f(x))=max(x+max(fa+ga,-inf),max(fb+ga,gb))(打f标记的时间在前,打g标记在后)

区间加减就是打上max(x,0),区间覆盖就是打上max(-inf,x)

只要记录历史最大标记即可维护历史最大值

code:

 #include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long int64;
char ch;
bool ok;
void read(int &x){
for (ok=,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=;
for (x=;isdigit(ch);x=x*+ch-'',ch=getchar());
if (ok) x=-x;
}
const int maxn=;
const int64 inf=4557430888798830399LL;
int n,m,val[maxn],op,l,r,x;
typedef pair<int64,int64> PII;
#define a first
#define b second
PII operator+(const PII &x,const PII &y){return make_pair(max(x.a+y.a,-inf),max(x.b+y.a,y.b));}
PII max(const PII &x,const PII &y){return make_pair(max(x.a,y.a),max(x.b,y.b));}
struct Seg{
#define ls k<<1
#define rs (k<<1)+1
PII now[maxn<<],ever[maxn<<];
void build(int k,int l,int r){
if (l==r){now[k]=ever[k]=make_pair(val[l],);return;}
int m=(l+r)>>;
build(ls,l,m),build(rs,m+,r);
}
void pushdown(int k){
ever[ls]=max(ever[ls],now[ls]+ever[k]);
ever[rs]=max(ever[rs],now[rs]+ever[k]);
now[ls]=now[ls]+now[k],now[rs]=now[rs]+now[k];
now[k]=ever[k]=make_pair(,);
}
void modify(int k,int l,int r,int x,int y,PII v){
if (l==x&&r==y){now[k]=now[k]+v,ever[k]=max(ever[k],now[k]);return;}
int m=(l+r)>>; pushdown(k);
if (y<=m) modify(ls,l,m,x,y,v);
else if (x<=m) modify(ls,l,m,x,m,v),modify(rs,m+,r,m+,y,v);
else modify(rs,m+,r,x,y,v);
}
void add(int x,int y,int v){modify(,,n,x,y,make_pair(v,));}
void cov(int x,int y,int v){modify(,,n,x,y,make_pair(-inf,v));}
int64 query(int k,int l,int r,int x,int op){
if (l==r){
if (op) return max(ever[k].a,ever[k].b);
else return max(now[k].a,now[k].b);
}
int m=(l+r)>>; pushdown(k);
if (x<=m) return query(ls,l,m,x,op); else return query(rs,m+,r,x,op);
}
int64 query(int x,int op){return query(,,n,x,op);}
}T;
int main(){
read(n),read(m);
for (int i=;i<=n;i++) read(val[i]);
T.build(,,n);
for (int i=;i<=m;i++){
read(op);
if (op==) read(l),read(r),read(x),T.add(l,r,x);
else if (op==) read(l),read(r),read(x),T.add(l,r,-x);
else if (op==) read(l),read(r),read(x),T.cov(l,r,x);
else if (op==) read(x),printf("%lld\n",T.query(x,));
else read(x),printf("%lld\n",T.query(x,));
}
return ;
}