【前言】
雅礼集训的时候讲题人放出来的题,但没有原题,于是机房几个人写了拍了。
然后丢到了LOJ上。
【题目】
LOJ
你需要写一个数据结构维护长度为 n n n的三个序列 A , B , C A,B,C A,B,C,支持:
每次修改操作后(前两种),令 B i = B i + A i , C i = max ( C i , A i ) B_i=B_i+A_i,C_i=\max(C_i,A_i) Bi=Bi+Ai,Ci=max(Ci,Ai)
初始给定 A i A_i Ai,初始 B i = 0 , C i = A i B_i=0,C_i=A_i Bi=0,Ci=Ai
n ≤ 2 × 1 0 5 n\leq 2\times 10^5 n≤2×105
【解题思路】
这个东西细节很多,来写一写容易发生错误的地方吧,仅供参考,具体实现可以看代码。
以上是我维护的所有基本信息,分别代表:区间最大值/次大值,区间最大值个数,区间长度,区间和。
以上是所有维护的最大值相关信息和非最大值相关信息,分别代表:区间历史最大值,区间历史版本和的差量和,区间历史版本和差量标记,区间加标记,区间历史最大加标记。
以上是维护这个区间最大值是否从左右儿子贡献上来。
为什么要维护上面这些信息?
对于操作 1 1 1,我们需要吉司机线段树将其转化为区间加,具体来说,若 f m x ≤ x fmx\leq x fmx≤x我们可以直接跳过,若 s m x < v < f m x smx<v<fmx smx<v<fmx,则相当于只对最大值进行加操作1,否则我们暴力递归下去更新。
而正是由于可能只对最大值进行操作,我们后面的所有标记都要分成最大值和非最大值两类来维护。
考虑操作 4 4 4,维护区间历史版本和,那么我们需要知道怎么对加法进行维护。假设在第 i i i个修改操作对一个区间加上了 x x x,那么在第 j j j个修改操作后进行询问时,第 i i i次操作对区间内历史版本和的贡献为 ( j − i + 1 ) x = j x − ( i − 1 ) x (j-i+1)x=jx-(i-1)x (j−i+1)x=jx−(i−1)x,于是我们可以对 hsum \text{hsum} hsum减去 l e n ⋅ ( i − 1 ) x len\cdot (i-1)x len⋅(i−1)x。在进行操作 4 4 4的时候,我们用 hsum \text{hsum} hsum加上 sum \text{sum} sum乘上当前做的修改操作个数即可。同样我们还需要维护关于这个的标记进行下传。
考虑操作 5 5 5维护区间历史版本最大值,我们需要维护历史最大值和历史最大加标记,后者用于下传。每次打加标记是,我们将历史最大加标记 hadd \text{hadd} hadd与当前标记 add \text{add} add取 max \text{max} max即可。
由于要对最大值和非最大值分别应用标记,我们还需要维护最大值从左右儿子中哪个进行贡献(可能两个一起)。
所有下传标记时,应当判断最大值是否在左/右区间来确定应用的标记。
对于 hadd \text{hadd} hadd的更新,应当是用当前节点上的 add \text{add} add标记和父亲的 hadd \text{hadd} hadd标记来更新,即
t[ls].hadd1=max(t[ls].hadd1,t[ls].add1+(t[x].f1?t[x].hadd1:t[x].hadd2))
对于 hmx \text{hmx} hmx的更新,应当使用当前区间 fmx,smx \text{fmx,smx} fmx,smx与父亲的 hadd \text{hadd} hadd标记来更新,即
t[ls].hmx1=max(t[ls].hmx1,t[ls].fmx+(t[x].f1?t[x].hadd1:t[x].hadd2));
对于 sum,hsum \text{sum,hsum} sum,hsum这类需要考虑应用区间长度的标记要格外注意
fmx,smx \text{fmx,smx} fmx,smx的更新应当放在 hmx \text{hmx} hmx之后,否则应用是错误的。
最后复杂度就是 O ( q log n ) O(q\log n) O(qlogn),常数巨大。
【参考代码】
#include
using namespace std;
typedef long long ll;
const int N=2e5+10;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll ind,a[N];
namespace IO
{
ll read()
{
ll ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
void write(ll x){if(x<0)putchar('-'),x=-x;if(x>9)write(x/10);putchar(x%10^48);}
void writeln(ll x){write(x);putchar('\n');}
}
using namespace IO;
namespace Data_Structure
{
struct Segment
{
#define lc (x<<1)
#define rc (x<<1|1)
struct node
{
ll fmx,smx,cnt,sum,len;
ll hmx1,hmx2,add1,add2,hadd1,hadd2,hsum1,hsum2,dhsum1,dhsum2;
bool f1,f2;
}t[N<<2];
void pushdown(int x)
{
int ls=x<<1,rs=ls|1;
t[ls].hadd1=max(t[ls].hadd1,t[ls].add1+(t[x].f1?t[x].hadd1:t[x].hadd2));
t[ls].hadd2=max(t[ls].hadd2,t[ls].add2+t[x].hadd2);
t[ls].add1+=t[x].f1?t[x].add1:t[x].add2;
t[ls].add2+=t[x].add2;
t[ls].hmx1=max(t[ls].hmx1,t[ls].fmx+(t[x].f1?t[x].hadd1:t[x].hadd2));
t[ls].hmx2=max(t[ls].hmx2,t[ls].smx+t[x].hadd2);
t[ls].sum+=(t[x].f1?t[x].add1:t[x].add2)*t[ls].cnt+t[x].add2*(t[ls].len-t[ls].cnt);
t[ls].dhsum1+=t[x].f1?t[x].dhsum1:t[x].dhsum2;
t[ls].dhsum2+=t[x].dhsum2;
t[ls].hsum1+=(t[x].f1?t[x].dhsum1:t[x].dhsum2)*t[ls].cnt;
t[ls].hsum2+=t[x].dhsum2*(t[ls].len-t[ls].cnt);
t[ls].fmx+=t[x].f1?t[x].add1:t[x].add2;t[ls].smx+=t[x].add2;
t[rs].hadd1=max(t[rs].hadd1,t[rs].add1+(t[x].f2?t[x].hadd1:t[x].hadd2));
t[rs].hadd2=max(t[rs].hadd2,t[rs].add2+t[x].hadd2);
t[rs].add1+=t[x].f2?t[x].add1:t[x].add2;
t[rs].add2+=t[x].add2;
t[rs].hmx1=max(t[rs].hmx1,t[rs].fmx+(t[x].f2?t[x].hadd1:t[x].hadd2));
t[rs].hmx2=max(t[rs].hmx2,t[rs].smx+t[x].hadd2);
t[rs].sum+=(t[x].f2?t[x].add1:t[x].add2)*t[rs].cnt+t[x].add2*(t[rs].len-t[rs].cnt);
t[rs].dhsum1+=t[x].f2?t[x].dhsum1:t[x].dhsum2;
t[rs].dhsum2+=t[x].dhsum2;
t[rs].hsum1+=(t[x].f2?t[x].dhsum1:t[x].dhsum2)*t[rs].cnt;
t[rs].hsum2+=t[x].dhsum2*(t[rs].len-t[rs].cnt);
t[rs].fmx+=t[x].f2?t[x].add1:t[x].add2;t[rs].smx+=t[x].add2;
t[x].add1=t[x].add2=t[x].hadd1=t[x].hadd2=t[x].dhsum1=t[x].dhsum2=0;
}
void pushup(int x)
{
int ls=x<<1,rs=ls|1;
if(t[ls].fmx==t[rs].fmx)
{
t[x].f1=t[x].f2=1;
t[x].fmx=t[ls].fmx; t[x].smx=max(t[ls].smx,t[rs].smx); t[x].cnt=t[ls].cnt+t[rs].cnt;
t[x].hmx1=max(t[ls].hmx1,t[rs].hmx1); t[x].hmx2=max(t[ls].hmx2,t[rs].hmx2);
t[x].hsum1=t[ls].hsum1+t[rs].hsum1; t[x].hsum2=t[ls].hsum2+t[rs].hsum2;
t[x].sum=t[ls].sum+t[rs].sum;
}
else
{
t[x].f1=t[x].f2=0;
if(t[ls].fmx<t[rs].fmx) swap(ls,rs),t[x].f2=1; else t[x].f1=1;
t[x].fmx=t[ls].fmx; t[x].smx=max(t[ls].smx,t[rs].fmx); t[x].cnt=t[ls].cnt;
t[x].hmx1=t[ls].hmx1; t[x].hmx2=max(t[ls].hmx2,max(t[rs].hmx1,t[rs].hmx2));
t[x].hsum1=t[ls].hsum1; t[x].hsum2=t[ls].hsum2+t[rs].hsum1+t[rs].hsum2;
t[x].sum=t[ls].sum+t[rs].sum;
}
}
void build(int x,int l,int r)
{
t[x].len=r-l+1;
if(l==r)
{
t[x].fmx=t[x].sum=t[x].hmx1=a[l];
t[x].smx=t[x].hmx2=-inf;t[x].cnt=1;
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);build(rc,mid+1,r);
pushup(x);
}
void upcover(int x,int l,int r,int L,int R,ll v)
{
int mid=(l+r)>>1;
if(L<=l && r<=R)
{
if(t[x].fmx<=v) return;
if(t[x].smx<v)
{
t[x].add1+=v-t[x].fmx; t[x].hadd1=max(t[x].hadd1,t[x].add1);
t[x].hsum1+=-t[x].cnt*(v-t[x].fmx)*(ind-1);
t[x].dhsum1+=-(v-t[x].fmx)*(ind-1); t[x].sum+=t[x].cnt*(v-t[x].fmx);
t[x].fmx=v;
}
else pushdown(x),upcover(lc,l,mid,L,R,v),upcover(rc,mid+1,r,L,R,v),pushup(x);
return;
}
pushdown(x);
if(L<=mid) upcover(lc,l,mid,L,R,v);
if(R>mid) upcover(rc,mid+1,r,L,R,v);
pushup(x);
}
void update(int x,int l,int r,int L,int R,ll v)
{
if(L<=l && r<=R)
{
t[x].add1+=v;t[x].add2+=v;
t[x].hsum1+=-t[x].cnt*v*(ind-1); t[x].hsum2+=-(t[x].len-t[x].cnt)*v*(ind-1);
t[x].dhsum1+=-v*(ind-1); t[x].dhsum2+=-v*(ind-1);
t[x].sum+=t[x].len*v;
t[x].fmx+=v;
if(t[x].smx>-inf) t[x].smx+=v;
t[x].hmx1=max(t[x].hmx1,t[x].fmx); t[x].hmx2=max(t[x].hmx2,t[x].smx);
t[x].hadd1=max(t[x].hadd1,t[x].add1); t[x].hadd2=max(t[x].hadd2,t[x].add2);
return;
}
pushdown(x);
int mid=(l+r)>>1;
if(L<=mid) update(lc,l,mid,L,R,v);
if(R>mid) update(rc,mid+1,r,L,R,v);
pushup(x);
//printf("%d %d %lld %lld\n",l,r,t[x].dhsum1,t[x].dhsum2);
}
ll query1(int x,int l,int r,int L,int R)
{
if(L<=l && r<=R) return t[x].sum;
pushdown(x);
int mid=(l+r)>>1;ll res=0;
if(L<=mid) res+=query1(lc,l,mid,L,R);
if(R>mid) res+=query1(rc,mid+1,r,L,R);
return res;
}
ll query2(int x,int l,int r,int L,int R)
{
//printf("%d %d %lld %lld %lld %lld %lld\n",l,r,t[x].sum,t[x].hsum1,t[x].hsum2,t[x].dhsum1,t[x].dhsum2);
if(L<=l && r<=R) return t[x].sum*ind+t[x].hsum1+t[x].hsum2;
pushdown(x);
int mid=(l+r)>>1;ll res=0;
if(L<=mid) res+=query2(lc,l,mid,L,R);
if(R>mid) res+=query2(rc,mid+1,r,L,R);
return res;
}
ll query3(int x,int l,int r,int L,int R)
{
if(L<=l && r<=R) return max(t[x].hmx1,t[x].hmx2);
pushdown(x);
int mid=(l+r)>>1;ll res=-inf;
if(L<=mid) res=max(res,query3(lc,l,mid,L,R));
if(R>mid) res=max(res,query3(rc,mid+1,r,L,R));
return res;
}
void debug(int x,int l,int r)
{
printf("%d %d:%lld %lld %lld %lld %lld %lld %lld\n",l,r,t[x].fmx,t[x].smx,t[x].sum,t[x].hsum1,t[x].hsum2,t[x].dhsum1,t[x].dhsum2);
if(l==r) return;
pushdown(x);
int mid=(l+r)>>1;
debug(lc,l,mid);debug(rc,mid+1,r);
}
#undef lc
#undef rc
}T;
}
using namespace Data_Structure;
namespace DreamLolita
{
int n,Q;
void solution()
{
n=read();Q=read();
for(int i=1;i<=n;++i) a[i]=read();
T.build(1,1,n);
for(int i=1;i<=Q;++i)
{
int op=read(),l=read(),r=read();
if(op==1) ++ind,T.upcover(1,1,n,l,r,read());
else if(op==2) ++ind,T.update(1,1,n,l,r,read());
else if(op==3) writeln(T.query1(1,1,n,l,r));
else if(op==4) writeln(T.query2(1,1,n,l,r));
else writeln(T.query3(1,1,n,l,r));
//T.debug(1,1,n);puts("");
}
}
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
DreamLolita::solution();
return 0;
}