先对询问推式子,设$S_i=\sum\limits_{j=1}^ia_j,SS_i=\sum\limits_{j=1}^iS_j$,那么答案是
$\sum\limits_{i=l}^r\sum\limits_{j=i}^nS_j-S_{j-i}=\sum\limits_{i=l}^rSS_n-SS_{i-1}-SS_{n-i}=(r-l+1)SS_n-\sum\limits_{i=l-1}^{r-1}SS_i-\sum\limits_{n-r}^{n-l}SS_i$
所以我们需要维护$SS$的和,直接上线段树,考虑修改$(l,r,v)$对$SS$的影响,令$S_2(n)=\dfrac{n(n+1)}2,len=r-l+1$
对$i\in[l,r]$,$SS_i$会增加$v\cdot S_2(i-l+1)$
对$i\in[r+1,n]$,$SS_i$会增加$v\cdot S_2(len)+v\cdot (i-r)len$
第一种对每个位置的增加量是关于下标下标的二次函数,第二种是一次函数,所以直接维护即可
这个题目本身没啥问题,但是这个坑啊,excited!
题目说“一条链”,修改实际上是区间修改,但实际上修改时会出现$u\gt v$的情况,写正解不swap会挂成$25$分,这个出题人他很棒棒啊?个人认为这种读题坑在省选里坑$75$分有点过分了
#include<stdio.h> void swap(int&a,int&b){a^=b^=a^=b;} typedef long long ll; const ll mod=1000000007,inv2=500000004,inv6=166666668; ll a[800010],b[800010],c[800010],s[800010],ss[200010]; ll s1(ll n){return n>0?n*(n+1)%mod*inv2%mod:0;} ll s2(ll n){return n>0?n*(n+1)%mod*(2*n+1)%mod*inv6%mod:0;} void pushup(int x){s[x]=(s[x<<1]+s[x<<1|1])%mod;} void ad(int x,ll l,ll r,ll da,ll db,ll dc){ (a[x]+=da)%=mod; (b[x]+=db)%=mod; (c[x]+=dc)%=mod; (s[x]+=(s2(r)-s2(l-1))*da%mod+(s1(r)-s1(l-1))*db%mod+(r-l+1)*dc%mod)%=mod; } void pushdown(int x,int l,int mid,int r){ if(a[x]|b[x]|c[x]){ ad(x<<1,l,mid,a[x],b[x],c[x]); ad(x<<1|1,mid+1,r,a[x],b[x],c[x]); a[x]=b[x]=c[x]=0; } } void build(int l,int r,int x){ if(l==r){ s[x]=ss[l]; return; } int mid=(l+r)>>1; build(l,mid,x<<1); build(mid+1,r,x<<1|1); pushup(x); } void modify(int L,int R,ll a,ll b,ll c,int l,int r,int x){ if(L<=l&&r<=R)return ad(x,l,r,a,b,c); int mid=(l+r)>>1; pushdown(x,l,mid,r); if(L<=mid)modify(L,R,a,b,c,l,mid,x<<1); if(mid<R)modify(L,R,a,b,c,mid+1,r,x<<1|1); pushup(x); } ll query(int L,int R,int l,int r,int x){ if(L<=l&&r<=R)return s[x]; int mid=(l+r)>>1; ll ans=0; pushdown(x,l,mid,r); if(L<=mid)(ans+=query(L,R,l,mid,x<<1))%=mod; if(mid<R)(ans+=query(L,R,mid+1,r,x<<1|1))%=mod; return ans; } int n; void modify(ll l,ll r,ll v){ ll len=r-l+1; modify(l,r,inv2*v%mod,(3-2*l)*inv2%mod*v%mod,(l*l-3*l+2)%mod*inv2%mod*v%mod,0,n,1); if(r<n)modify(r+1,n,0,len*v%mod,((len+1)*inv2%mod-r)*len%mod*v%mod,0,n,1); } int query(ll l,ll r){ return(((r-l+1)*query(n,n,0,n,1)%mod-query(l-1,r-1,0,n,1)-query(n-r,n-l,0,n,1))%mod+mod)%mod; } int main(){ int m,i,op,x,y,z; scanf("%d%d",&n,&m); for(i=1;i<=n;i++){ scanf("%lld",ss+i); (ss[i]+=ss[i-1])%=mod; } for(i=1;i<=n;i++)(ss[i]+=ss[i-1])%=mod; build(0,n,1); while(m--){ scanf("%d%d%d",&op,&x,&y); if(op==1){ scanf("%d",&z); if(x>y)swap(x,y); modify(x,y,z); }else printf("%d\n",query(x,y)); } }