有插入的操作,而且两种修改对区间和都可以打标记,所以直接平衡树维护就完事了
区间加等差数列的操作就维护一个 $s,p$ 表示区间加以 $s$ 为首项,$p$ 为公差的数列,然后记得覆盖标记要直接把以前的标记都覆盖
因为我不知道区间覆盖的值域是多少,所以多维护一个 $pd$ 判断是否有覆盖标记
记得区间加等差数列的时候标记给右儿子的 $s$ 要变大
下传标记我是在每次 $splay$ 之前先把整条链的标记传下来,打标记是把 $l-1$ 移到根,$r+1$ 移到根的右儿子
标记打完要把根和根的右儿子的数据更新,因为会访问到 $0$ 和 $n+1$ 所以要多两个虚节点防止越界
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=2e5+7; int n,m,a[N]; int rt,c[N][2],fa[N],sz[N],cnt; ll val[N],sum[N]; struct dat { ll c,s,p,pd; dat (ll _c=0,ll _s=0,ll _p=0,ll _pd=0) { c=_c,s=_s,p=_p,pd=_pd; } inline ll calc(int n) { return pd*c*n+s*n+1ll*n*(n-1)/2*p; } inline ll val(int n) { return pd*c+s+1ll*n*p; } inline dat operator + (const dat &tmp) const { if(tmp.pd) return dat(tmp.c,tmp.s,tmp.p,tmp.pd); return dat(c,s+tmp.s,p+tmp.p,pd); } }tag[N]; inline void pushup(int x) { int &lc=c[x][0],&rc=c[x][1]; sz[x]=sz[lc]+sz[rc]+1; sum[x]=sum[lc]+sum[rc]+val[x]; } inline void pushdown(int x) { if(!x||(!tag[x].s&&!tag[x].p&&!tag[x].pd)) return; int &lc=c[x][0],&rc=c[x][1]; if(tag[x].pd) sum[x]=0,val[x]=0; sum[x]+=tag[x].calc(sz[x]); val[x]+=tag[x].val(sz[c[x][0]]); if(lc) tag[lc]=tag[lc]+tag[x]; tag[x].s+=tag[x].p*(sz[c[x][0]]+1);// if(rc) tag[rc]=tag[rc]+tag[x]; tag[x]=dat(0,0,0,0); } inline void rotate(int x,int &k) { int y=fa[x],z=fa[y],d=(c[y][1]==x); y!=k ? c[z][c[z][1]==y]=x : k=x; fa[x]=z; fa[y]=x; fa[c[x][d^1]]=y; c[y][d]=c[x][d^1]; c[x][d^1]=y; pushup(y); pushup(x); } void push_tag(int x) { if(x!=rt) push_tag(fa[x]); else pushdown(x); pushdown(c[x][0]); pushdown(c[x][1]); } inline void splay(int x,int &k) { push_tag(x); while(x!=k) { int y=fa[x],z=fa[y]; if(y!=k) (c[y][0]==x ^ c[z][0]==y) ? rotate(x,k) : rotate(y,k); rotate(x,k); } } inline int K_th(int k) { int x=rt; while(233) { if(sz[c[x][0]]+1==k) return x; if(sz[c[x][0]]>=k) x=c[x][0]; else k-=sz[c[x][0]]+1,x=c[x][1]; } } inline void split(int l,int r) { splay(K_th(l-1),rt); splay(K_th(r+1),c[rt][1]); } inline void Cover(int l,int r,ll v) { split(l,r); int x=c[c[rt][1]][0]; tag[x]=tag[x]+dat(v,0,0,1); pushdown(x); pushup(fa[x]); pushup(rt); } inline void Add(int l,int r,ll p) { split(l,r); int x=c[c[rt][1]][0]; tag[x]=tag[x]+dat(0,p,p,0); pushdown(x); pushup(fa[x]); pushup(rt); } inline void Ins(int k,ll v) { splay(K_th(k),rt); int f=K_th(k+1); splay(f,c[rt][1]); int &x=c[f][0]; x=++cnt; fa[x]=f; sz[x]=1; sum[x]=val[x]=v; pushup(f); pushup(rt); } inline void Query(int l,int r) { split(l,r); int x=c[c[rt][1]][0]; pushdown(x); printf("%lld\n",sum[x]); } void build(int l,int r,int f) { int mid=l+r>>1; if(l<mid) build(l,mid-1,mid); if(mid<r) build(mid+1,r,mid); val[mid]=a[mid]; c[f][mid>f]=mid; fa[mid]=f; pushup(mid); } int main() { n=read(),m=read(); for(int i=2;i<=n+1;i++) a[i]=read(); cnt=n+2; build(1,n+2,0); rt=(n+3)>>1; int opt,a,b; for(int i=1;i<=m;i++) { opt=read(),a=read(),b=read(); if(opt==1) { Cover(a+1,b+1,read()); continue; } if(opt==2) { Add(a+1,b+1,read()); continue; } if(opt==3) { Ins(a,b); continue; } Query(a+1,b+1); } return 0; }