P4458

· · 个人记录

考虑直接算算不了一点,打算拆个贡献。拆贡献到每个点上,则其每个点权的贡献是个神秘二次多项式,不好做。考虑拆到前缀和上。

$ans = \sum (sum_r - sum_l)[L<=r-l<=R]$,$sum_r$ 与 $sum_l$ 贡献显然分离,分开计算。考虑 $sum_l$ 的计算($sum_r$ 对偶),发现若 $l\in [n-L+1,n]$ 则无贡献;$l\in [n-R+1,n-L]$ 则 $sum_l$ 贡献为 $-(n+1-L-l)$;$l\in [0,n-R]$ 则贡献为 $-(R-L+1)$。则我们只需要维护 $sum_i$ 的和与 $sum_i\times i$ 的和即可,其余都是常数。 考虑区间加 $d$,相当于给 $sum_i$ 区间加等差数列,对 $sum_i$ 的影响为 $d\times (i-L+1)$,对 $sum_i\times i$ 的影响为 $d\times (i-l+1)\times i$,我们只需要在分离常数项与变量,转变为一次区间加常数,一次区间加等差数列,过程中求个 $\sum_{j=1}^{i}j^2$ 即可。在线段树上维护打两个 tag 分别表示区间加 $c$ 与区间加公差为 $c$ 的等差数列。 时间复杂度:$O(n\log n)$。 ```cpp #include <bits/stdc++.h> using namespace std; const int N=2e5+5,mod=1e9+7; 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<<3)+(x<<1)+(ch^48),ch=getchar(); return x*f; } int n,q,a[N]; inline long long calc1(int x){ return x*(x+1ll)/2%mod; } inline long long calc2(int x){ return x*(x+1ll)*(2ll*x+1)/6%mod; } struct tree{ int p,l,r; long long sum1,sum2,tag1,tag2; }t[N<<2]; #define mid (t[p].l+t[p].r>>1) inline void up(int p){ t[p].sum1=(t[p<<1].sum1+t[p<<1|1].sum1)%mod; t[p].sum2=(t[p<<1].sum2+t[p<<1|1].sum2)%mod; } inline void build(int p,int l,int r){ t[p].l=l,t[p].r=r; if(l==r){ t[p].sum1=a[l]; t[p].sum2=a[l]*1ll*l%mod; return; } build(p<<1,l,mid),build(p<<1|1,mid+1,r); up(p); } inline void cg1(int p,long long v){ t[p].tag1=(t[p].tag1+v)%mod; t[p].sum1=(t[p].sum1 + v*(t[p].r-t[p].l+1ll))%mod; t[p].sum2=(t[p].sum2 + v*(calc1(t[p].r) - calc1(t[p].l-1)))%mod; } inline void cg2(int p,long long v){ t[p].tag2=(t[p].tag2+v)%mod; t[p].sum1=(t[p].sum1 + v*1ll*(calc1(t[p].r) - calc1(t[p].l-1)))%mod; t[p].sum2=(t[p].sum2 + v*1ll*(calc2(t[p].r) - calc2(t[p].l-1)))%mod; } inline void spread(int p){ if(t[p].tag1){ cg1(p<<1,t[p].tag1),cg1(p<<1|1,t[p].tag1); t[p].tag1=0; } if(t[p].tag2){ cg2(p<<1,t[p].tag2),cg2(p<<1|1,t[p].tag2); t[p].tag2=0; } } inline void change(int p,int l,int r,int op,int v){ if(l<=t[p].l&&t[p].r<=r){ if(op==0)cg1(p,v); else cg2(p,v); return; } spread(p); if(l<=mid)change(p<<1,l,r,op,v); if(r>mid)change(p<<1|1,l,r,op,v); up(p); } inline long long query(int p,int l,int r,int op){ if(l<=t[p].l&&t[p].r<=r){ if(op==0)return t[p].sum1; return t[p].sum2; } spread(p); long long ans = 0; if(l<=mid)ans=query(p<<1,l,r,op); if(r>mid)ans=(ans+query(p<<1|1,l,r,op))%mod; return ans; } int main(){ n=read();q=read(); for(int i = 1;i<=n;i++)a[i]=(read()+a[i-1])%mod; build(1,0,n); int op,l,r,d; while(q--){ op=read(),l=read(),r=read(); if(l>r)swap(l,r); if(op==1){ d=read(); change(1,l,r,0,d*1ll*(mod+1-l)%mod); change(1,l,r,1,d); if(r<n)change(1,r+1,n,0,d*(r-l+1ll)%mod); } else{ long long ans = 0; if(l!=r){ ans = query(1,n-r+1,n-l,1); ans = (ans - query(1,n-r+1,n-l,0)*(n+1ll-l))%mod; } ans = (ans - query(1,0,n-r,0)*(r-l+1ll))%mod; if(l!=r){ ans = (ans + query(1,l,r-1,1))%mod; ans = (ans - query(1,l,r-1,0)*(l-1ll))%mod; } ans=(ans + query(1,r,n,0)*(r-l+1ll))%mod; printf("%lld\n",(ans+mod)%mod); } } return 0; } ```